2005-09-20
目次
「WebObjects Dev Report」 第22回 田畑 英和
今回は「単一テーブル」型の継承を用いたユーザ情報のモデル化方法について解説いたします。まず大まかな手順ですが、次のようになります。
1. 親クラス用Entityの作成
継承元のEntityを作成します。
2. サブクラス用Entityの作成
親クラス用Entityから継承したEntityを作成します。
3. ソースコードの作成
Entityからソースコードを生成し、継承のためのコードを追加します。
今回作成するEntityですが、「MOSA会員」「非会員」「事務局」の3種類のユーザタイプ用のEntityに加え、各ユーザタイプに共通した属性をまとめた親クラス用Entityの計4つを作成します。それぞれのEntity名は次のようにします。
MOSAUser:親クラス用Entity
MOSAMember:MOSA会員用Entity
MOSANonMember:非会員用Entity
MOSAAdmin:事務局用Entity
◇親クラス用Entityの作成
全てのサブクラスに共通する属性を定義します。属性の追加方法は、通常のEntityと同様ですが、継承を行う場合は継承用の属性が1つ必要になります。継承を用いた場合、データベース上の1つのテーブルに複数のEntityのレコードが混在することになりますので、この属性を用いて各レコードがどのEntityのレコードかを識別します。識別用の属性は例えば次のように作成します。
Name : type
Column : TYPE
Value Class(Java) : Number
External Type : int
レコードを追加するさいに、この属性(type)にレコードごとのユニークな数値をセットすることにより、Entityの識別をおこないます。どのように数値をセットするかについてはソースコードの作成の説明で取り上げます。この属性は、Entityを識別するために用いるだけですが、値をセットする必要がありますのでクラスプロパティとして設定します。またそれぞれのEntityの数値は次のようにします。
MOSAMember:10, MOSANonMember : 20, MOSAAdmin:30
今回は、親クラス用のEntityを実際にはインスタンス化せず、ユーザ用のインスタンスはいずれかのサブクラス用Entityから生成します。このような場合には、EOModelerのAdvanced Entity Inspectorを用いてEntityをAbstractとして設定することにより、そのEntityがインスタンス化されない継承のための親クラスであることを宣言できます。
◇サブクラス用Entityの作成
サブクラス用のEntityを作成するには、まずEOModeler上で継承する親クラスを選択し、PropertyメニューからCreate Subclassを実行します。サブクラス用のEntityを作成したらEntity名を設定しますが、このときテーブル名は親クラス用Entityのテーブル名と同じままにしておきます。単一テーブルの場合は、継承関係にあるすべてのEntityを単一のテーブルで管理しますので、テーブル名を統一しておく必要があります。
親クラス用Entityに含まれる属性は、サブクラスを作成した時点でサブクラス用Entityにも自動的に継承されているため、あとはサブクラス固有の属性を追加していきます。
次に単一のテーブルから特定のEntityに対応するレコードを取り出す設定をおこないます。EOModeler上でサブクラス用Entityを選択し、Advanced Entity Inspectorを用いてQualifierの設定をおこないます。このときQualifierはそれぞれのサブクラス用Entityで次のように設定します。
MOSAMember:(type = 10)
MOSANonMember : (type = 20)
MOSAAdmin:(type = 30)
このようなQualifierを設定することにより単一のテーブルから特定のEntityのレコードのみを取り出すことが可能になります。これらの操作をすべてのサブクラスごとに実行していきます。
これで親クラスとサブクラス用のEntityの設定ができましたので、次回は継承を用いた場合のカスタムEOのソースコードの作成方法について解説いたします。
小池邦人のCarbon API 徒然草(2005/09/16)
今回は、openViwerWindow()から呼ばれているimageFileToImage()ルーチンについて解説します。基本的には、画像ファイルからCore Graphics Imageを作る処理なのですが、Mac OS Xのバージョンにより、その解決方法が大きく異なります。
通常、画像ファイルから画像データを読み込む場合には、QuickTimeのGraphicsImporter APIを利用します。実際には、GetGraphicsImporterForFile()に画像ファイルのFSSpec構造体を渡し、GraphicsImportComponentを得ます。それを関連APIに渡すことで、各種画像情報や画像データを得ることや、指定CGrafPortへの描画などが可能となります。この場合、対象がどんな種類の画像ファイル(JPEGとかTIFF)なのかは、ほとんど気にする必要はありません。QuickTimeが読み込んで表示可能な画像種類であれば、すべて同様な処理を実行することができます。もし、QuickTimeが未対応の画像ファイルを処理しようとすると、GetGraphicsImporterForFile()でエラーが返りますので注意してください。
以下のimageFileToPicture()ルーチンは、GraphicsImporter APIを利用して画像ファイルからPicture(PICT)データを得る簡単な例です。
short imageFileToPicture( Rect *frt,FSSpec *fsc,PicHandle *pict,Rect *srt )
{
short ret=1;
Rect drt;
GraphicsImportComponent gi;
if( ! GetGraphicsImporterForFile( fsc,&gi ) ) // GraphicsImporterを開く
{
if( ! GraphicsImportGetNaturalBounds( gi,srt ) ) // 画像矩形枠を得る
{
OffsetRect( srt,-srt->left,-srt->top ); // 矩形枠を原点基準にする
if( frt ) // frtが渡されていればその矩形枠内に拡大縮小する
{
OffsetRect( frt,-frt->left,-frt->top );
fitBounds( 1,frt,srt,&drt ); // 矩形枠フィット用の自作ルーチン
OffsetRect( &drt,-drt.left,-drt.top );
}
else // frtとしてNULLが渡された場合
drt=*srt; // PICT枠にはオリジナル画像枠を利用する
GraphicsImportSetBoundsRect( gi,&drt ); // 画像矩形枠をセットし直す
ret=GraphicsImportGetAsPicture( gi,pict );// 画像からPICTデータを得る
}
CloseComponent( gi ); // GraphicsImporterを閉じる
}
return( ret );
}
続いて、imageFileToImage()を調べてみます。今回、画像ファイルから得る必要があるのは、Core Graphics ImageのCGImageRefです。そのため、まず最初にimageFileToGworld()ルーチンを用いて、画像ファイルをオフスクリーン用に確保したGWorldへ描画してやります。そのGWorldのPixMapデータ(メモリ領域)から、Core Graphics(Quartz 2D)APIを駆使してCGImageRefを作成しています。
short imageFileToImage( FSSpec *fsc,CGImageRef *image,GWorldPtr *off,Rect *srt )
{
long size,ww,hh;
short row,ret=1;
CGColorSpaceRef color;
Ptr addr;
CGDataProviderRef prov;
PixMapHandle phd;
Rect drt;
if( ! imageFileToGworld( fsc,off,srt ) ) // 画像を描画したGWorldを得る
{
GetPortBounds( *off,&drt ); // 画像の矩形枠を得る
phd=GetGWorldPixMap( *off ); // GWorldのPixMap(メモリ領域)を得る
addr=GetPixBaseAddr( phd ); // PixMapの先頭アドレスを得る
row=GetPixRowBytes( phd ); // PixMapのRowBytesを得る(横幅バイト数)
ww=drt.right;
hh=drt.bottom;
size=hh*row;
if( prov=CGDataProviderCreateWithData( NULL,(void *)addr,size,NULL ) )
{ // GWorldのPixMapを対象としたCGDataProviderRefを得る
color=CGColorSpaceCreateDeviceRGB(); // RGBのCGColorSpaceRefを得る
if( *image=CGImageCreate( ww,hh,8,32,row,color,
kCGImageAlphaNoneSkipFirst,prov,
NULL,0,kCGRenderingIntentDefault ) )
// CGDataProviderRefよりCore Graphics Imageを得る
ret=noErr;
CGColorSpaceRelease( color ); // 用済みCGColorSpaceRefをリリース
CGDataProviderRelease( prov ); // 用済みCGDataProviderRefをリリース
}
if( ret )
DisposeGWorld( *off ); // エラーが発生した場合にはGWorldを削除
}
return( ret );
}
imageFileToGworld()ルーチンは、FSSpecから画像ファイルのGraphicsImportComponentを得て、それをオフスクリーン用に確保したGWorld(CGrafPort)へと描画します。描画先のGWorldをGraphicsImporterに知らせるにはGraphicsImportSetGWorld()を使い、実際の描画はGraphicsImportDraw()が担当します。
short imageFileToGworld( FSSpec *fsc,GWorldPtr *off,Rect *srt )
{
short ret=1;
GraphicsImportComponent gi;
if( ! GetGraphicsImporterForFile( fsc,&gi ) ) // GraphicsImporterを開く
{
if( ! GraphicsImportGetNaturalBounds( gi,srt ) ) // 画像矩形枠を得る
{
OffsetRect( srt,-srt->left,-srt->top ); // 矩形枠を原点基準にする
if( ! NewGWorld( off,32,srt,NULL,NULL,0 ) ) // GWorldを作成する
{
LockPixels( GetGWorldPixMap( *off ) ); // GWorldのPixMapをロック
GraphicsImportSetGWorld( gi,*off,0L ); // 描画先のGWorldを設定
GraphicsImportSetBoundsRect( gi,srt ); // 画像矩形枠を設定
GraphicsImportDraw( gi ); // GWorldに画像を描画する
ret=noErr;
}
}
CloseComponent( gi );// GraphicsImporterを閉じる
}
return( ret );
}
上記方法では、オフスクリーン用のGWorldを確保してからCGImageRefを得ています。しかし、Mac OS X 10.4以降ではQuickDrawやGWorldといったレガシーな仕組みを極力用いないようにと、Apple社は提言しています。そのため、QuickTimeも徐々に改良が進められており、Mac OS Xのモダンな環境に対応した新APIがいくつも追加されています。例えば、Mac OS X 10.3とQuickTime 6.4以降からは、GraphicsImportCreateCGImage()という新APIが利用できます。このAPIを使えば、GraphicsImportComponentから直接Core Graphics Imageを得ることが可能です。以下に、このAPIを用いた場合のopenViwerWindow()を紹介しておきます。非常にスマートな処理となりますが、Mac OS X 10.2をアプリケーション・ターゲットに加えるとなると、この方法は採用できませんので注意してください。
short openViwerWindow( WindowRef window,FSSpec *fsc,WindowRef *wptr )
{
short ret=1;
CGImageRef image;
WindowClass wcls;
WindowAttributes watt;
Rect drt;
GraphicsImportComponent gi;
if( ! GetGraphicsImporterForFile( fsc,&gi ) )
{ // FSSPecで指定された画像ファイル用GraphicsImporterを開く
if( ! GraphicsImportGetNaturalBounds( gi,&drt ) )
{ // 画像ファイルのオリジナル矩形枠を得る
if( ! GraphicsImportCreateCGImage( gi,&image,
kGraphicsImportCreateCGImageUsingCurrentSettings ) )
// Core Graphics Imageを得る...Mac OS X 10.3 & QT 6.4以降のみ可能
{
wcls=kDocumentWindowClass; // ウィンドウクラスはドキュメント
// ウィンドウアトリビュートをセット
watt=kWindowStandardDocumentAttributes|
kWindowLiveResizeAttribute|kWindowStandardHandlerAttribute|
kWindowCompositingAttribute;
if( ! createMyWindow(fsc->name,'VIEW',wcls,watt,&drt,fsc,wptr) )
{ // 画像表示用ウィンドウの作成
if( ! setupViwerWindow( *wptr,image ) ) // ウィンドウ初期化
{
setupViwerWindowEvent( *wptr ); // Event Handlerの登録
setWParent( *wptr ,window ); // 親ウィンドウのセット
ShowWindow( *wptr ); // ウィンドウを表示する
ret=0;
}
else
DisposeWindow( *wptr ); // エラーであれば削除
}
CGImageRelease( image ); // Core Graphics Imageをリリース
}
}
}
return( ret );
}
次回も、openViwerWindow()内部で実行されている色々なルーチンを追跡します。実際には、画像表示用ウィンドウを作成しているcreateMyWindow()ルーチンの解説が中心となる予定です。
つづく
SqueakではじめるSmalltalk入門 第47回 鷲見正人
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、ファイルリストの文字化けをフィックスする作業を完了し、新しいメソッドの定義を他の仮想イメージでも利用できるようにするためのファイル出力の方法に触れます。
▼文字化け解消を.txtに限って機能するようにする
前回、FileList >> #defaultEncoderFor:でa Latin1TextConverterに設定されていたコンバータをa ShiftJISTextConverterに変更することで、文字化けを解消できることがわかりました。ただ、このままではファイルリストでの文字コードコンバータがa Latin1TextConverterであることを想定している機構があった場合に、ちょっと困ったことになりますね。そこで、今回の改変による影響を最小限にとどめるために、拡張子が.txtのファイルに限ってa ShiftJISTextConverterを使うようにしておきましょう。
このメソッドのコードをよく見ると、冒頭でテンポラリ変数「l」にファイル名を束縛しています。
| l |
l _ aFileName asLowercase.
文字列の最後の文字が’.txt’であるかどうかをチェックするために送るメッセージは「endsWith: ‘.txt’」です。 したがって、lに束縛されたファイル名を示す文字列の最後が’.txt’ならa ShiftJISTextConverterを返す式を追加すれば目的は簡単に達成できそうです。そのための式は次のようになります。
(l endsWith: '.txt') ifTrue: [^ ShiftJISTextConverter new].
「endsWith: …」を「ifTrue: [...]」に優先して送信しなければならないので、括弧が必要です。この括弧がないと、「endsWith: … ifTrue:[...]」というひとつながりのメッセージと解釈されてしまいますので注意してください。また、生成したコンバータ(a ShiftJISTextConverter)をこのメソッドの返値として返すために「^」が必要です。まだ式が続くので、行末のピリオドも忘れないように。
この式を途中に挿入し、あとは前回、ShiftJISTextConverterに変えてしまった最後のデフォルトのコンバータクラスをLatin1TextConverterに戻せば完成です。
[fig.A]加筆、修正後のFileList >> #defaultEncoderFor:メソッド
http://squab.no-ip.com:8080/mosaren/uploads/47a.png
これで日本語ファイルの文字化けを解消する細工はOK。以後、ファイルリストで呼び出すシフトJISエンコードの.txtファイルは文字化けせずに表示されるようになります。デスクトップメニューから「保存」を選んで使用中の仮想イメージを上書きすれば再起動後もこの修正は機能し続けます。
▼修正したメソッドの定義をファイル出力する
この改変を他の仮想イメージにも適用したい場合、いったん当該メソッドの定義をSmalltalkシステムの外へ持ち出さなければいけません。このようなときは、メソッドのソースをファイルとして出力し、別の仮想イメージ内でそれを読込む作業を行ないます。Smalltalkでは、システム内のリソース(主にソースコード)のファイル出力のことをファイルアウト(file out)、リソース(主にソースコード)のファイルからの読み込みのことをファイルイン(file in)と言います。
言うまでもなく、メソッドのソースのファイルアウトもメッセージ送信で指示できます。
FileList fileOutMethod: #defaultEncoderFor:
が、こうした式をいちいちタイプしたり、do itするのも面倒な話ですよね。当然、ブラウザには同等の操作を行なうGUIが用意されているので、普段はこちらを使います。今、FileList >> #defaultEncoderFor:の編集に使っている変形ブラウザの上のペイン(通常のブラウザなら上段右端のペインに相当)の黄ボタンメニューからfileOutを選んでください。
[fig.B]FileList >> #defaultEncoderFor:メソッドのソースをファイルアウト
http://squab.no-ip.com:8080/mosaren/uploads/47b.png
すると、FileList-defaultEncoderFor.stという名前のテキストファイルが使用中の仮想イメージと同じフォルダに作成されます。このファイルの中身はメソッドの定義とほぼ同じ内容です。“ほぼ”なのは、このファイルに含まれるコードがどんな素性のものかを示すメタ情報が追加され含まれているからです。具体的には、冒頭に仮想イメージのバージョンやファイルアウトされた日時が、また、メソッドの定義の直前には、クラス名、カテゴリ名、オーサー名とタイムスタンプが付記されます。なお多数挿入されている「!」は、これらメタ情報の区切りを示します。
別の仮想イメージで、このファイルをファイルインすれば、機能の追加が可能です。次回は、いくつかあるファイルインの方法と、関連した便利なツールを紹介します。
バックナンバー:
http://squab.no-ip.com:8080/mosaren/
ニュース・解説
今週の解説担当:木下 誠
———————————————————————-
Java 1.3.1と1.4.2 Release 2がリリース
———————————————————————-
Java 1.3.1と1.4.2 Release 2がリリースされました。それに合わせて、リリースノート「Java 1.3.1 and 1.4.2 Release 2 Release Notes」も公開されました。
このリリースは、バグフィックスが中心となっているようです。細かいフィックスの内容は、リリースノートから調べることができます。主に、描画周りの修正が行われているようです。
業務でJavaを利用している方は、要チェックでしょう。
Java 1.3.1 and 1.4.2 Release 2
http://www.apple.com/support/downloads/java131and142release2.html
Java 1.3.1 and 1.4.2 Release 2 Release Notes
http://developer.apple.com/releasenotes/Java/Java142RNTigerR2/index.html
———————————————————————-
WindowsからのQuickTimeプログラミング
———————————————————————-
WindowsプログラムからQuickTime 7を利用する方法を解説したドキュメント、「Scripting the COM/ActiveX Control in QuickTime 7 for Windows」が公開されています。Windows環境では、QuickTimeはCOMまたはActiveXを使って利用することになります。これにより、C、C++、C#、Visual Basicから透過的にアクセスできることになっています。
実際にCOM/ActiveXインタフェースを眺めてみると、結構充実しています。Cocoa用のQTKitよりも高機能であり、ちょっとうらやましかったりもします。
Scripting the COM/ActiveX Control in QuickTime 7 for Windows
http://developer.apple.com/quicktime/activexcontrol.html
———————————————————————-
QuickTimeのQAとサンプル
———————————————————————-
Technical Q&A「QA1443: Using QTPixelBufferContextCreate with NewMovieFromProperties」と「QA1441: UpdateMovieResource causes my movie file to grow bigger」が公開されています。どちらも、QuickTimeプログラミングに関するものです。
さらに、QuickTimeに関するサンプルコード「QTPixelBufferVCToCGImage」も公開されています。これは、QuickTimeのピクセルバッファを、CGImageとして書き出すサンプルです。
最近、QuickTimeやCore Imageなど、グラフィック系のドキュメントやサンプルが、頻繁にアップデートされていますね。
QA1443: Using QTPixelBufferContextCreate with NewMovieFromProperties
http://developer.apple.com/qa/qa2005/qa1443.html
QA1441: UpdateMovieResource causes my movie file to grow bigger
http://developer.apple.com/qa/qa2005/qa1441.html
QTPixelBufferVCToCGImage
http://developer.apple.com/samplecode/QTPixelBufferVCToCGImage/QTPixelBufferVCToCGImage.html
MOSAからのお知らせと編集後記は割愛します