<Previous> <Next> <SDK Top> <Top>
3章.11節.ツールバーのボタンの右に▼をつけてドロップダウンさせてみよう
ツールバーのボタンの右に▼をつけてドロップダウンさせてみましょう.
今回は,ドロップダウンして出てきたメニューのボタンを押したら,それを表示させるようにしましょう.
ボタンを3つ作ります.よって,IDは3つです.
(IDの作り方を知らない方は,「別章.2節.ストリングテーブルを編集してみよう」を先に読んでください.)
ID | キャプション |
IDC_BUTTON1 | 黒 |
IDC_BUTTON2 | 茶 |
IDC_BUTTON3 | 緑 |
としましょう.
前節同様,リソースビューからメニュー(IDはIDR_DROPDOWNとしときます)を編集します.
メニューのボタンのIDを決めます.
[黒]-[黒1]のID:ID_BLACK1
[黒]-[2番目黒]のID:ID_BLACK2
としましょう.
下のような感じで編集します.
今回のポイントは,
1.どうやってツールチップのボタンの右に▼をつける?
2.メニューのボタンが押されたら,どうやって表示する?
というところですね.
では,プログラムを見ましょう.
#include "stdafx.h" #include <commctrl.h> #include "resource.h" #pragma comment(lib, "comctl32.lib") #define MAX_LOADSTRING 100 // グローバル変数: HINSTANCE hInst; // 現在のインスタンス TCHAR szTitle[MAX_LOADSTRING]; // タイトル バー テキスト TCHAR szWindowClass[MAX_LOADSTRING]; // タイトル バー テキスト // このコード モジュールに含まれる関数の前宣言: ATOM MyRegisterClass( HINSTANCE hInstance ); BOOL InitInstance( HINSTANCE, int ); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); HWND ToolBarCreate(HWND hWnd); void ToolBarAddBitmapEx(HWND hToolBar, int nBotton, TBBUTTON* tbb, HINSTANCE hInst, UINT nID); void ToolBarAddButtonsEx(HWND hToolBar, int nBotton, TBBUTTON* tbb, BOOL bString); void ToolBarAddButtonSpaceEx(HWND hToolBar); void ToolBarButtonDropDown(HWND hWnd, LPNMHDR lpnm, LPNMTOOLBAR lpnmTB, int nIndex); void DispText(HWND hWnd, char* pszBuf); HWND hToolBar1; #define TOOL1_HEIGHT (30) #define NUMTBB1 (3) TBBUTTON tbb1[NUMTBB1] = { {0, IDC_BUTTON1, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_DROPDOWN, 0, 0, 0}, {1, IDC_BUTTON2, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_DROPDOWN, 0, 0, 0}, {2, IDC_BUTTON3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, }; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; HACCEL hAccelTable; // グローバル ストリングを初期化します LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_SAMPLE, szWindowClass, MAX_LOADSTRING); MyRegisterClass( hInstance ); // アプリケーションの初期化を行います: if( !InitInstance( hInstance, nCmdShow ) ) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SAMPLE); // メイン メッセージ ループ: while( GetMessage(&msg, NULL, 0, 0) ) { if( !TranslateAccelerator (msg.hwnd, hAccelTable, &msg) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } return msg.wParam; } ATOM MyRegisterClass( HINSTANCE hInstance ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SAMPLE); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCSTR)IDC_SAMPLE; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx( &wcex ); } BOOL InitInstance( HINSTANCE hInstance, int nCmdShow ) { HWND hWnd; hInst = hInstance; // グローバル変数にインスタンス ハンドルを保存します hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if( !hWnd ) { return FALSE; } ShowWindow( hWnd, nCmdShow ); UpdateWindow( hWnd ); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; static char szBuf[256]=""; UINT nBmpHandle; LPNMHDR lpnm; LPNMTOOLBAR lpnmTB; switch( message ) { case WM_CREATE: // ツールバーを作る hToolBar1 = ToolBarCreate( hWnd ); // ビットマップのハンドルを取得する nBmpHandle = (UINT)LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP1) ); // ツールバーにグラフィックの挿入 ToolBarAddBitmapEx( hToolBar1, NUMTBB1, tbb1, NULL, nBmpHandle ); // ツールバーにボタンを挿入する ToolBarAddButtonsEx( hToolBar1, NUMTBB1, tbb1, TRUE ); break; case WM_PAINT: DispText( hWnd, szBuf ); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); switch( wmId ) { case IDC_BUTTON1: LoadString(hInst, IDC_BUTTON1, (LPSTR)&szBuf, sizeof(szBuf)); break; case IDC_BUTTON2: LoadString(hInst, IDC_BUTTON2, (LPSTR)&szBuf, sizeof(szBuf)); break; case IDC_BUTTON3: LoadString(hInst, IDC_BUTTON3, (LPSTR)&szBuf, sizeof(szBuf)); break; case ID_BLACK1: lstrcpy( szBuf, "黒1" );break; case ID_BLACK2: lstrcpy( szBuf, "2番目黒" );break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } InvalidateRect(hWnd, NULL, TRUE);//クライアント全体を再描画する命令 break; case WM_SIZE: MoveWindow(hToolBar1, 0, 0, LOWORD(lParam), TOOL1_HEIGHT, TRUE); break; case WM_NOTIFY: switch (((LPNMHDR)lParam)->code) { case TBN_DROPDOWN: lpnm = ((LPNMHDR)lParam); lpnmTB = ((LPNMTOOLBAR)lParam); switch(lpnmTB->iItem) { case IDC_BUTTON1: ToolBarButtonDropDown(hWnd, lpnm, lpnmTB, 0); break; case IDC_BUTTON2: ToolBarButtonDropDown(hWnd, lpnm, lpnmTB, 1); break; } break; } break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } HWND ToolBarCreate(HWND hWnd) { HWND hTool; InitCommonControls(); hTool = CreateWindowEx( WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_LIST, 0,0,0,0, hWnd, NULL, hInst, NULL); SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); SendMessage(hTool, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS); return hTool; } void ToolBarAddBitmapEx(HWND hToolBar, int nBotton, TBBUTTON* tbb, HINSTANCE hInst, UINT nID) { int i, index; TBADDBITMAP tbAddBmp; tbAddBmp.hInst = hInst; tbAddBmp.nID = nID; index = SendMessage(hToolBar, TB_ADDBITMAP, (WPARAM)nBotton, (LPARAM)&tbAddBmp); for( i=0; i<nBotton; i++ ) tbb[i].iBitmap += index; } void ToolBarAddButtonsEx(HWND hToolBar, int nBotton, TBBUTTON* tbb, BOOL bString) { int i; char szBuf[256]; int nAddBotton[20]; if (bString == TRUE) { for( i=0; i<nBotton; i++ ) { LoadString(hInst, tbb[i].idCommand, (LPSTR)&szBuf, sizeof(szBuf)); nAddBotton[i] = (int)SendMessage(hToolBar, TB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuf); tbb[i].iString = nAddBotton[i]; } } SendMessage(hToolBar, TB_ADDBUTTONS, (WPARAM)nBotton, (LPARAM)tbb); } void ToolBarAddButtonSpaceEx(HWND hToolBar) { TBBUTTON tbSpace = {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}; SendMessage(hToolBar, TB_ADDBUTTONS, 1, (LPARAM)&tbSpace); } void ToolBarButtonDropDown(HWND hWnd, LPNMHDR lpnm, LPNMTOOLBAR lpnmTB, int nIndex) { RECT rc; TPMPARAMS tpm; HMENU hPopupMenu = NULL; HMENU hMenuLoaded; BOOL bRet = FALSE; SendMessage(lpnmTB->hdr.hwndFrom, TB_GETRECT, (WPARAM)lpnmTB->iItem, (LPARAM)&rc); MapWindowPoints(lpnmTB->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&rc, 2); tpm.cbSize = sizeof(TPMPARAMS); tpm.rcExclude = rc; hMenuLoaded = LoadMenu( hInst, MAKEINTRESOURCE(IDR_DROPDOWN)); hPopupMenu = GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_DROPDOWN)), nIndex); TrackPopupMenuEx(hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL, rc.left, rc.bottom, hWnd, &tpm); DestroyMenu(hMenuLoaded); } void DispText(HWND hWnd, char* pszBuf) { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint ( hWnd, &ps ); TextOut( hdc, 25, 50, (LPSTR)pszBuf, lstrlen(pszBuf) ); EndPaint( hWnd, &ps ); }
〜プログラムの解説〜 1.どうやってツールチップのボタンの右に▼をつける? ツールチップのボタンの右に▼をつけるには,スタイルを拡張しなければいけません. 拡張するには,ツールバーに拡張するメッセージを送ってやらないといけません. HWND ToolBarCreate(HWND hWnd) { HWND hTool; InitCommonControls(); hTool = CreateWindowEx( WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_LIST, 0,0,0,0, hWnd, NULL, hInst, NULL); SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); SendMessage(hTool, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS); return hTool; } なんと, SendMessage(hTool, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS); 一行だけ書いてやれば,拡張できます. 他は,何もいらわなくても,ビルドしてやればちゃんとボタンに▼印がついていることがわかります. 2.メニューのボタンが押されたら,どうやって表示する? まず,ドロップダウンして出てくるメニューボタンのIDはなんだったか確認します. [黒]-[黒1]のID:ID_BLACK1 [黒]-[2番目黒]のID:ID_BLACK2 でしたね. メニューやツールバーのボタンが押されたら,どんなメッセージが来るんでしたか? そう.いつもどうりWM_COMMANDが飛んでくるんですね. ここまで言えば,いつもどうりswitch文でID_BLACK1とID_BLACK2をひろってやればいいわけです. case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); switch( wmId ) { case IDC_BUTTON1: LoadString(hInst, IDC_BUTTON1, (LPSTR)&szBuf, sizeof(szBuf)); break; case IDC_BUTTON2: LoadString(hInst, IDC_BUTTON2, (LPSTR)&szBuf, sizeof(szBuf)); break; case IDC_BUTTON3: LoadString(hInst, IDC_BUTTON3, (LPSTR)&szBuf, sizeof(szBuf)); break; case ID_BLACK1: lstrcpy( szBuf, "黒1" );break; case ID_BLACK2: lstrcpy( szBuf, "2番目黒" );break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } InvalidateRect(hWnd, NULL, TRUE);//クライアント全体を再描画する命令 break; szBufに文字列を代入するのに, lstrcpy( szBuf, "黒1" ); としています. LoadString(hInst, ID_BLACK1, (LPSTR)&szBuf, sizeof(szBuf)); とするとうまくいきませんでした. LoadStringを使って,IDからキャプションを取得できるのは,StringTableで定義されたIDだけなんですかね? 原因はわかりませんでした. 今日は,研究室さぼって親戚の家にPCのメンテナンスに行ってきました. 説明書を見ながら無線LANの設定をしてきたわけですが,ありゃまったくの初心者には少し難しいですね.. 誰にでもできるように説明書を作るって難しいんでしょうね.![]()
![]()
![]()
------------------------------------------------------------------------------------------------
当ページの一部または全部を転載、複写、複製することを禁じます。
また,当サイトを利用した結果に関するトラブル等は、一切関与いたしませんのでご容赦下さい。
Update 04/03/27 By 松本義弘
------------------------------------------------------------------------------------------------