FC2ブログ

VS2017-はじめの1/10歩(13):カスタムなチェックボックス作成

   プログラミング [2019/09/06]

VS2017を使うんだけど慣れてないからVS6でまずは作ってました。
タブレットで使うので、それっぽいGUIをちょっとだけ目指してます。

これまでの、この備忘録の内容は、
→ナレーション再生と音声認識を使う
  →そのため音声データの作り方(多言語対応)
  →ナレーション(.WAV)再生のサンプルコード
  →音声認識のサンプルコード
→VS6で作ったC/C++コードをVS2017に持って行って.cppレベルで共通にする方法
→ダイアログベースのプログラム
  →背景に画像(.BMP)を使う
  →ラベルを透かす
  →ボタンの色を変える
  →Windowsタブレット上でピンチイン/アウト:拡大縮小
  →タブレット画面の回転への対応
  →カスタムなチェックボックス作成←今回


前回、タブレット画面の回転動作に対応するためのコントロール類の拡縮の処理例を書きましたが、それでは、うまくいかないコントロールがありました。
ラジオボタンとチェックボックスです。(他にもあると思いますが、代表的なものという意味です。)

上記の2つは、ボタンコントロールの一種で、OwnerDrawができないものなんだそうです。
つまり、フォントやコントロールのサイズ、あるいはそれなりのサイズ指定の属性を持っていれば、前回の説明の類似で済むのですが、そうはいきませんでした。
※Win32 SDKの範囲内だけの話なのかもしれません。その辺をカスタマイズできるクラスとかがどっかにあるのかも。

ともかく、そうなると自分で描画するコントロールを作らないといけません。
そもそもがBUTTONコントロールの発展形みたいなものなので、ベースの動きはBUTTONクラスを利用して、足りない動き/描画の部分を個別に実装します。

幸い、ラジオボタンは利用してなかったので、サンプルはチェックボックスだけになります。

まずは、ボタンを作成する際のスタイルに「オーナー描画」=BS_OWNERDRAW を指定します。
リソースエディタ上では、見た目フツーのキャプション入りのボタンコントロールです。


◆ウィンドウプロシジャ内の処理
//----------------------------------------------
case WM_INITDIALOG:
{


//オーナードロー・ボタンのステート初期化
//切り替えは、WM_COMMANDで実施
g_fChkOpen = FALSE;
g_fChkPrint = FALSE;

return TRUE;
}



//******* オーナードローボタン描画
case WM_DRAWITEM:
{
INT cid = LOWORD(wParam);
LPDRAWITEMSTRUCT podraw = (LPDRAWITEMSTRUCT) lParam;
switch (cid) {


//チェックボックス風ボタン
//※※checkboxは文字サイズを大きくしても、ボックスの大きさが変わらない。
//かつ、BS_OWNERDRAWスタイルは、他のcheckbox、radiobuttonスタイルとは排他。
//よって、checkboxスタイルのままでオーナードローは不可。
//通常のbutton+オーナードローとし、ステートはフラグで保持する。
case IDC_CHOPEN: //g_fChkOpen
DrawCheckBoxCtrl(hDlg, podraw, g_fChkOpen);
break;
case IDC_CHPRINT: //g_fChkPrint
DrawCheckBoxCtrl(hDlg, podraw, g_fChkPrint);
break;


}
return TRUE;
} //end WM_DRAWITEM



//****** ボタンクリック等
case WM_COMMAND:
switch (LOWORD(wParam)) {



//**** チェック・ボックス風ボタン
case IDC_CHOPEN:
if (!g_fChkOpen) g_fChkOpen = TRUE;
else g_fChkOpen = FALSE;
InvalidateRect(GetDlgItem(hDlg, LOWORD(wParam)), NULL, FALSE);
return TRUE;
case IDC_CHPRINT:
if (!g_fChkPrint) g_fChkPrint = TRUE;
else g_fChkPrint = FALSE;
InvalidateRect(GetDlgItem(hDlg, LOWORD(wParam)), NULL, FALSE);
return TRUE;



} //end switch WM_COMMAND-lParam
break;
//----------------------------------------------


コアな描画処理は・・・


◆チェック・ボックス風ボタンのオーナードロー処理
//----------------------------------------------
//name :DrawCheckBoxCtrl
//function :チェックボックスの描画を行う
//parameter :hDlg -ダイアログウィンドウハンドル
// pOwnDraw -オーナーDRAW情報
// fState -CHECKED/UNCHECKEDステート
//global :なし
//return :なし

