タブコントロールの背景色を取得する方法を探しています。(メインエリアの背景色)
Windows2000とXPにおいて色が違う部分であるため、別のコントロールや独自の描画を加える際に表
示がマッチしない場合があります。
現状はXPに合わせて白っぽいカラーにあわせています。
ただし、テキストコントロールなど、背景色を透明にできるものも多く、現状で問題があるのは
チェックボックスのみとなっています。
ということでチェックボックスの背景色を透明にする方法があればそちらでも解決可能です。
とりあえず以下の二つの方法を試しましたが失敗に終わりました。
・SendMessage( hWnd, WM_CTLCOLORDLG, ... で背景色を取得
・GetPixelを使用し気合で背景色を取得
WM_CTLCOLORDLGでは灰色のカラーが取得できましたが目的の色とは違いました。
WM_PAINTでのGetPixelは常に0xffffffffが得られました。何か違うのでしょうか?
という感じです。
■開発環境は以下の通り
Win32プロジェクト
VisualC++2005
ショボイ質問(?)かもしれませんがよろしくおねがいします。
■追記
各種コントロールはリソースエディタを使わずにCreateWindow,CreateWindowExを使用して作って
います。
タブコントロール
CreateWindowEx( 0, WC_TABCONTROL, ...
チェックボックス
CreateWindow( _T(BUTTON), _T(ああああ), WS_CHILD | WS_VISIBLE |
BS_AUTOCHECKBOX, ...
といった感じです。
ボタンやダイアログの色や文字って
画面のプロパティで変えられるけど
そういうこと?
GetSysColorとは違うのか?
XP の VisualStyle が有効になっている場合、描画に必要な情報は Theme API から得ら
れます。
おそらく、GetThemeSysColor という API がお求めのものかと思います。
シャノンさん。
返信ありがとうございます。
GetThemeSysColorを調べて使ってみましたがやはり目的の色とは少し違うようです。
ただし、使い方が合ってるかは微妙です。(GetThemeSysColorでググってもあんまりヒットしな^
^;)
#include <uxtheme.h>
#include <tmschema.h>
#pragma comment(lib, uxtheme.lib )
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HTHEME hTheme;
hTheme = OpenThemeData( hWnd, _T(TAB));
if( hTheme != NULL)
{
DWORD color = GetThemeSysColor( hTheme, TMT_BACKGROUND );
m_hTabBrush = CreateSolidBrush( color );
CloseThemeData(hTheme);
}
こんな感じでブラシを取得。
TMT_BACKGROUND以外も試しましたが、なぜかすべて同じ色でした。(灰色)
それと、Theme系のAPIはWinXP専用っぽいので、Win2000ではexeが起動しなくなる恐れがありま
す。(今手元にWin2000がないので試せない^^;)
> ということでチェックボックスの背景色を透明にする方法があれば
> そちらでも解決可能です。
というか…特に何もせずに透過されちゃいました。
リソースエディタで作っているせい?
> それと、Theme系のAPIはWinXP専用っぽいので、Win2000ではexeが起動しなくなる
> 恐れがあります。(今手元にWin2000がないので試せない^^;)
VC++ には「DLL の遅延ロード」という機能があります。
DLL に含まれる関数をはじめて使う時まで、その DLL をロードしないというものです。
これを使って、XP の場合にだけ uxtheme.dll をロードすることができるかと。
> というか…特に何もせずに透過されちゃいました。
> リソースエディタで作っているせい?
コードで動的に作っても、特に透過処理を必要とせずに透過されてます。
ダイアログ自体はリソースエディタで作っているんですか?
> VC++ には「DLL の遅延ロード」という機能があります。
> DLL に含まれる関数をはじめて使う時まで、その DLL をロードしないというものです。
> これを使って、XP の場合にだけ uxtheme.dll をロードすることができるかと。
これは知りませんでした。
過去にOS依存のAPIを使おうか迷ったことが合ったので、それも解決できるかもしれません。
ありがとうございます。
> というか…特に何もせずに透過されちゃいました。
> リソースエディタで作っているせい?
実験ありがとうございます。
私の方でも一度デフォルト(色を変えない)を試してみましたが、透過されませんでした。
ただし、チェックボックスの背景色はデフォルトでダイアログの背景色と同じ物のようなので、ダイ
アログ上に直接貼り付ける場合は問題なく(透過された様に)見えます。(タブコントロール上に貼
り付けると問題になる)
透過とはこれのことではないかと推察したのですが、既にタブコントロール上に貼り付けて透過を確
認しているようなら私の誤解です。申し訳ありません。
> ダイアログ自体はリソースエディタで作っているんですか?
ダイアログはエディタを使わずにCreateWindowで作っています。
ウィンドウクラスを以下のように設定すると背景色がダイアログと同じになるので、それを使ってい
ます。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hbrBackground = (HBRUSH)GetStockObject( NULL_BRUSH );
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一応チェックボックス作成部分を記載しておきます。
気になる部分があればご指摘いただけると助かります。
hCheckBox = CreateWindow( _T(BUTTON), text, WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON, 50, 50, 10, 22, hParentWnd, (HMENU)0,
GetModuleHandle(NULL), NULL );
若輩者で勘違いしている部分もあるかと思いますが、よろしくおねがいします。
> 透過とはこれのことではないかと推察したのですが、既にタブコントロール上に
> 貼り付けて透過を確認しているようなら私の誤解です。申し訳ありません。
タブは一般的にはコントロールの親ウィンドウとしては使わないのではないでしょうか。
あれはただ「タブを切り替えたように見える」だけで、実際にはタブ上に縁なしのダイア
ログを貼り付け、その表示・非表示を切り替えるのがよくある作り方だと思います。
で、何が言いたいかというと、チェックボックスの親ウィンドウをタブではなくダイアロ
グ自体にしたため、白いタブの上でグレーのチェックボックスが浮いている状態になって
しまいました。
が、ダイアログの背景をタブ風にする方法は見つけたため、それを試行してみたところ、
チェックボックスの背景も見事に白くなりました。
この「ダイアログの背景をタブ風にする」をする場合でもしない場合でも、チェックボッ
クスの背景色は常にダイアログと同じであったことから、デフォルトで透過処理が行われ
ているように見える、と発言したわけです。
> wc.cbWndExtra = DLGWINDOWEXTRA;
> wc.hbrBackground = (HBRUSH)GetStockObject( NULL_BRUSH );
これだけでは背景色はダイアログと同じにはなりませんでした。
どうも、es さんの状況をこちらで再現できておりません。
あまり長くなければ、問題箇所のコード全文を掲載してもらうことは可能でしょうか?
親ウィンドウを CreateWindowEx で作った場合、チェックボックスの背景は勝手に透過し
てはくれませんでした。
ダイアログリソースを使うと、チェックボックスの背景色はダイアログの背景色に追従し
ました。
>> wc.cbWndExtra = DLGWINDOWEXTRA;
>> wc.hbrBackground = (HBRUSH)GetStockObject( NULL_BRUSH );
>
> これだけでは背景色はダイアログと同じにはなりませんでした。
DefWindowProc を DefDlgProc に差し替えたら背景色がダイアログになりました。
かつ、この場合、
> ダイアログリソースを使うと、チェックボックスの背景色はダイアログの背景色に
> 追従しました。
追従しませんでした。
ここからが本番。
ウィンドウプロシージャの要約を載せます。
LRESULT CALLBACK DlgProc(
HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
static HBRUSH hBrush = NULL;
switch( uMsg )
{
case WM_CREATE:
{
// タブコントロールを作成してタブページを追加 ...
// チェックボックスを作成 ...
HTHEME hTheme = OpenThemeData( hCheck, WC_TABCONTROLW );
hBrush = GetThemeSysColorBrush( hTheme, TMT_BACKGROUND );
CloseThemeData( hTheme );
return 0;
}
case WM_CTLCOLORSTATIC:
{
if( GetDlgCtrlID( ( HWND )lParam ) == IDC_CHECK1 )
{
return ( DLGPROCRESULTTYPE )hBrush;
}
break;
}
case WM_CLOSE:
{
DestroyWindow( hDlg );
return 0;
}
case WM_DESTROY:
{
DeleteObject( hBrush );
PostQuitMessage( 0 );
return 0;
}
default:
{
break;
}
}
return DefDlgProc( hDlg, uMsg, wParam, lParam );
}
申し訳ない。上記のレスは撤回。
> HTHEME hTheme = OpenThemeData( hCheck, WC_TABCONTROLW );
これが失敗しており、結果として
> return ( DLGPROCRESULTTYPE )hBrush;
が
return NULL;
と同じ状況になっていた。
これで結果的には望む状況になるのだけれど、WM_CTLCOLORSTATIC で NULL を返した場合
の挙動は MSDN に書かれておらず、これで合っているのかどうかわからない。
#なお、DLGPROCRESULTTYPE はコピペ時のミス。
#正しくは return ( LRESULT )hBrush;
非常に「今更」なレスですが…
タブコントロールの背景色にはグラデーションがかかっており、上の方ほど白く、下の方
ほど暗くなっています。
そのため、チェックボックスの位置によっては、単色で塗りつぶすのは不適切です。
場所に応じた描画を行うためには、オーナードローしなければならないかもしれません。
大変面倒くさそうではありますが…
#ちなみに、ダイアログリソースを使わずに動的に生成しているのには、何か理由が?
#一人で何度も書き込みをして申し訳ない。
> そのため、チェックボックスの位置によっては、単色で塗りつぶすのは不適切です。
ならば、単色でないブラシを用意すればいい。それだけのことでした。
それでもかなり面倒くさくなってしまいましたが…。
LRESULT CALLBACK DlgProc(
HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
static HBRUSH hBrush = NULL;
switch( uMsg )
{
case WM_CREATE:
{
// タブコントロールを作成 ...
// タブページを追加 ...
// チェックボックスを作成 ...
// hTab はタブコントロールのハンドル、
// hCheck はチェックボックスのハンドルとする。
// タブコントロールのサイズを取得し、
// タブ部分を除いたページ部分のサイズを得る
RECT rcTab;
GetClientRect( hTab, &rcTab );
TabCtrl_AdjustRect( hTab, FALSE, &rcTab );
// タブページの座標を、チェックボックスを基準とした相対座標に変換
MapWindowPoints( hTab, hCheck, ( POINT * )&rcTab, 2 );
// チェックボックスのサイズを得る
RECT rcCheck;
GetClientRect( hCheck, &rcCheck );
// チェックボックスと同じサイズのメモリビットマップを作成
HDC hdcCheck = GetDC( hCheck );
HDC hdcMem = CreateCompatibleDC( hdcCheck );
HBITMAP hbmpMem =
CreateCompatibleBitmap( hdcCheck, rcCheck.right, rcCheck.bottom );
HBITMAP hbmpOld = ( HBITMAP )SelectObject( hdcMem, hbmpMem );
// メモリビットマップにタブの背景を描画
HTHEME hTheme = OpenThemeData( hCheck, LTAB );
DrawThemeBackground( hTheme, hdcMem, TABP_PANE, 0, &rcTab, &rcCheck );
CloseThemeData( hTheme );
// ビットマップからブラシを作成
hBrush = CreatePatternBrush( hbmpMem );
// 後片付け
SelectObject( hdcMem, hbmpOld );
DeleteObject( hbmpMem );
DeleteObject( hdcMem );
ReleaseDC( hCheck, hdcCheck );
return 0;
}
case WM_CTLCOLORSTATIC:
{
if( GetDlgCtrlID( ( HWND )lParam ) == IDC_CHECK1 )
{
// チェックボックスの背景描画に、↑で作ったブラシを使う
return ( LRESULT )hBrush;
}
break;
}
case WM_CLOSE:
{
DeleteObject( hBrush );
DestroyWindow( hDlg );
}
case WM_DESTROY:
{
PostQuitMessage( 0 );
return 1;
}
default:
{
break;
}
}
return DefDlgProc( hDlg, uMsg, wParam, lParam );
}