
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 は避けたいと考えています。
あるいは、上記のコーディングで、何かおかしいんじゃないかという部分がありましたら教えていただけませんでしょうか。
よろしくお願いします。
A 回答 (1件)
- 最新から表示
- 回答順に表示
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;
とかやってみたらどうなりますかね?
この回答への補足
早速の回答ありがとうございます。
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 のバグのような気がしてきました・・・。
エクスプローラだとどうなるのか試してみましたところ、エクスプローラでも同じ現象が確認できました。
エクスプローラは、標準の状態ではNTFS圧縮ファイル、NTFS圧縮フォルダを青 ( RGB( 0, 0, 0xff ) ) で表示しますが、
レジストリのキー
HKEY_CURRENT_USER\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer
に
"AltColor"=hex:00,00,80,00
を追加して、Windows を再起動したところ、エクスプローラでもファイル名のみが濃紺で、サイズなどの項目は黒になりました。
リストビューコントロールのバグなのか、私が使用しているシステムがおかしくなっているのかはわかりませんが、少なくとも、自作プログラムのバグでないことはわかりましたので、この質問は締め切らせていただきます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
リストビューで選択行の背景を変える
C言語・C++・C#
-
リストコンロールの一行だけを太文字に(VC++)
C言語・C++・C#
-
空のリストビューで1行おきに背景色を変える
C言語・C++・C#
-
-
4
リストコントロールのデータの変更を検知したい
C言語・C++・C#
-
5
CStringのFindで文字列検索を行いたいのですが
C言語・C++・C#
-
6
ダイアログ内コントロールの位置取得について
C言語・C++・C#
-
7
MFCでコンボボックスを選択不可状態にしたい
C言語・C++・C#
-
8
ビジュアルC++でボタンの有効/無効
C言語・C++・C#
-
9
VC++で文字列から任意の文字を削除するにはどうしたらいいですか?
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
コマンドプロンプトで作成日時...
-
アクセス 壊れた? 「ファイ...
-
#include <Windows.h>というヘ...
-
binファイルを解凍したいの...
-
C言語---ファイルに出力したデ...
-
リンクの張り付けかたを教えて...
-
監視ツールを入れさせられまし...
-
Latexで図番号だけを「図1.1」...
-
jarファイル
-
Matlab/ @の意味
-
参照するファイルをワイルドカ...
-
HTMLからのBATファイル実行
-
「ブルーファイル」と「グリー...
-
warファイルをEclipseでプロジ...
-
【VBS】 iniファイルの特定部...
-
CSVから指定行だけを読み込み
-
CSSファイルの日本語コメントが...
-
cgiファイルが開けないです。
-
Doxygenで#includeのファイル内...
-
公文書のxmlファイルの開き方が...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
binファイルを解凍したいの...
-
アクセス 壊れた? 「ファイ...
-
コマンドプロンプトで作成日時...
-
#include <Windows.h>というヘ...
-
Latexで図番号だけを「図1.1」...
-
リンクの張り付けかたを教えて...
-
.NETアプリを作ったときの .man...
-
jarファイル
-
コマンドプロンプトで、指定し...
-
「営業秘密の漏洩」について
-
自分で作成した重要ファイルを...
-
warファイルをEclipseでプロジ...
-
公文書のxmlファイルの開き方が...
-
ストレージにある全てのファイ...
-
C言語---ファイルに出力したデ...
-
HTMLからのBATファイル実行
-
ファイルが開かれているかどう...
-
監視ツールを入れさせられまし...
-
「ブルーファイル」と「グリー...
-
バッチ処理で追記コピーしたい
おすすめ情報