• ベストアンサー

仮想リストコントロールの表示

お世話になります、fujitomoです。 今回ご意見を頂きたいと思い、質問させて頂きましたのはVCでの仮想リストコントロールにデータを表示する件に関してです。 具体的に申し上げますと、 あるデータが記述されたcsvファイルがあり、そのcsvファイルのある位置から200件のデータを仮想リストコントロールに表示させたいと思っています。 そこで、私が考えたアプリケーションの作りとして、初めにcsvファイルからデータを読み込んでCStringの二次元配列に各セルのデータを保存します。 そしてLVN_GETDISPINFOを受ける関数を作成し、そこでリストコントロールにCStringの二次元配列の値を当てはめていこうと思っています。つまり、関数内でリストの項目とCStringの二次元配列を1対1に対応させています。 しかしここで、LVN_GETDISPINFOを受ける関数は常にCStringの二次元配列の1行目から見てしまい、例えば、リストコントロールに100行目からのデータを表示させたいと思い、LVN_GETDISPINFOを受ける関数内でリストコントロールに表示させる開始行を指定したとしても0~99行目までが空白となって表示されてしまいます。目的の動作としては100行目からの200行をリストに表示させたいと思っているのでこれではダメです。 仮想リストコントロールを使うのは初めてで、どのように使うのが定石なのか分からない為悩んでいるのですが、私の目的の動作を達成させるためには表示させたい200行分のデータをその都度CStringの二次元配列に格納し、その配列とリストの項目をLVN_GETDISOINFOを受ける関数内で対応させるべきなのでしょうか? 文章だけではかなり分かりづらいと思うので、大雑把にですがソースを載せます。 //メンバ変数 CString data[gyo][row] //データを保存するCString二次元配列 CListCtrl m_list; //リストコントロールのコントロール変数 int start; //リスト表示行 //ダイアログの初めに BOOL C***Dlg::OnInitDialog() { CDialog::OnInitDialog(); Read_File(); //csvファイルをCStringの二次元配列に保存 m_list.SetItem(200);//200件表示に設定 return TRUE; } LRESULT C***Dlg::DefWindowProc(UINT message,WPARAM wParam,LPARAM lParam) { switch(message) case WM_NOFITY: return OnGetListInfo(lParam); } return CDialog::DefWindowProc; } LRESULT C***Dlg::OnGetListInfo(LPARAM lParam) { LPNMHDR lpnmh = (LPNMHDR)lParam; CWnd* hwndListView = GetDlgItem(IDC_LIST1); LV_DISPINFO* lpDInfo; switch(lpnmh->code){ case LVN_GETDISPINFO: lpDInfo = (LV_DISPINFO*)lParam; if(lpDInfo->iItem.mask & LVIF_TEXT){ if(lpDInfo->item.iItem >= start){     switch(lpDInfo->item.iSubItem){ case 0: _tcscpy_s(lpDInfo->item.pszText,256, data[lpDinfo->item.iItem][lpDinfo->item.iSubItem]; break; } } } break; } return 0; } といったソースとなっています。 ご意見を宜しくお願い致します。 尚、開発環境は Windows CE 6.0 Visual Studio 2005 です。 ご回答をお待ちしております。

質問者が選んだベストアンサー

  • ベストアンサー
  • tanma3
  • ベストアンサー率58% (14/24)
回答No.1

定石というのであれば、"m_list.SetItem(gyo);"とするのが定石だと思いますが、"200件を固定で表示する"というのが仕様なのであれば、別に定石にこだわらなくても、 m_start_line = 200; // cvs表示開始セット _tcscpy_s(lpDInfo->item.pszText,256, data[m_start_line+lpDinfo->item.iItem][lpDinfo->item.iSubItem]; などとして、コピー開始位置にゲタをはかせてやれば問題は解決すると思いますが、どうでしょう?

fujtomo
質問者

お礼

