<Previous> <Next> <SDK Top> <Top>
3章.10節.ツールバーのボタンをドロップダウンさせてみよう
SDK/3-10.h2.gif)
今回は,ツールバーのボタンをドロップダウンと呼ばれるものにしてみましょう.
「ドロップダウン」とは,どんなものか?
それは図を見てもらったほうが早いですね.
クリックすると,メニューがぐいーんと下に現れます.
ボタンを3つ作ります.よって,IDは3つです.
(IDの作り方を知らない方は,「別章.2節.ストリングテーブルを編集してみよう」を先に読んでください.)
| ID | キャプション |
| IDC_BUTTON1 | 黒 |
| IDC_BUTTON2 | 茶 |
| IDC_BUTTON3 | 緑 |
としましょう.
次に,ドロップダウンで表示させる項目を作ります.
それはリソースビューで新しくメニューバーを追加します!
今回,IDはIDR_DROPDOWNとします.
そして,下のように変更してみてください.
SDK/3-10.h3.gif)
SDK/3-10.h4.gif)
今回のポイントは,
1.どうやってツールチップのボタンをドロップダウンさせる?
というところですね.
では,プログラムを見ましょう.
#include "stdafx.h"
#include <commctrl.h>
#include "resource.h"
#pragma comment(lib, "comctl32.lib")
#define MAX_LOADSTRING 100
#define IDC_RICHEDIT (101)
// グローバル変数:
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;
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;
case IDC_BUTTON3:
ToolBarButtonDropDown(hWnd, lpnm, lpnmTB, 2);
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);
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.どうやってツールチップのボタンをドロップダウンさせる?
まず,黒と茶のボタンをドロップダウンさせるために,TBSTYLE_DROPDOWNというスタイルを追加します.
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},
};
追加しました.
これで,ボタンがクリックされたらツールバーからドロップダウンされたよってことを僕たちに教えてくれます.
それは前節と同じ,WM_NOTIFY メッセージなんですね.
だから,僕たちはWM_NOTIFYに対応するプロシージャーを書かないといけません.
では書きましょう.
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;
こんな感じになってます.
さらにドロップダウンなのか,前節のようにツールチップ表示なのかは,lParam->codeにあるんですね.
それが,TBN_DROPDOWN(ドロップダウン)であれば,ドロップダウンされたということです.
そしてさらに,どのボタンが押されたのかをswitch文で分岐しています!
次にToolBarButtonDropDown関数ですね.
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);
}
なんじゃこりゃぁ!わけわかんねーと思われるでしょう.
実は,著者自身もわけわかりません.msdnをほぼ引用させてもらいました.
ここで重要なのは,
LoadMenu(API)で,IDR_DROPDOWN(初めにつくったメニューバー)を読みこんで,
GetSubMenu(API)で,メニューボタンからポップアップされたウィンドウ(黒1とか2番目黒とか書いてたやつ)を読んで,
TrackPopupMenuExで表示しているということですね.
TrackPopupMenuExで表示されるウィンドウは「ショートカットメニュー」と呼ばれ,
右クリックして出てくるあのウィンドウと同じですね.
詳しく知りたい人は,一つ一つAPIを調べていってください.
今日は,特に面白いことがなかったなぁ..
というか,みんな就活大変そうだ!!がんばれ!!
俺だけ進学かよ...つまらんなぁー...
Menu/Top.png)
------------------------------------------------------------------------------------------------
当ページの一部または全部を転載、複写、複製することを禁じます。
また,当サイトを利用した結果に関するトラブル等は、一切関与いたしませんのでご容赦下さい。
Update 04/03/26 By 松本義弘
------------------------------------------------------------------------------------------------