none
ポップアップメニューを無効にした時、無効にしたメニューが選択状態にならないようにしたい

    質問

  • いつもお世話になっております。arubi-momoと申します。

    開発環境はWindows7 64bit、Visual Studio Professional 2010 MFCを使用しています。

    今、右クリックで表示するポップアップメニューを、ある条件の時に無効になるようにしています。

    CMenu *pMenu = menu.GetSubMenu(0);
    pMenu->EnableMenuItem(ID, MF_GRAYED | MF_BYPOSITION);

    このソースコードできちんと無効になり、メニュー項目もグレーアウトされるので、動作的には何の問題もないのですが、マウスをそのメニュー項目の上に持っていくと、ほかの項目と同様に選択されているかのように色が変わる表示になります。ユーザーからは、無効のメニューがこのように色が変わることが違和感があるということで、できればOfficeなどと同じように、無効の項目は選択状態にもならないような表示にしたいという要望がありました。

    MFCのシングルドキュメントの画面のメニューバーでは、無効のメニューはマウスを乗せても選択状態にならないのですが、ポップアップメニューだと選択状態になってしまいます。

    色々調べてはみたのですが、結論としては不可能なのではないか。。。と思っております。

    もし何かやり方があるのであれば、ご教示いただければと思います。

    何卒、よろしくお願いいたします。

    2017年3月24日 4:51

回答

  • ビジュアルスタイルを有効にするとメニューの選択状態が目立たなくなりますが、どうでしょうか。
    ビジュアルスタイルONのとき、メニュー項目の無効状態は下記のような表示になりました。

    プロジェクトでビジュアルスタイルを有効にするには、

    #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

    上記のコードをプログラムのどこかに挿入します。

    ビジュアルスタイル以外の方法でメニュー項目の色を変える方法として、メニューのオーナードローがあります。

    メニュー項目に、MF_OWNERDRAW フラグを設定すると、メニューの表示の際、オーナーウィンドウで WM_DRAWITEM が呼ばれるようになります。そこでメニュー項目を独自に描画することができます。

    MFC ではないのですが、以下のサンプルプログラムが参考になるかもしれません。

    https://github.com/kenjinote/PopupMenuOwnerDraw/blob/master/Source.cpp#L8-L70

    追伸:

    CMFCPopupMenu を使うと、ポップアップメニューの無効状態の項目にマウスが乗っても、背景の色が変わりませんでした。ただ、EnableMenuItem関数で無効に設定しても、表示状態は無効になりますが、項目をクリックして選択してしまえるようになってしまったので、無効に設定するには ON_UPDATE_COMMAND_UI を使って行う必要があるようです。以下試したサンプルプログラムです。

    BEGIN_MESSAGE_MAP(CPopupMenuDlg, CDialogEx)
    	ON_WM_CONTEXTMENU()
    	ON_UPDATE_COMMAND_UI(ID_POPUP_CCC, &CPopupMenuDlg::OnUpdatePopupCcc)
    END_MESSAGE_MAP()
    
    void CPopupMenuDlg::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
    {
    	CMenu menu;
    	menu.LoadMenu(IDR_MENU1);
    	CMenu *pSubMenu = menu.GetSubMenu(0);
    	CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu;
    	pPopupMenu->Create (this, point.x, point.y, pSubMenu->Detach(), TRUE, TRUE);
    	pPopupMenu->UpdateShadow();
    }
    
    void CPopupMenuDlg::OnUpdatePopupCcc(CCmdUI *pCmdUI)
    {
    	pCmdUI->Enable(FALSE); // 無効に設定
    }
    2017年3月24日 7:15
  • IE11のメニュー、及びコンテキストメニューも同様の動作になりますので、これはWindows7においては標準的な動作と言えます。
    これを変更するのは不可能ではありませんが、MFCやWindows OSの基本動作を変更するのは、比較的高コストになります。
    2017年3月24日 8:42
  • 非MFC Win7(32bits),Win8(64bits)で試してみました。結果はnotepad.exeと同様でした。

    すなわち、メニューバーのプルダウンメニュー、コンテキストメニュー共に、マウスポインターがメニュー項目の上にある時、MF_GRAYEDかMF_DISABLEDなら灰色の選択色に、そうでなければ青色の選択色になりました。

    このような動作で良ければ、MFCだとkenjinoteさんの追伸部分のようにOnUpdateCommandUIを使うように思います。


    ちなみに、Win7で視覚効果の無効にした場合や、Win8で256色にした場合や、WinXPだとMF_GRAYED,MF_DISABLEDでも青色の選択色でした。
    2017年3月26日 8:09

