EternalWindows
ツールバー / ドロップダウンボタン

今回はツールバーのボタンをドロップダウンボタンに設定し、ポップアップメニューが表示されるようにします。 また、ボタンの状態を変更する方法も取り上げます。

#include <windows.h>
#include <commctrl.h>

#define ID_TOOLBAR 100
#define ID_OPEN    200
#define ID_HELP    300
#define ID_SHOW    400
#define ID_ENABLE  500

#pragma comment (lib, "comctl32.lib")

void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND  hwndToolbar = NULL;
	static HMENU hmenuPopup = NULL;

	switch (uMsg) {
		
	case WM_CREATE: {
		TBBUTTON tbButton[] = {
			{STD_FILEOPEN, ID_OPEN, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
			{0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0}, 0, 0},
			{STD_HELP, ID_HELP, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_DROPDOWN, {0}, 0, 0}
		};
		int                  nCount = sizeof(tbButton) / sizeof(tbButton[0]);
		DWORD                dwStyle;
		INITCOMMONCONTROLSEX ic;
		
		ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
		ic.dwICC  = ICC_BAR_CLASSES;
		InitCommonControlsEx(&ic);

		hwndToolbar = CreateToolbarEx(hwnd, WS_CHILD | WS_VISIBLE, ID_TOOLBAR, 0, HINST_COMMCTRL, IDB_STD_SMALL_COLOR, tbButton, nCount, 0, 0, 0, 0, sizeof(TBBUTTON));
		
		dwStyle = (DWORD)SendMessage(hwndToolbar, TB_GETSTYLE, 0, 0) | TBSTYLE_FLAT;
		SendMessage(hwndToolbar, TB_SETSTYLE, 0, (LPARAM)dwStyle);
		SendMessage(hwndToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);

		hmenuPopup = CreatePopupMenu();
		InitializeMenuItem(hmenuPopup, TEXT("表示/非表示"), ID_SHOW);
		InitializeMenuItem(hmenuPopup, TEXT("有効/無効"), ID_ENABLE);	

		return 0;
	}
	
	case WM_NOTIFY: {
		if (((LPNMHDR)lParam)->code == TBN_DROPDOWN) {
			POINT pt;

			GetCursorPos(&pt);
			TrackPopupMenu(hmenuPopup, 0, pt.x, pt.y, 0, hwnd, NULL);
		}
		return 0;
	}

	case WM_COMMAND:
		if (LOWORD(wParam) == ID_SHOW) {
			DWORD dwState;

			dwState = (DWORD)SendMessage(hwndToolbar, TB_GETSTATE, ID_OPEN, 0) ^ TBSTATE_HIDDEN;
			SendMessage(hwndToolbar, TB_SETSTATE, ID_OPEN, dwState);
		}
		else if (LOWORD(wParam) == ID_ENABLE) {
			DWORD dwState;

			dwState = (DWORD)SendMessage(hwndToolbar, TB_GETSTATE, ID_OPEN, 0) ^ TBSTATE_ENABLED;
			SendMessage(hwndToolbar, TB_SETSTATE, ID_OPEN, dwState);
		}
		else
			;
		return 0;
	
	case WM_SIZE:
		MoveWindow(hwndToolbar, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId)
{
	MENUITEMINFO mii;
	
	mii.cbSize     = sizeof(MENUITEMINFO);
	mii.fMask      = MIIM_ID | MIIM_TYPE;
	mii.fType      = MFT_STRING;
	mii.wID        = nId;
	mii.dwTypeData = lpszItemName;

	InsertMenuItem(hmenu, nId, FALSE, &mii);
}

ツールバーのボタンをドロップダウンボタンにするには、ボタンのスタイルにBTNS_DROPDOWNを指定します。 今回はこの他にTB_GETSTYLEとTB_SETSTYLEを使用してTBSTYLE_FLATを指定していますが、 これはツールバーをフラットにする仕組みです。 フラットツールバーならば、TB_SETEXTENDEDSTYLEにTBSTYLE_EX_DRAWDDARROWSを指定することでボタンの横に矢印を表示できるため、 そのボタンがドロップダウンボタンであるとすぐに分かるようになります。 また、フラットツールバーは、セパレータを縦線として表示します。 セパレータを表示する場合は、TBBUTTON構造体の4番目のメンバにTBSTYLE_SEPを指定します。 CreateToolbarExに直接TBSTYLE_FLATを指定してもフラットツールバーにはならない点に注意してください。

ドロップダウンボタンの矢印が押された場合は、通知コードがTBN_DROPDOWNであるWM_NOTIFYが送られます。 ここではTrackPopupMenuでポップアップメニューを表示し、 項目が選択された場合はWM_COMMANDが送られることになります。 WM_COMMANDの処理は次のようになっています。

if (LOWORD(wParam) == ID_SHOW) {
	DWORD dwState;

	dwState = (DWORD)SendMessage(hwndToolbar, TB_GETSTATE, ID_OPEN, 0) ^ TBSTATE_HIDDEN;
	SendMessage(hwndToolbar, TB_SETSTATE, ID_OPEN, dwState);
}
else if (LOWORD(wParam) == ID_ENABLE) {
	DWORD dwState;

	dwState = (DWORD)SendMessage(hwndToolbar, TB_GETSTATE, ID_OPEN, 0) ^ TBSTATE_ENABLED;
	SendMessage(hwndToolbar, TB_SETSTATE, ID_OPEN, dwState);
}

ID_SHOWの場合はボタンの表示/非表示を切り替え、ID_ENABLEの場合はボタンの有効/無効を切り替えます。 表示や有効といったボタンの状態はTB_GETSTATEで取得できるため、 これと特定の状態の排他的論理和をTB_SETSTATEに指定すればよいことになります。


戻る