{{category 開発情報}} {{category 陰郎の書いた記事,nolink}} !!概要  このページでは、LstSetDrawFunction を使用してコールバック関数方式でリストを描画する方式に関する注意点について記述しています。   !!説明  Palm OS API である LstSetListChoices を使用すると、リストコントロールに表示するデータの設定をすることができます。この API の関数プロトタイプは以下のとおりです。 void LstSetListChoices( ListType* pList, Char** pItemsText, Int16 numItems );  この API は以下のように使用します。つまり、文字列の配列を用意し、その先頭ポインタと要素数を渡すことになります。 const char* pItems[] = { "foo", "bar", "baz", "quux" }; ListType* pList = (ListType*)FrmGetObjectPtr( /* omit */ ); LstSetListChoices( pList, pItems, 4 );  この方法の欠点としては、別のデータ構造に大量のデータが存在する場合などに、それを配列として再構成して渡さなければならないという点が挙げられます。また、API 呼び出しの時点で配列を丸ごと API に渡すため、要素数に比例して処理時間がかかるそうです。  この方法とは別に、LstSetDrawFunction という API を併用することでコールバック関数を経由してリストを描画する方法があります。これはリストの各行を描画するためのコールバック関数を LstSetDrawFunction を使って登録し、その後要素数だけを LstSetListChoices で指定するという方法になります。LstSetDrawFunction の関数プロトタイプは以下のとおりです。 void LstSetDrawFunction( ListType* pList, ListDrawDataFuncPtr func );  第2引数の ListDrawDataFuncPtr には、コールバック関数のアドレスを渡します。この関数は以下のように定義されます。 void ListDrawDataFuncType( Int16 itemNum, RectangleType* pBounds, Char** pItemsText );  つまり、上記の関数と同じパラメータをとる関数を自前で定義し、それを LstSetDrawFunction を使用してリストコントロールと結びつけることで、描画のためのコールバックとして利用できるわけです。以下の例では、コールバック関数として MyDrawFunction という関数を用意して使用しています。 void MyDrawFunction( Int16 itemNum, RectangleType* pBounds, Char** pItemsText ) { /* itemNum 番目の要素を pBounds が指す矩形内に描画する。 */ /* pItemsText には、LstSetListChoices の第2引数に渡した */ /* データがそのまま渡される。 */ } ListType* pList = (ListType*)FrmGetObjectPtr( /* omit */ ); LstSetDrawFunction( pList, MyDrawFunction ); LstSetListChoices( pList, NULL, 100 );  ここでは、リストの要素数として100を指定しています。このリスト内の描画をするために MyDrawFunction がコールバックされるわけですが、実際に呼び出されるのは、画面に実際に描画する必要のある行だけとなります。この場合、コード内のコメントにあるとおり、LstSetListChoices の第2パラメータに渡したデータはそのままコールバック関数に渡されます。コールバック関数で使用しないのであれば、NULL を渡すこともできます。  Palm OS API リファレンスによれば、コールバック関数を使用する場合、この pItemsText パラメータには NULL や文字列の配列を渡す他、全く別のデータオブジェクトのポインタをキャストして(コールバック関数側で利用するために)渡すこともできるそうです。つまり、コールバック関数を使用する限り、Palm OS はこの第2引数に関知しないということになります。ただし、ListDrawDataFuncType のリファレンスには以下のような注意書きがあります。 ""Note, however, that if you pass anything other than a pointer to a list of strings when you call LstSetListChoices, you must ensure that LstGetSelectionText is never called since it assumes that this pointer indicates an array of text items. In particular, if your list is associated with a pop-up trigger you must handle the popSelectEvent yourself before FrmHandleEvent gets a chance at it since FrmHandleEvent calls LstGetSelectionText.  つまり、LstSetListChoices の第2引数に文字列の配列以外のものを渡した場合(これには NULL の場合も含まれるか?)、LstGetSelectionText が呼び出されないように注意せよ、と書かれています。LstGetSelectionText は LstSetListChoices の第2引数に渡されたデータが文字列の配列であると決め付けて動作するからのようです。また、ポップアップトリガーに関連付けられたリストの場合、内部的に LstGetSelectionText が呼び出されるのを防ぐため、popSelectEvent を自前でハンドリングせよ、とも書かれています。  DAなどのコードリソースでは大域が使用できないため、コールバック関数が必要とするデータを渡すためにはこの第2引数を経由せざるを得ません。筆者がDAの作成時にコールバック関数方式を試みた時は、上記の注意書きに気づかなかったせいもあり、デバッグ時にクラッシュする原因を突き止めることができず、コールバック方式を断念したことがあります。しかし、第2引数に任意のデータ型を(キャストして)渡す方法は(制限つきとはいえ)APIリファレンスで公式に認められているため、注意して使用すれば柔軟なコーディングができるはずです。   !!参考情報  LstSetListChoices、LstSetDrawFunction、ListDrawDataFuncType などの詳細については Palm OS API リファレンスを参照してください。   !!注意事項  記述内容には誤りがあるかもしれません。お気づきの方がいらっしゃいましたらご指摘いただけると幸いです。   !!コメント *コメントスパムが来ますので、コメント欄をコメントアウトしました。コメントを追加したい方は、コメント欄の復活させるか、または直接編集してください。- よういち (2007年02月07日 09時05分00秒) //{{comment multi}}