すべての返信

  • ビジュアルスタイルを有効にするとメニューの選択状態が目立たなくなりますが、どうでしょうか。
    ビジュアルスタイルONのとき、メニュー項目の無効状態は下記のような表示になりました。

    プロジェクトでビジュアルスタイルを有効にするには、

    #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

    上記のコードをプログラムのどこかに挿入します。

    ビジュアルスタイル以外の方法でメニュー項目の色を変える方法として、メニューのオーナードローがあります。

    メニュー項目に、MF_OWNERDRAW フラグを設定すると、メニューの表示の際、オーナーウィンドウで WM_DRAWITEM が呼ばれるようになります。そこでメニュー項目を独自に描画することができます。

    MFC ではないのですが、以下のサンプルプログラムが参考になるかもしれません。

    https://github.com/kenjinote/PopupMenuOwnerDraw/blob/master/Source.cpp#L8-L70

    追伸:

    CMFCPopupMenu を使うと、ポップアップメニューの無効状態の項目にマウスが乗っても、背景の色が変わりませんでした。ただ、EnableMenuItem関数で無効に設定しても、表示状態は無効になりますが、項目をクリックして選択してしまえるようになってしまったので、無効に設定するには ON_UPDATE_COMMAND_UI を使って行う必要があるようです。以下試したサンプルプログラムです。

    BEGIN_MESSAGE_MAP(CPopupMenuDlg, CDialogEx)
    	ON_WM_CONTEXTMENU()
    	ON_UPDATE_COMMAND_UI(ID_POPUP_CCC, &CPopupMenuDlg::OnUpdatePopupCcc)
    END_MESSAGE_MAP()
    
    void CPopupMenuDlg::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
    {
    	CMenu menu;
    	menu.LoadMenu(IDR_MENU1);
    	CMenu *pSubMenu = menu.GetSubMenu(0);
    	CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu;
    	pPopupMenu->Create (this, point.x, point.y, pSubMenu->Detach(), TRUE, TRUE);
    	pPopupMenu->UpdateShadow();
    }
    
    void CPopupMenuDlg::OnUpdatePopupCcc(CCmdUI *pCmdUI)
    {
    	pCmdUI->Enable(FALSE); // 無効に設定
    }
    2017年3月24日 7:15
  • IE11のメニュー、及びコンテキストメニューも同様の動作になりますので、これはWindows7においては標準的な動作と言えます。
    これを変更するのは不可能ではありませんが、MFCやWindows OSの基本動作を変更するのは、比較的高コストになります。
    2017年3月24日 8:42
  • 非MFC Win7(32bits),Win8(64bits)で試してみました。結果はnotepad.exeと同様でした。

    すなわち、メニューバーのプルダウンメニュー、コンテキストメニュー共に、マウスポインターがメニュー項目の上にある時、MF_GRAYEDかMF_DISABLEDなら灰色の選択色に、そうでなければ青色の選択色になりました。

    このような動作で良ければ、MFCだとkenjinoteさんの追伸部分のようにOnUpdateCommandUIを使うように思います。


    ちなみに、Win7で視覚効果の無効にした場合や、Win8で256色にした場合や、WinXPだとMF_GRAYED,MF_DISABLEDでも青色の選択色でした。
    2017年3月26日 8:09
  • kenjinoteさま、仲澤@失業者さま、snaoさま

    いつもお世話になっております。arubi-momoです。

    ご回答いただきましてありがとうございます!緊急の修正が入り、お礼が遅くなってしまいました。申し訳ありません。

    >MF_GRAYEDかMF_DISABLEDなら灰色の選択色に、そうでなければ青色の選択色

    これがOSの標準動作なのですね。Officeのことばかり気を取られていて、OSの動作に注目しておりませんでした。

    kenjinoteさまにご教示いただいた方法(CMFCPopupMenuを使用)ですと、ユーザーの要望通りの動作ができそうですが、確かに色々と修正が生じて高コストになりそうなので、まずはユーザー側と相談をしてみたいと思います。

    どうしてものご要望だった場合には、kenjinoteさまにご教示いただいた方法を使わせていただきます!

    いつもご指導いただきましてありがとうございます。今後ともよろしくお願いいたします。

    2017年3月27日 6:17