• 締切済み

リストビューのカスタムドローについて

Windows XP SP3 + Visual Studio 2008 C++ で、リストビューを使用したダイアログベースのソフトを作っています。 リストビューには、ファイル名、ファイルサイズ、最終更新日時を「詳細」で表示させています。(よくあるファイル一覧です。) エクスプローラと同じように、ファイル名等のテキストを NTFS の圧縮ファイルは青 暗号化ファイルは緑 で表示させようと思い、カスタムドローを使用しています。 また、圧縮でもなく暗号化でもないファイルに対しては、ChooseFont() で選択された色 ( CHOOSEFONT 構造体の rgbColors ) を設定しています。 ChooseFont() で選択した色のうち、濃紺以外の色は問題なく表示されているのですが、なぜか、ChooseFont で濃紺 ( 0x00800000 ) を選択した場合だけ、第一列 ( ファイル名 ) のみ濃紺になり、第二列目以降 ( ファイルサイズ、最終更新日時 ) が、システム設定値 ( 黒 ) となります。 しかも、リストビューのスタイルを拡張スタイルの LVS_EX_FULLROWSELECT ( 行選択モード? ) にすると、濃紺の場合でも、第二列目以降も正常に表示されます。 コーディングは、カスタムドローの部分だけを抜粋すると以下のような感じになっています。 LPNMLVCUSTOMDRAW pnmlvcd; LVITEM lvi; DWORD dwAttributes; switch( message ) { case NM_CUSTOMDRAW:   pnmlvcd = ( LPNMLVCUSTOMDRAW )lParam;   switch( pnmlvcd->nmcd.dwDrawStage ) {   case CDDS_PREPAINT:     SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_NOTIFYITEMDRAW );     return( TRUE );   case CDDS_ITEMPREPAINT:     lvi.mask = LVIF_PARAM;     lvi.iSubItem = 0;     lvi.iItem = pnmlvcd->nmcd.dwItemSpec; // 描画しようとしている行のインデックス     if( ListView_GetItem( hwndList, &lvi ) ) {       // 属性を取得       // lvi.lParam はファイルの情報を格納した構造体 FILEITEM へのポインタです。       dwAttributes = ( ( PFILEITEM )lvi.lParam )->dwAttributes;       if( 通常ファイルの場合 ) {  // dwAttributes を使用して属性を判定         // ChooseFont で選択した色を設定         pnmlvcd->clrText = cfList.rgbColors;         SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );         return( TRUE );       } else if( 圧縮ファイルの場合 ) {  // dwAttributes を使用して属性を判定         // 青         pnmlvcd->clrText = RGB( 0, 0, 0xff );         SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );         return( TRUE );       } else if( 暗号化ファイルの場合 ) {  // dwAttributes を使用して属性を判定         // 緑         pnmlvcd->clrText = RGB( 0, 0xff, 0 );         SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );         return( TRUE );       }     }   }   break; hwndMain はダイアログのウィンドウハンドル、hwndList はリストビューのウィンドウハンドルです。 (見やすくするため、スペースに全角スペースを使用しています。また、属性の判定部分は実際には dwAttributes との、&、| を使用しています。) コーディング的には、ChooseFont() で何色が選択されようが知ったこっちゃないという感じなのですが・・・。 試しに、ChooseFont() で選択した色ではなく、RGB( 0, 0, 0x80 ) を指定しても同様の現象でした。 濃紺の場合でも、LVS_EX_FULLROWSELECT でなくても第二列目以降が正しい色で表示されるようにする方法はないでしょうか。 このリストビューは Drag & Drop のソース側の機能も実装していまして、その影響で、LVS_EX_FULLROWSELECT だと、Drag 操作による複数行選択の操作が難しくなるので、LVS_EX_FULLROWSELECT は避けたいと考えています。 あるいは、上記のコーディングで、何かおかしいんじゃないかという部分がありましたら教えていただけませんでしょうか。 よろしくお願いします。

みんなの回答

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

カスタムドロー、その辺りまで試したことはありませんが… CommCtrl.hに #if (_WIN32_IE >= 0x0400) #define CDDS_SUBITEM 0x00020000 #endif なんてのがありますが…… case CDDS_ITEMPREPAINT: だけだと、CDDS_SUBITEMのビットが設定されている場合は対応できません…よね? _WIN32_IEが0x0400以上に設定されている必要はあるかと思われますが…   case (CDDS_SUBITEM | CDDS_ITEMPREPAINT):   case CDDS_ITEMPREPAINT:     lvi.mask = LVIF_PARAM; とかやってみたらどうなりますかね?

tsukasa-12r
質問者

お礼

エクスプローラだとどうなるのか試してみましたところ、エクスプローラでも同じ現象が確認できました。 エクスプローラは、標準の状態ではNTFS圧縮ファイル、NTFS圧縮フォルダを青 ( RGB( 0, 0, 0xff ) ) で表示しますが、 レジストリのキー HKEY_CURRENT_USER\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer に "AltColor"=hex:00,00,80,00 を追加して、Windows を再起動したところ、エクスプローラでもファイル名のみが濃紺で、サイズなどの項目は黒になりました。 リストビューコントロールのバグなのか、私が使用しているシステムがおかしくなっているのかはわかりませんが、少なくとも、自作プログラムのバグでないことはわかりましたので、この質問は締め切らせていただきます。

tsukasa-12r
質問者

補足

早速の回答ありがとうございます。 CDDS_ITEMPREPAINT に対して CDRF_DODEFAULT を返すと、それ以降のサブアイテムに対しては「デフォルト」の処理が行われるようで、CDDS_SUBITEM | CDDS_ITEMPREPAINT のメッセージは送られてきませんでした。 CDDS_ITEMPREPAINT に対して CDRF_NOTIFYSUBITEMDRAW を返すように、 case CDDS_ITEMPREPAINT:   pnmlvcd->clrText = cfList.rgbColors;   ・・・   SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_NOTIFYSUBITEMDRAW );   return( TRUE ); case CDDS_SUBITEM | CDDS_ITEMPREPAINT:   pnmlvcd->clrText = cfList.rgbColors;   ・・・   SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );   return( TRUE ); とすることで CDDS_SUBITEM | CDDS_ITEMPREPAINT の場合の処理が実行されるようになりました。(ブレークポイントを設定して確認しました。) が、状況は変わりませんでした。 case CDDS_SUBITEM | CDDS_ITEMPREPAINT: なしの場合でも、ありの場合でも、濃紺以外の色でしたらサブアイテムも設定した色で表示されていますので、Microsoft のバグのような気がしてきました・・・。

