• ベストアンサー

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

お世話になります、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

  • コントロールリスト(CListCtrl)非表示行

    C++でのFORM部品のコントロールリスト(CListCtrl)において、登録済みの複数アイテムのうち、特定アイテム(行)のみを、アイテムを削除せずに非表示に設定することは可能でしょうか? やりたいのは特定カラムの格納値でフィルタリング設定を行い、特定の値をもつ行のみを選択表示したいでのすが、アイテム削除や別リストでの表示ではなく、あくまでもひとつのコントロールリスト内のアイテム設定で行いたいです。 アイテム別の状態設定としては SetItemState 関数がありますが、非表示にする機能は見当たりませんでした。

  • リストコントロールのデータの変更を検知したい

    リストコントロールのデータの変更時に呼び出されるイベントが分かりません、 OnLvnItemchangedList()であっているのでしょうか?もっと簡単に実現できるのなら、 教えてください。 VC++2010 MFC です。 削除のときは、条件なしに、OnLvnDeleteitemList()内でいいのですが、 追加も pNMLV->uChanged == 4 にすれば問題ないです。でもその他は、厳しくしすぎると クリックしただけで、データが変更されたと判断されたり、・・・でうまく行きません。 【リスト上のデータが変更されるケース】 データが変更される場合は、非選択状態から「すべてを置換」するケースや 一個一個 検索(選択)しながら、「置換」するケースがあります。 後は、リストコントロールにエディットボックスを張り付かせて、「編集」(エンターで確定) して、データを変更するケースがあります。 ただし、「すべてを置換」する場合でも、既に選択状態のデータを処理する場合もあり、困っています。 自分で作ったプログラムなのですから、各機能終了時に変更されたか?されてないか?は 分かっているのですが、勉強のため、質問をしました。 PreTranslateMessage()で出来るのでしょうか? (参考サイト: http://isobe.exblog.jp/996027/ ) 【目的】 起動時 から(前回保存時から)リストデータに変化がない場合、何もせずに終了したい 【やりたいこと】 リストの文字が変わったら、キャプションを FileListCreator(*) にすると ともに、ListDataNoChange_FLG = FALSE; にする。 保存ややリカバリ(復帰)を行ったら (*) を取って、 ListDataNoChange_FLG = TRUE; にする。 if ( ListDataNoChange_FLG == TRUE ) //保存処理をスキップする。 【できれば】 あとは、pNMLV->uChanged などの 4とか8とか、定数で記述したいです。 lParamが何を意味しているか?分からないです。教えて下さい。 void CFileListCreatorDlg::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult) {   LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);   // TODO: ここにコントロール通知ハンドラー コードを追加します。   if (( pNMLV->uChanged == 4 && pNMLV->uNewState == 0 && pNMLV->uOldState == 0 ) //リストコントロールにアイテムが追加した時     || ( pNMLV->uChanged == 8 && pNMLV->uNewState == 3 && pNMLV->uOldState == 0)){ //「すべてを置換」「置換」ボタンを押した時 //「検索」ボタンで検索しただけでも選択状態になる     //|| ( pNMLV->uChanged == 8 && pNMLV->uNewState == 0 && pNMLV->uOldState == 1 )     //|| ( pNMLV->uChanged == 8 && pNMLV->uNewState == 0 && pNMLV->uOldState == 2 )     //|| ( pNMLV->uChanged == 8 && pNMLV->uNewState == 0 && pNMLV->uOldState == 3 )){     ListDataNoChange_FLG = FALSE;//追加 2012.05.13          CFileListCreatorDlg* m_Dlg = (CFileListCreatorDlg*)AfxGetMainWnd();     if( (m_Dlg==NULL)||(m_Dlg->GetSafeHwnd()==NULL) ){       return;     }     m_Dlg->SetWindowText(_T("FileListCreator (*)"));   }   //CString tempStr;   //tempStr.Format(_T("OnLvnItemchangedList iItem: %d, lParam: %d, uChanged: %d, uNewState: %d, uOldState: %d\n"), pNMLV->iItem, pNMLV->lParam, pNMLV->uChanged, pNMLV->uNewState, pNMLV->uOldState);   //MessageBox(tempStr);   *pResult = 0; } void CFileListCreatorDlg::OnLvnDeleteitemList(NMHDR *pNMHDR, LRESULT *pResult) {   LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);   // TODO: ここにコントロール通知ハンドラー コードを追加します。   ListDataNoChange_FLG = FALSE;//追加 2012.05.13   CFileListCreatorDlg* m_Dlg = (CFileListCreatorDlg*)AfxGetMainWnd();   if( (m_Dlg==NULL)||(m_Dlg->GetSafeHwnd()==NULL) ){     return;   }   m_Dlg->SetWindowText(_T("FileListCreator(*)"));   *pResult = 0; } ご教授下さい。

  • リストコントロールにセットするイメージリストについて

    こんにちは。 Windowsでレポート状態表示のリストコントロールについて質問です。 リストコントロールははオーナーデータで表示しています。 一覧でアイテムの横にアイコン(ビットマップ)を表示しています。 またソートできるようにし、コラム部分には昇順か降順か分かるように▲▼が 表示されるようにしようと思っています。 リストコントロールに表示するアイテム用のイメージリストとヘッダー コントロール用のイメージリストを用意し、リストコントロールと リストコントロールから取得したヘッダーコントロールにそれぞれ 追加したのですが、 Header_SetImageList(ヘッダーコントロールのウィンドウハンドル) ; ListView_SetImageList(リストコントロールのウィンドウハンドル) ; 上記の順番では後から追加したイメージリストで上書きされてしまいました。 Header_GetImageListでイメージリストを取るとListView_SetImageListで セットしたイメージリストのハンドルが取得されます。 リストコントロールでイメージリストを取り扱う場合はリストアイテムも ヘッダーも一つのイメージリストで管理しなければならないのでしょうか ?

  • リストコントロール(MFC or API)の最後尾にアイテムを追加するには?

     以下のような手順でリストコントロールにアイテムを追加しています。すると新しいアイテムはリストコントロールの先頭に追加されてしまいます。  先頭ではなくリストの最後尾にアイテムを挿入するにはどうしたらいいのでしょうか?  このサンプルはMFCですが回答はAPIやほかの手段を使っていても構いません。ヒントだけでも分かる方がいましたらお願いします。 LVITEM sItem; sItem.mask = LVIF_TEXT; sItem.iItem = 0; sItem.iSubItem = 0; sItem.pszText = LPSTR_TEXTCALLBACK; m_lpcList->InsertItem(&sItem);

  • Excel VBA でリストボックスへ行追加について

    お世話になります。 ExcelVBAで、ユーザフォーム表示のときに、リストボックスにデータを追加します。 その際、追加したいアイテムが項目数3の配列なのです。 配列もユーザ定義した配列(2次元配列)を使っています。 配列を作って、.List=Array でセットしようと思ったのですが、コンパイルエラーが出ます。 どうしたらよいでしょうか。 説明がわかりにくいかもしれませんが、よろしくお願い致します。

  • データ リスト コントロールについて教えてください

    AccessのデータをADOデータコントロールを通じてデータリストコントロールに表示させています。データリストの10のリストのうち3番目のリストを取得(マウスで選択せずに)するにはどうすればよいでしょうか?またリストの総数を取得するにはどうすればよいのでしょうか? 大変初歩的な質問ですがよろしくお願いします。

  • エクセルのリスト表示に関して

    エクセルで 入力規則のリストをつくりを2つのセルにある数値を選んで表示できるようにしたいと思っていますが、 「入力規則」 → 「リスト」に行き 関数を表示しているセルを『2つ』選ぶと 条件 データの入力規則 には、OR演算、AND演算、配列定数は使用出来ません。 となります。 使用している関数は =数値*1.05 とかの関数です。 どうやれば出る様になるかお教え下さい。

  • MFCのCListCtrlでスクロールを検出

    MFCのダイアログアプリを作成しています。 レポートスタイルのリストコントロールを配置して、全部で1000行のアイテム を表示させたいのですが、いきなり1000行は多すぎるので最初に始めの100行分 だけ表示して、ユーザーがスクロールバーを一番下まで移動させるたびに 次の100行を追加挿入していって表示させるようにしたいと思っています。 そこでまずはユーザーがスクロールバーを一番下まで移動させたタイミングを イベントで拾おうと思ったのですが、それっぽいLVN_BEGINSCROLL、 LVN_ENDSCROLLなどのイベントハンドラを作成してスクロールバーを 動かしてもうまく呼ばれません。どうすればいいかご教示ください

  • Win32のリストコントロールで縦スクロールはできませんか?

    こんにちは。Win32のリストコントロールについて質問です。 リストコントロールでアイコン表示で使用しています。 リストコントロールでアイコンをたくさん表示させると、縦幅に入る範囲で アイコンが複数行表示され、入らないアイコンは横スクロールさせることで 表示できますが、これを縦スクロールベースにはできないものでしょうか ?

  • VBScriptでCSVファイルを読み出したい

    現在VBScriptでCSVファイルを1行ずつ読み取って、2次元配列に格納するプログラムを作成しています。 CSVファイルの中身は、サンプルで shop,price,sales 001,500,700 003,1200,90 024,,18 という並びになっています。 実データは300件くらいです。 1行目のヘッダーを読み飛ばし、2行目のデータから1行ずつ読取、","でsplitを用いてまず1次配列に格納しています。 1次元配列のarrLine(0)=001、(1)=500、(2)=700と入ったデータを 2次元配列arrshopに順次保存?したいのです。 ---------------------------------------------- dim strLine '1行ずつ読込んだデータを持つ dim ntLineNum '行数のカウント dim arrLine '","で区切った要素を持つ一次元配列 dim arrshop '一次元配列になった要素を2次元配列として格納 Do until .AtEndOfStream   strLine = .ReadLine   if 0<>strComp("",Trim(strLine)) then ntLineNum = intLineNum + 1   end if   arrLine = split(strLine , ",")   arrshop = Array(arrLines,i) i = i + 1 loop ----------------------------------------- msgbox arrshop(2)(0) と指定すると「003」出るようにしたいです。 Array関数が上手くないような気もします・・・。 どなたかご教授お願いします(>_<。)

専門家に質問してみよう