メニューの削除


メニュー項目を消す

メニューの項目をプログラムから動的に削除することも可能です
これを行うには DeleteMenu() 関数を使います

BOOL DeleteMenu(HMENU hMenu , UINT uPosition , UINT uFlags);

hMenu には、メニュー項目を持つメニューのハンドルを
uPosition は、メニュー項目の ID またはインデックスを指定します
uFrags は uPosition の値の意味を表す定数を指定します
MF_BYCOMMAND であれば ID、MF_BYPOSITION であれば位置を表します
関数が成功すると 0 以外、失敗すると 0 が返ります

まったく同じような関数で RemoveMenu() 関数もあります

BOOL RemoveMenu(HMENU hMenu , UINT uPosition , UINT uFlags);

引数も戻り値も DeleteMenu() 関数とまったく同じです
しかし、この関数はメニュー項目がドロップダウンメニューやサブメニューを開く場合
それらのメニューやそのハンドルは削除しません

あらかじめ GetSubMenu() 関数でサブメニューのハンドルを取得しておけば
メニューを再利用することが可能です

これらの関数で、メニューに変化を与えた場合
メニューは Windows によって再描画されるまで変化しません
メニューの再描画は DrawMenuBar() 関数で明示的に行えます

BOOL DrawMenuBar(HWND hWnd);

hWnd には、メニューバーを持つウィンドウのハンドルを指定します
メニューのハンドルではなく、ウィンドウのハンドルなので注意してください
関数が成功すると 0 以外、失敗すると 0 が返ります
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_COMMAND:
		DeleteMenu(GetMenu(hwnd) , LOWORD(wp) , MF_BYCOMMAND);
		DrawMenuBar(hwnd);
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= TEXT("KITTY");
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
選択されたメニュー項目を削除するというプログラムです
メニューは、KITTY と言う名前のメニューであればどのようなものでもかまいません
適当に、リソーススクリプトで定義されているものとします


メニューの解放

通常は、ウィンドウに割り当てられているメニューを解放する必要はありません
Windows は、プログラムがウィンドウを破棄する時に自動的にメニューを破壊します

しかし、ウィンドウに割り当てられていないメニューは別です
その場合は、メモリから明示的に解放する必要があるのです

メニューの解放は DestroyMenu() 関数で行います

BOOL DestroyMenu(HMENU hMenu);

hMenu には、解放するメニューのハンドルを指定します
関数が成功すると 0 以外、失敗すると 0 が返ります
//リソーススクリプト
KITTY MENU {
	POPUP "Kitty on your lap" {
		MENUITEM "レナ" , 40001
		MENUITEM "ユキ" , 40002
		MENUITEM "ミミ" , 40003
	}
}

TARUTO MENU {
	POPUP "Magical nyan nyan TARUTO" {
		MENUITEM "たると" , 40004
		MENUITEM "シャルロッテ" , 40005
		MENUITEM "ちとせ" , 40006
		MENUITEM "柿ピー" , 40007
	}
}
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	static HINSTANCE hInstance;
	static HMENU kitty , taruto;

	switch (msg) {
	case WM_DESTROY:
		SetMenu(hwnd , NULL);
		DestroyMenu(kitty);
		DestroyMenu(taruto);
		
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hInstance = ((LPCREATESTRUCT)(lp))->hInstance;
		kitty = LoadMenu(hInstance , TEXT("KITTY"));
		taruto = LoadMenu(hInstance , TEXT("TARUTO"));
		return 0;
	case WM_LBUTTONDOWN:
		SetMenu(hwnd , kitty);
		return 0;
	case WM_RBUTTONDOWN:
		SetMenu(hwnd , taruto);
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
SetMenu() 関数の第二引数を NULL にするとウィンドウのメニューは解除されます
また、メニューが設定されている状態で呼び出してもメニューは変更されます
しかし、この時メニューはメモリから開放されることはありません

これはマウスの右、左クリックでメニューが入れ替わるプログラムですが
入れ替わる時、以前のメニューはメモリに残されています
プログラムが終了する時、ウィンドウに設定されていないメニューは破棄されません
そこで、DestroyMenu() によってメモリからメニューを解放しています


DeleteMenu()

BOOL DeleteMenu(HMENU hMenu , UINT uPosition , UINT uFlags);

メニューからメニュー項目を削除します
項目がサブメニューを開く場合、そのハンドルも削除します

hMenu - 項目を持つメニューのハンドルを指定します
uPosition - メニューの ID またはインデックスを指定します
uFlags - uPosition の意味を表す定数を指定します

戻り値 - 成功すれば 0 以外、失敗すれば 0

uFlags には以下の定数のいずれかを指定します

定数解説
MF_BYCOMMAND uPosition パラメータがメニュー項目の ID を指定していることを示します
デフォルトです
MF_BYPOSITION uPosition パラメータがメニュー項目の位置を指定していることを示します
位置は、0 からの相対位置で指定します

RemoveMenu()

BOOL RemoveMenu(HMENU hMenu , UINT uPosition , UINT uFlags);

メニューからメニュー項目を削除します
項目がドロップダウンメニューやサブメニューを開く場合、それらのメニューやそのハンドルは削除しません

hMenu - 項目を持つメニューのハンドルを指定します
uPosition - メニューの ID またはインデックスを指定します
uFlags - uPosition の意味を表す定数を指定します

戻り値 - 成功すれば 0 以外、失敗すれば 0

uFlags には以下の定数のいずれかを指定します

定数解説
MF_BYCOMMAND uPosition パラメータがメニュー項目の ID を指定していることを示します
デフォルトです
MF_BYPOSITION uPosition パラメータがメニュー項目の位置を指定していることを示します
位置は、0 からの相対位置で指定します

DrawMenuBar()

BOOL DrawMenuBar(HWND hWnd);

メニューバーを再描画します

hWnd - 再描画するメニューを持つウィンドウのハンドルを指定します

戻り値 - 成功すると 0 以外、失敗すると 0

DestroyMenu()

BOOL DestroyMenu(HMENU hMenu);

指定したメニューをメモリから破棄します

hMenu - 解放するメニューのハンドルを指定します

戻り値 - 成功すると 0 以外、失敗すると 0



前のページへ戻る次のページへ