関連するQ&A

  • リストビューで選択行の背景を変える

    お世話になります。リストビューの選択行の背景色を変えたいと思い、カスタムドローを用い以下のようにしましたが、選択していない所も赤になってしまいます。 if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {  // 選択行の背景色を変更  if (lplvcd->nmcd.uItemState & CDIS_SELECTED) {   lplvcd->clrTextBk = RGB(255, 0, 0);   lplvcd->nmcd.uItemState &= ~CDIS_SELECTED;  } else {   lplvcd->clrTextBk = RGB(255, 255, 255);  }  return CDRF_NOTIFYSUBITEMDRAW; } デバッグモードで見ると、else以降の分は解釈されていないようです。 リストビューは g_hList = CreateWindowEx(0 , WC_LISTVIEW , 0 , WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_NOSORTHEADER | LVS_SHOWSELALWAYS, 1 , 1 , width , lv_height , g_hMain , (HMENU)1 , g_hInst , NULL); dwStyle = ListView_GetExtendedListViewStyle(g_hList); dwStyle |= LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES; ListView_SetExtendedListViewStyle(g_hList, dwStyle); ListView_SetBkColor(g_hList, RGB(240,240,240)); のようにしています。宜しくお願いします

  • LVS_EX_FULLROWSELECTが効かない

    LVS_EX_FULLROWSELECTをリストコントロールに指定して、一行選択をしたいのですが、なぜか効きません。なぜでしょうか? ソース---------------- BOOL CXXXXXX::OnInitDialog() { CPropertyPage::OnInitDialog(); ListView_SetExtendedListViewStyle( m_LIST.m_hWnd , LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_UNDERLINEHOT ); ・・・・・ } プロパティページ内にリストコントロールを貼り付けて使っています。 よろしくお願いします。

  •  WindowsAPIのリストビューのチェックボックスでの質問

     WindowsAPIのリストビューのチェックボックスでの質問 開発環境はVS.NET2003です。 リストビューでチェックボックスを使っているのですが、 チェックボックスを1つしかチェックできないようにしたいのです。 リストビューの拡張スタイルであるLVS_EX_CHECKBOXESを指定してチェックボックスのあるリストビューを作成したのですが、チェックできるのが一つのみにしたいのです。 LVN、LVNIメッセージを調べたのですが、これに該当するものが見つからないためここで質問しました。 LV_DISPINFO構造体を使ってメッセージを受け取るのですが、ここで変更を行ったほうがいいんでしょうか? C++とありましたが、ListCheckBoxクラスを使用していません。 このクラスを使用しない方法をお願いします。  

  • リストビューの選択状態を取得するメッセージはありますか?

    リストビューが選択状態(1行が青色や灰色の背景になる状態)にあって、エディットボックスが空欄では無いときに、 あるボタンを有効にするという処理をしたいと思っています。 リストビューが選択されていることを教えてくれるメッセージがあれば、教えてください。よろしくお願いします。 環境:Win32 API, VC++6.0

  • VB6を使っています。リストビューのカラムヘッダーの色を変えたい。

    VB6を使っています。リストビューのカラムヘッダーの色を変えたい。 リストビューのカラムヘッダーをクリックしたら、そのカラムヘッダーの文字色が変わるとか、又は背景色が変わるとかしてその列が選択されたと判るようにしたいのですが、可能でしょうか? ColumnHeadersにはForecolorとかFontcolorといったものは無さそうなのでどうすればいいか判りません。 別に色にはこだわりません。 太字でもいいです。列がわかればいいのです。よろしくご指導下さい。

  • リストビューの画面表示部分

    リストビューの選択によってsubitemの文字の色を変えることになりました。 問題はリストビューの件数で数万件のデータがあります。 そこでリストの画面表示部分を知りたいのです。 例えば1000件のリスト中、画面に表示されているのは20件目から12件であるという具合に。 この20件目から12件という情報は取得することができるのでしょうか? あるいは数万件といえどパソコン上では瞬間だから、 そんなこと気にせずに全リストをループさせても良いものでしょうか? 設計上、どのようにしたら良いか悩んでいます。 ちなみにマシンはCore2Duo以降を念頭に考えて下さい。

  • VC++リストビューで選択されている色の変更

    リストビューで表示スタイルをレポートにしています。 で、マウスなどでクリックすると当然のごとく青色に選択され、別のウィンドウをクリックすると灰色になるのですが、この青色と灰色両方の色を変えたいのですがどうしたらよいでしょうか?よろしくお願いします。

  • リストビュー、ツリービューの選択時の色がなくなる(XP)

    Becky、OutlookExpressなどの複数のソフトで、ツリービュー(Outlookの左側のコンポーネント)、リストビュー(Outlookの右下側のコンポーネント)に関し、次の症状で困ってます。 ・フォーカスがあるときは背景色が青で、通常どおりどれが選択されているかわかる ・フォーカスを他のコントロールに移動させると、背景色が薄い灰色となり、目をよほど凝らしてみないとどれが選択されているかわからない ・上記症状のでるPCで、画面のスタイルをXPスタイル(標準)からWindows2000スタイルにすると上記症状はなくなり、非選択状態でもどれが選択されているかわかるようになる。詳細設定をいろいろいじりましたが、解決できませんでした ・上記状態は、Windows2000マシンでは発生せず、XP固有の問題だと考えられます Windows200スタイルにしてしまえば解決するのはわかりますが、プログラムの開発をしている関係上、XP標準状態のままでいたいと思ってます。 よろしくお願いします

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

    お世話になります、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 です。 ご回答をお待ちしております。

  • エクセルVBA リストビュー選択項目を別フォームへ

    皆さんこんにちは。 エクセル2013使用のVBA初心者です。 エクセルVBAのリストビューについて教えてください。 Userform1上にListview1とコマンドボタン1があります。 Listview1はSheet1を呼び込んだものが反映されており 左から駅名・顧客名・店舗名が記載されています。 Listview1でどれかを選択してコマンドボタン1を押したら Listview1で選択した項目の 駅名をUserform2のTextbox1に 顧客名を〃のTextbox2に 店舗名を〃のTextbox3に反映したいのですが リストビューの情報がネット上にも少なく コードをどのように書いたら良いか見当がつきません。 Userform2のPrivate Sub UserForm_Initialize()に TextBox1 = UserForm1.ListView1.FocusedItem.SubItems(0).Text を記載してみたものの、コンパイルエラーが出てしまいます。 (スイマセン、あまり意味が分かっていないで書きました) リストビューで選択した項目を別のユーザーフォームに 反映させるにはどうしたら良いでしょうか? どなたかヒントをいただけると助かります。

専門家に質問してみよう