VC++の使い方

VC++の使い方 > リファレンス > GUIリファレンス > ボタンコントロール
このページの内容
ボタンコントロールとは
作成方法
ウインドウスタイル
使い方
ありがたいスポンサー様
All About ソフトウエアエンジニア
ネットで8%割引!自動車保険はアメリカンホーム・ダイレクト
人生の「チャンス」と「ピンチ」にモビット!
保険料が一生上がらない、保険料最大50%割引の一生涯の医療保険!

ボタンコントロールとは

ボタンコントロールは、次のような用途に使います。


ボタンには、通常のボタンとデフォルトプッシュボタンの2種類があります。ダイアログにデフォルトプッシュボタンがあるときは、フォーカスがどのコントロールにあったとしても、Enter キーを押すとデフォルトプッシュボタンを押したものとして処理されます。デフォルトプッシュボタンは、たのボタンに比べて枠が太く描画されるので簡単に判別できるでしょう(下図参照)。なお、デフォルトプッシュボタンのこの機能は、ダイアログでしか機能しないので注意して下さい。

デフォルトプッシュボタンとプッシュボタン
デフォルトプッシュボタンとプッシュボタン

作成方法

CreateWindow で作成する方法

CreateWindow( 
    "button",                           // スタティックコントロールのクラス名
    "OK",                               // 表示する文字列
    BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
                                        // ウインドウスタイル
    x, y,                               // 左上の座標
    iWidth, iHeight,                    // 幅と高さ
    hParent,                            // 親ウインドウのウインドウハンドル
    NULL,                               // メニューハンドル。NULLでよい。
    hInstance,                          // アプリケーションのインスタンスハンドル。
    NULL                                // ウインドウ作成データ。NULLでよい
) ;

ダイアログで作成する方法

ダイアログエディタで作成する場合には、コントロールバーの 『ボタン』 を選択してドラッグすれば作成できます。

コントロールバーが表示されていない場合は、VC++ のメニューの上で右クリックして、『コントロール』 をチェックすれば出てきます。

ウインドウハンドルを取得するには、hwnd = GetDlgItem( hDlg, IDC_BUTTON) ;といった感じできます。

ウインドウスタイル

スタイル 意味
BS_LEFT,BS_CENTER,BS_RIGHT テキストを配置する位置を決める。通常は中央。リソースエディタでは、スタイルタブの 『水平方向の配置』
BS_TOP,BS_VCENTER,BS_BOTTOM テキストを配置する垂直方向の位置を決める。リソースエディタでは、スタイルタブの『垂直方向の配置』。
BS_NOTIFY 親ウインドウに BN_DBLCLK、BN_KILLFOCUS、BN_SETFOCUS 通知メッセージを送ることを可能にします。これを指定しなくても、 BN_CLICKED メッセージは送られます。リソースエディタでは、スタイルタブの 『通知』
BS_DEFPUSHBUTTON デフォルトプッシュボタンに設定します。リソースエディタでは、スタイルタブの 『標準のボタン』
BS_OWNERDRAW オーナードローボタンになり、ボタンの作画を自由に行うことができます。詳しくは後述。リソースエディタでは、スタイルタブの 『オーナー作画』

詳細は、『MSDNのプラットフォームSDK → Platform SDK → User Interface Services → Controls → Buttons → Button Reference → Button Styles』 にあります。ただし、MSDN では、ボタンクラスに属するチェックボックスもラジオボタンも混同して扱っているのでちょっと見にくいかもしれません。

.NET版 MSDNでは、『ユーザーインターフェースデザインおよび開発 → User Interface Design and Development → Windows User Interface → SDK Documentation → Windows User Interface → Controls → Button Controls → Button Control Reference → Button Control Styles』 です。ただし、MSDN では、ボタンクラスに属するチェックボックスもラジオボタンも混同して扱っているのでちょっと見にくいかもしれません。

見つからない場合は、検索で 『BS_CENTER』 などをキーワードに調べてみてください。

使い方

文字列を変更する

// 戻り値は成功したかどうか。
BOOL SetWindowText( HWND hwnd, LPCSTR lpString) ;

// コントロールがダイアログ内にあって、いちいち
// ウインドウハンドルを取得するのが面倒な場合は、次の関数が便利
// nIDDlgItem には コントロールID を指定。
BOOL SetDlgItemText( HWND hDlg, int nIDDlgItem, LPCTSTR lpString) ;

文字列の長さを取得する

// ウインドウハンドルが分かっていないと、文字列の長さは取得できない。
// 戻り値が長さを表わす。
int GetWindowTextLength( HWND hwnd) ;