VOID DrawCheckBoxCtrl(
HWND hDlg,
LPDRAWITEMSTRUCT pOwnDraw,
BOOL fState)
{
HWND hctrl = pOwnDraw->hwndItem;
HDC hdc = pOwnDraw->hDC;
RECT rect, bxrect;
TCHAR capt[128];
POINT pt[6];
HBRUSH hbrs, hbrs_org;
HPEN hpen, hpen_org;
INT lnw = 2;
COLORREF bg_col, bx_col, bxln_col, tx_col;

//ボタン以外の場合は何もしない
if (pOwnDraw->CtlType != ODT_BUTTON) return;
//非活性の場合は色を変更する
if (pOwnDraw->itemState & ODS_DISABLED) {
bg_col = RGB(159,159,159);
bx_col = RGB(223,223,223);
bxln_col = RGB( 63, 63, 63);
tx_col = RGB( 32, 32, 32);
}
else {
bg_col = RGB(223,223,223);
bx_col = RGB(255,255,255);
bxln_col = RGB( 0, 0, 0);
tx_col = RGB( 0, 0, 0);
}

GetClientRect(hctrl, &rect);
GetWindowText(hctrl, capt, sizeof(capt));
//背景塗りつぶし
hbrs = CreateSolidBrush(bg_col);
hbrs_org = (HBRUSH) SelectObject(hdc, hbrs); //一時ブラシ設定&元ブラシ退避
FillRect(hdc, &rect, hbrs);
//チェック枠塗りつぶし
lnw = 4;
hbrs = CreateSolidBrush(bx_col);
DeleteObject(SelectObject(hdc, hbrs)); //一時ブラシ2設定&一時ブラシ廃棄
bxrect.top = rect.top + lnw;
bxrect.bottom = rect.bottom - lnw;
bxrect.left = rect.left + lnw;
bxrect.right = bxrect.left + (bxrect.bottom - bxrect.top);
FillRect(hdc, &bxrect, hbrs);
//チェック枠線描画
hpen = CreatePen(PS_SOLID, 1, bxln_col);
hpen_org = (HPEN) SelectObject(hdc, hpen); //一時ペン設定&元ペン退避
pt[0].x = bxrect.left;
pt[0].y = bxrect.top;
pt[1].x = bxrect.right;
pt[1].y = bxrect.top;
pt[2].x = bxrect.right;
pt[2].y = bxrect.bottom;
pt[3].x = bxrect.left;
pt[3].y = bxrect.bottom;
pt[4].x = bxrect.left;
pt[4].y = bxrect.top;
Polyline(hdc, pt, 5);
//チェックマーク線描画
if (fState) {
lnw = 5;
hpen = CreatePen(PS_SOLID, 4, bxln_col);
DeleteObject(SelectObject(hdc, hpen)); //一時ペン2設定&一時ペン廃棄
pt[0].x = bxrect.left + lnw;
pt[0].y = bxrect.top + lnw + (bxrect.bottom - bxrect.top) / 6;
pt[1].x = bxrect.left + (bxrect.right - bxrect.left) / 2;
pt[1].y = bxrect.bottom - lnw;
pt[2].x = bxrect.right - lnw;
pt[2].y = bxrect.top + lnw;
Polyline(hdc, pt, 3);
}
//キャプション描画
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, tx_col);
bxrect.left = rect.left + (rect.bottom - rect.top) * 3 / 2;
bxrect.right = rect.right;
bxrect.top = rect.top;
bxrect.bottom = rect.bottom;
DrawText(hdc, capt, -1, &bxrect, DT_SINGLELINE | DT_VCENTER | DT_LEFT);

//フォーカスを持っている場合
if (pOwnDraw->itemState & ODS_FOCUS) {
hpen = CreatePen(PS_DOT, 1, RGB(0, 0, 32));
DeleteObject(SelectObject(hdc, hpen)); //一時ペン3設定&一時ペン2廃棄
lnw = 2;
pt[0].x = rect.left + lnw;
pt[0].y = rect.bottom - lnw;
pt[1].x = rect.left + lnw;
pt[1].y = rect.top + lnw;
pt[2].x = rect.right - lnw;
pt[2].y = rect.top + lnw;
pt[3].x = rect.right - lnw;
pt[3].y = rect.bottom - lnw;
pt[4].x = rect.left + lnw;
pt[4].y = rect.bottom - lnw;
Polyline(hdc, pt, 5);
}

DeleteObject(SelectObject(hdc, hbrs_org)); //元ブラシ復帰&一時ブラシ廃棄
DeleteObject(SelectObject(hdc, hpen_org)); //元ペン復帰&一時ペン廃棄

return;
}
//----------------------------------------------


無駄に長いコードですが、こんな感じです。
本来、ON/OFFのフラグ処理とか含めて、クラス化した方がスッキリする気がしますが、
先を急いでたので、考えずにチャッチャと実装してしまいました。

細かい処理内容の説明は省きます。
興味のある方は、温かい気持ちでよしなに解釈してやってください。

次回・・・ボタンに画像を貼り付けるサンプルです。

では、この辺で。
m(__)m

スポンサーサイト





コメントの投稿

非公開コメント

カレンダー
01 | 2024/02 | 03
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 - -
プロフィール

さるもすなる

Author:さるもすなる
さるです。別HPサイト「さるもすなる」から侵食してきました。 山菜/きのこ、それとタイトルにしたPPバンド籠のことをメインに徒然に・・・・暇を持て余したさるの手仕事:男手芸のブログってことで。

最新記事
最新コメント
月別アーカイブ
カテゴリ
天気予報

-天気予報コム- -FC2-
本家のHPのトップ
山菜や茸の話です
PPバンドの籠作品と作り方です
投稿をお待ちしております



PVアクセスランキング にほんブログ村 にほんブログ村 ハンドメイドブログへ



マニュアルのお申し込み



検索フォーム
リンク
RSSリンクの表示
ブロとも申請フォーム

この人とブロともになる

QRコード
QR