ラジオボタン(オプションボタン)のオーナー描画について
Posted: 2011年4月06日(水) 15:56
BCC Developer 1.2.21 (borland C++)でC++のプログラムを書いています。(Windows Me)
ボタンタイプのラジオボタン(オプションボタン)をオーナー描画して作りたいと下記のようなコードを書いたのですが、ラジオボタンとして正しく動きません。
現象としては「ラジオボタン(同一グループ)以外の他のコントロールを一度触った後に再び何れかのラジオボタンを押すと、直前に押していたラジオボタンが凹んだままで、凸に戻らない」
というものです。
何故そうなるのかについてはある程度明らかなのですが、
(下記のコード中ではオーナーウインドウのコールバック・プロシージャ内で
WM_DRAWITEMを拾ってオーナー描画をしているのですが、そのとき
同一グループ内のあるラジオボタンから別のラジオボタンをクリックしたときには、
LPARAM で渡されるDRAWITEMSTRUCT構造体の情報、
コントロールのIDとlpDraw->itemAction、itemStateの値が次のような順で現れます。
① ボタンを押した時 ---> ID=今回押したボタン itemAction=ODA_SELECT itemState=17(※1)
② 「①」の直後に ---> ID=前回押していたボタン itemAction=ODA_DRAWENTIRE itemState=0
③ 「①」のボタンを離した時---> ID=今回押したボタン itemAction=ODA_SELECT itemState=16(※2)
(※1 17= ODS_SELECTED(16) | ODS_FOCUS(1) )
(※2 16= ODS_SELECTED(16) )
ここで直前に押されていたボタンを元に戻すのにこのコードでは②のitemAction=ODA_DRAWENTIREを拾った時を利用して行っています。
ところが一度他のコントロール(又は他のウインドウ)を触ってからラジオボタンにもどると
②が現れず、①→③と直接移ります。これにより前に押していたボタンが「押されっぱなし」になってしまうものと思われます。
ただしそのことが分かっても、いざそれを直そうとすると一体どのようにしていいのか分からず。直前のボタンのデバイス・コンテキストや描画用のRECT構造体など一切合切保存して、他のコントロールから移ってきたかどうかを判定して、、というのもどうなのかなという気もしますし。。。
このようなラジオボタンのオーナー処理について、良い方法がありましたらご教授下さい。
ボタンタイプのラジオボタン(オプションボタン)をオーナー描画して作りたいと下記のようなコードを書いたのですが、ラジオボタンとして正しく動きません。
現象としては「ラジオボタン(同一グループ)以外の他のコントロールを一度触った後に再び何れかのラジオボタンを押すと、直前に押していたラジオボタンが凹んだままで、凸に戻らない」
というものです。
何故そうなるのかについてはある程度明らかなのですが、
(下記のコード中ではオーナーウインドウのコールバック・プロシージャ内で
WM_DRAWITEMを拾ってオーナー描画をしているのですが、そのとき
同一グループ内のあるラジオボタンから別のラジオボタンをクリックしたときには、
LPARAM で渡されるDRAWITEMSTRUCT構造体の情報、
コントロールのIDとlpDraw->itemAction、itemStateの値が次のような順で現れます。
① ボタンを押した時 ---> ID=今回押したボタン itemAction=ODA_SELECT itemState=17(※1)
② 「①」の直後に ---> ID=前回押していたボタン itemAction=ODA_DRAWENTIRE itemState=0
③ 「①」のボタンを離した時---> ID=今回押したボタン itemAction=ODA_SELECT itemState=16(※2)
(※1 17= ODS_SELECTED(16) | ODS_FOCUS(1) )
(※2 16= ODS_SELECTED(16) )
ここで直前に押されていたボタンを元に戻すのにこのコードでは②のitemAction=ODA_DRAWENTIREを拾った時を利用して行っています。
ところが一度他のコントロール(又は他のウインドウ)を触ってからラジオボタンにもどると
②が現れず、①→③と直接移ります。これにより前に押していたボタンが「押されっぱなし」になってしまうものと思われます。
ただしそのことが分かっても、いざそれを直そうとすると一体どのようにしていいのか分からず。直前のボタンのデバイス・コンテキストや描画用のRECT構造体など一切合切保存して、他のコントロールから移ってきたかどうかを判定して、、というのもどうなのかなという気もしますし。。。
このようなラジオボタンのオーナー処理について、良い方法がありましたらご教授下さい。
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInstance;
HWND hMainWnd;
HFONT hFont;
HBRUSH h3DFaceBrush;
HWND hRadioButton[15];
const RadioButton1=100;
long oldRadioButtonID;
//
//●コールバック・プロシージャ(ラジオボタンのオーナーウインドウ)
//
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_CREATE:{
hInstance=((CREATESTRUCT *)lp)->hInstance;
hFont=CreateFont(-12,0,0,0,400,0,0,0,128,3,2,1,32,"MS Pゴシック");
hMainWnd=hWnd;
SetWindowPos(hMainWnd,NULL,0,0,296,316, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
SetWindowText(hMainWnd,"ラジオボタン・テスト");
//-----------------------------
//16個(4×4)のラジオボタン作成
//-----------------------------
long radioButton_offsetXA=16,radioButton_offsetYA=16;
long radioButtonXV=64, radioButtonYV=64;
long radioButtonXA, radioButtonYA;
int i;
for (i=0; i<16; i++){
radioButtonXA=radioButton_offsetXA+radioButtonXV*(i & 3);
radioButtonYA=radioButton_offsetYA+radioButtonYV*(i >> 2);
hRadioButton[i]=CreateWindowEx(0x00000000,"BUTTON","",0x50001309 | BS_OWNERDRAW, radioButtonXA, radioButtonYA, radioButtonXV, radioButtonYV, hMainWnd, (HMENU)(RadioButton1+i),hInstance,0);
SendMessage(hRadioButton[i],WM_SETFONT,(WPARAM)hFont,0);
}
ShowWindow(hMainWnd,SW_SHOW);
}return TRUE;
case WM_DRAWITEM:{
//---------------------------
//ラジオボタンのオーナー描画
//---------------------------
LPDRAWITEMSTRUCT lpDraw = (LPDRAWITEMSTRUCT)lp;
if (lpDraw->itemAction & ODA_SELECT){ //アイテム動作が「選択」なら以下の処理、そうでないなら9行下「else②」へ
if (lpDraw->itemState & ODS_FOCUS){ //アイテム状態が「フォーカス取得」なら以下の処理
if (lpDraw->CtlID != oldRadioButtonID){ //今回のラジオボタンが直前に押していたラジオボタンでないならそれを凹ませる(IDで判定)
DrawEdge(lpDraw->hDC, &lpDraw->rcItem, EDGE_SUNKEN, BF_RECT);
oldRadioButtonID=lpDraw->CtlID; //今回のラジオボタンのIDを保存
return TRUE;
}
}
}
else { //<-----else② アイテム動作が「選択」以外ならここに来るが、実際には「ODA_DRAWENTIRE」の時のみ。
//主にコントロールが他のウインドウとの重なりなどで一旦消えてしまった後などに来る。
//何故か「ODA_FOCUS」は検出されない。このif文の頭でODA_FOCUSによる判定ではなく、「ODA_SELECT」を使用しているのは単にそれだけの理由。
//ここでは何故かODA_SELECT=2 と ODA_DRAWENTIRE=1 しか現れず ODA_FOCUS=4 が現れない。
if (lpDraw->CtlID==oldRadioButtonID){ //今回のIDが直前に押していたものと同じなら「このボタンは凹んでいる」として凹み描画
DrawEdge(lpDraw->hDC, &lpDraw->rcItem, EDGE_SUNKEN, BF_RECT);
}
else { //今回のIDが直前に押していたものと違うなら「このボタンは凸」として凸描画
DrawEdge(lpDraw->hDC, &lpDraw->rcItem, EDGE_RAISED, BF_RECT);
}
return TRUE;
}
}break;
case WM_DESTROY:
DeleteObject(hFont);
DeleteObject(h3DFaceBrush);
PostQuitMessage(0);
return TRUE;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return FALSE;
}