tanma3様、早速のご回答ありがとうございます。 おっしゃったように配列の行に下駄を履かせてみたら無事目的の動作をさせることが出来ました。 重ねての質問で申し訳ありませんが、 この表示する仮想リストコントロールの読み込むデータが別の箇所で更新される場合に、そのデータを読み込み、・リストに表示させたい際に、例えば、全てのデータ(例えば4000件)のうちのある200件を表示させたいと考えたときに、全てのデータのうちの表示させたい開始行を今回のように、全てのデータを一度保存した配列に下駄としてはかせる方法と、あらかじめ表示させたい200件を全てのデータを保存した配列から抽出して、別の配列に保存した後にリストに表示させるのではどちらが一般的なのでしょうか? 今回実現したいアプリケーションの動作というのが、ある時間間隔で保存されていく時間データ(csv形式ファイル)のうちの最新の200件をリストコントロールに随時表示させたいと考えています。

その他の回答 (3)

  • tanma3
  • ベストアンサー率58% (14/24)
回答No.4

>全てのデータを一度保存した配列に下駄としてはかせる方法と、 >あらかじめ表示させたい200件を全てのデータを保存した配列から >抽出して、別の配列に保存した後にリストに表示させるのでは >どちらが一般的なのでしょうか? 設計方針によって違ってくると思います。 今回の場合は、リスト更新タイミングによるのではないでしょうか。CSVが更新されたタイミングでリストの方も更新しなければならないのであれば、1つのバッファでデータを管理した方がいいと思いますし、 逆にリスト更新タイミングは一定(たとえば1分毎)で有るのであれば、 CSVとの同期が邪魔になるので、別バッファ管理とした方がいいと思います。

fujtomo
質問者

お礼

tanma3様、ご回答ありがとうございます。 データが更新されるタイミングの問題ということですね。 設計仕様によって、どちらにするか考えてみたいと思います。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.3

>リストコントローラのスクロールバーが4000件分の長さに変化してしまい、 これは仕方が無いと思いますが、なにか不都合でもあるのでしょうか? むしろ、スクロールができて便利だと思うのですが。 逆に、200件でいいのなら、仮想リストコントロールにする意味があまりないように思えます。 >その範囲以外の項目が表示されないわけではなく、範囲以外の項目が空白となって、結局4000行分表示されてしまう結果となりました。 意味がよくわからないです。 仮想リストコントロールの場合、表示に必要な分だけのLVN_GETDISPINFOがやってくるはずで、表示範囲外のアイテムについては、LVN_GETDISPINFOはやってこないはずですが。

fujtomo
質問者

お礼

titokani様ご回答ありがとうございます。 >むしろ、スクロールができて便利だと思うのですが。 逆に、200件でいいのなら、仮想リストコントロールにする意味があまりないように思えます。 現在作成しているアプリケーションの実行環境がWindows CE 6.0という組み込み用のOSのため、少しでもメモリを消費させない方法として仮想リストコントロールを選択しました。 >仮想リストコントロールの場合、表示に必要な分だけのLVN_GETDISPINFOがやってくるはずで、表示範囲外のアイテムについては、LVN_GETDISPINFOはやってこないはずですが。 lpDInfo.item.iItemの表示範囲のコードはどの箇所に入力するのでしょうか? LVN_GETDISPINFOを受ける関数内でも、DefWindowProc内でも範囲のコードを入力しても、表示に必要な範囲以外の0から最終行までLVN_GETDISPINFOが送信され、値を代入していない行は空白行となって表示されます。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.2

仮想リストコントロールの場合、アイテムの総数にはデータの総数を指定することになると思います。 つまり、全体で4000件なら、 m_list.SetItemCount(4000) です。 どのアイテムを表示させるかは、lpDInfo->item.iItemをそのまま使えばいいはずです。

fujtomo
質問者

お礼

titokani様、ご回答ありがとうございます。 私も初めにそう思い、そのようにコードを作成してみたのですが、 m_list.SetItemCount(4000) とすると、リストコントローラのスクロールバーが4000件分の長さに変化してしまい、 lpDInfo->item.iItemをそのまま使う って範囲を指定すると、その範囲以外の項目が表示されないわけではなく、範囲以外の項目が空白となって、結局4000行分表示されてしまう結果となりました。

関連するQ&A