メニュー項目を使用禁止にする

メニューの項目を状況に応じて使用禁止にしたり、ふたたび使用できるようにするにはどうすればよいだろうか?

ここでは2通りの方法を説明するが、まず最初に2通りの方法に共通する準備をしておく。

適当な名前のSDIプロジェクトを作成し、「Resource View」からメニューリソースを開く。 「ファイル(F)」「編集(E)」「表示(V)」「ヘルプ(H)」の4つのメニュー項目があるはずなので、 新たに「ウィンドウ(W)」という項目を追加する。
追加したら、その項目の下に「最大化(X)」「元のサイズに戻す(R)」という2つのサブメニューを追加する。 項目のプロパティで、それぞれのIDを「ID_WINDOW_MAXIMIZE」「ID_WINDOW_RESTORE」とする。
さて、メニューリソースの編集を終えたら、 実際にこれらのメニューを選択したときにウィンドウを最大化表示させたり元のサイズに戻したりする処理を入れる。 「表示」−「ClassWizard」メニューを選択してClassWizardダイアログを開き、クラス名を「CMainFrame」にする。 オブジェクトID「ID_WINDOW_MAXIMIZE」のCOMMANDメッセージを選択して「関数の追加」をおこなう。 同様にオブジェクトID「ID_WINDOW_RESTORE」でもCOMMANDメッセージのハンドラ関数を追加する。 これでメッセージハンドラであるCMainFrame::OnWindowMaximize関数とCMainFrame::OnWindowRestore関数が作成されるので、 CMainFrameクラスのソースを開いて次のように編集する。

void CMainFrame::OnWindowMaximize() 
{
	// TODO: この位置にコマンド ハンドラ用のコードを追加してください
	ShowWindow(SW_SHOWMAXIMIZED);
}

void CMainFrame::OnWindowRestore() 
{
	// TODO: この位置にコマンド ハンドラ用のコードを追加してください
	ShowWindow(SW_RESTORE);
}
これで、それぞれのメニューを選択することでウィンドウが最大化表示されたり元のサイズに戻ったりするようになる。

さて、ここからが本題になる。作成した2つのメニューであるが、 ウィンドウが最大化表示されているときに「最大化」メニューを選択しても意味がないし、 元のサイズに戻したのに「元のサイズに戻す」メニューを選択する意味もない。 ならば意味のないメニューは選択できないようにするほうが親切だし、自然だろう。 ということで、以下にその方法を2通り説明したい。


方法1:UPDATE_COMMAND_UIメッセージハンドラを使う
メニューがプルダウンされたときに発行されるこのメッセージを取得することで、メニュー項目の表示などを変更することができる。
ClassWizardダイアログを開き、クラス名を「CMainFrame」にする。 オブジェクトID「ID_WINDOW_MAXIMIZE」と「ID_WINDOW_RESTORE」のUPDATE_COMMAND_UIメッセージのハンドラ関数を追加する。 追加をおこなったら、CMainFrameクラスのソースを開いて次のように編集する。
// ID_WINDOW_MAXIMIZEのUPDATE_COMMAND_UIメッセージハンドラ
void CMainFrame::OnUpdateWindowMaximize(CCmdUI* pCmdUI) 
{
	// TODO: この位置に command update UI ハンドラ用のコードを追加してください
	if( GetStyle() & WS_MAXIMIZE )
		pCmdUI->Enable(FALSE);
	else
		pCmdUI->Enable(TRUE);
}

// ID_WINDOW_RESTOREのUPDATE_COMMAND_UIメッセージハンドラ
void CMainFrame::OnUpdateWindowRestore(CCmdUI* pCmdUI) 
{
	// TODO: この位置に command update UI ハンドラ用のコードを追加してください
	if( GetStyle() & (WS_MAXIMIZE | WS_MINIMIZE) )
		pCmdUI->Enable(TRUE);
	else
		pCmdUI->Enable(FALSE);
}
この方法を使う利点は、ツールバーにID_WINDOW_MAXIMIZEやID_WINDOW_RESTOREコマンドのボタンを作成した場合、 このボタンもメニューと同様に使用禁止になったり解除されたりすることである。


方法2:CMenu::EnableMenuItem関数を使う
方法1ではメニューがプルダウンされたときに現在のプログラムの状態を取得してメニューの使用禁止を設定しているが、 方法2では状態が変更されたときにメニューの使用禁止を設定するようにしている。 ここではウィンドウのサイズが変更されたときのメッセージハンドラであるCMainFrame::OnSize関数をオーバーライドし、 以下のようにソースを変更する。
このようにメニューの状態を変更する場合には、CFrameWndクラスのメンバ変数であるm_bAutoMenuEnableをFALSEにしておく必要がある。
// CMainFrameクラスのコンストラクタ
CMainFrame::CMainFrame()
{
	// TODO: この位置にメンバの初期化処理コードを追加してください。
	m_bAutoMenuEnable = FALSE;
}

void CMainFrame::OnSize(UINT nType, int cx, int cy) 
{
	CFrameWnd::OnSize(nType, cx, cy);
	
	// TODO: この位置にメッセージ ハンドラ用のコードを追加してください
	switch(nType)
	{
	case SIZE_MAXIMIZED:
		GetMenu()->EnableMenuItem(ID_WINDOW_MAXIMIZE, MF_GRAYED | MF_BYCOMMAND);
		GetMenu()->EnableMenuItem(ID_WINDOW_RESTORE, MF_ENABLED | MF_BYCOMMAND);
		break;
	case SIZE_RESTORED:
		GetMenu()->EnableMenuItem(ID_WINDOW_MAXIMIZE, MF_ENABLED | MF_BYCOMMAND);
		GetMenu()->EnableMenuItem(ID_WINDOW_RESTORE, MF_GRAYED | MF_BYCOMMAND);
		break;
	}
}

目次へ