文字列を取得する

// nMaxCount でバッファに格納できる最大文字数を指定
BOOL GetWindowText( HWND hwnd, LPSTR lpString, int nMaxCount) ;

// コントロールがダイアログ内にあって、いちいち
// ウインドウハンドルを取得するのが面倒な場合は、次の関数が便利
// nIDDlgItem には コントロールID を指定。
BOOL GetDlgItemText( HWND hDlg, int nIDDlgItem, LPCTSTR lpString, int nMaxCount) ;

クリックされた通知を読みとりたい

親ウインドウのプロシージャで、WM_COMMAND を処理すればよいでしょう。ただし、ボタンに BS_NOTIFY スタイルが適応されている場合は、フォーカスが移った場合などでも WM_COMMAND メッセージが飛ぶので注意しましょう。

case WM_COMMAND:
	if( LOWORD( wParam) == IDC_BUTTON)
	{
		if( HIWORD( wParam) == BN_CLICKED)
		{
			// クリックされたときの処理
			return TRUE ;
		}
	}

オーナードローしたい。もしくは、凝ったボタンを作りたい。

ボタンの描画はボタンのプロシージャが行っていますが、親ウインドウのプロシージャで WM_DRAWITEM を処理することで、親ウインドウで描画処理を行うことができます。これをオーナードローといいいます。オーナードローは、ボタンに限ったことでなく、他のコントロールでもできますが、ボタンでのやり方を覚えておけば他でも応用できるでしょう。

WM_DRAWITEM の lParam には DRAWITEMSTRUCT へのポインタが入っており、コントロールIDや、ボタンの状態が入っています。詳細は MSDN の WM_DRAWITEM の項目をご覧くさだい…って、手抜きなだけですが。

プロシージャを次のようにすると完成です。こういうブラシを作って描いていくような作業は繁雑になりがちなので、読みにくいかもしれませんね。出来るだけ分かりやすくまとめたつもりなんですが、ソースはbutton1.lzhをダウンロードしてご覧下さい。

static HICON hicon ;
switch( uiMsg)
{
case WM_INITDIALOG:
	hicon = LoadIcon( NULL, IDI_HAND) ;
	return TRUE ;

case WM_DRAWITEM:
{
	LPDRAWITEMSTRUCT pdis = (LPDRAWITEMSTRUCT)lParam ;
	RECT* prc = (RECT*)&pdis->rcItem ;
	HBRUSH hBrush, hOldBrush ;
	COLORREF color ;
	int iAdd = 0 ;

	// 色の作成
	if( pdis->itemState & ODS_SELECTED)  // selected 
	{
		color = RGB( 255, 255, 255) ;
		iAdd = 2 ;
	}
	else if( pdis->itemState & ODS_FOCUS) // focus
	{
		color = RGB( 204, 204, 204) ;
	}
	else // nomal
	{
		color = RGB( 204, 204, 204) ;
	}

	// ブラシの作成
	hBrush = CreateSolidBrush( color) ;
	hOldBrush = (HBRUSH)SelectObject( pdis->hDC, hBrush) ;
	SetBkColor( pdis->hDC, color) ;

	// 枠の描画
	Rectangle( pdis->hDC, prc->left, prc->top, prc->right, prc->bottom) ;
	if( pdis->itemState & ODS_FOCUS){
		// フォーカスがあるときは内枠も描く
		Rectangle( pdis->hDC, prc->left + 2, prc->top + 2, prc->right - 2, prc->bottom - 2) ;
	}
	
	// ボタンの中身を書く
	int y = prc->top + ( prc->bottom - prc->top) / 2 - 8 ;
	prc->bottom += iAdd ; // 選択されているときは、少し右にずらす
	prc->left   += iAdd ;
	prc->right  += iAdd ;
	prc->top    += iAdd ;
	DrawText( pdis->hDC, "OK", -1, prc, DT_VCENTER | DT_CENTER | DT_SINGLELINE) ;
	DrawIconEx( pdis->hDC, 10 + iAdd, y + iAdd, hicon, 16, 16, 0, NULL, DI_NORMAL) ;

	// ブラシの廃棄
	SelectObject( pdis->hDC, hOldBrush) ;
	DeleteObject( hBrush) ;
	return TRUE ;
}

case WM_COMMAND:
	DestroyIcon( hicon) ;
	EndDialog( hDlg, TRUE) ;
	return TRUE ;

default:
	return FALSE ;

なお、ボタンのようなフレームを描くには、DrawFrameControl という関数が便利なので覚えておくと良いでしょう。