none
CMFCMenuBarとアクセラレータ RRS feed

  • 質問

  • VisualC++ 2008 SP1で、メニューのアクセラレータが表示もされず、動作もしません。

    次の手順で簡単なアプリケーションを作ってみました。

    1. アプリケーションウィザードの「ユーザーインターフェイス機能」のプロパティページで、「メニューバーとツールバーを使用する」のラジオボタンをチェックして作成。
    2. IDR_MAINFRAMEメニューリソースの適当な場所に、「テスト\tCtrl+T」などをCaptionとしてID_TESTを作成。
    3. IDR_MAINFRAMEアクセラレータリソースに、ID_TESTをCtrl+Tとなるように設定。
    4. このメニューのメッセージハンドラを作成して、メッセージボックスを表示するなどの適当なコードを記述。

    以上をビルドして実行しても、メニューにはアクセラレータが表示されず、実際にCtrlキーを押したままTをタイプしても何も起こりません。

    CMainFrameにCMFCMenuBarクラスのメンバーができていて、これがメニューを表示しているようなのですが、この場合アクセラレータ実装方法に特別な手順が必要なのでしょうか?ヘルプなどいろいろ調べてみたのですが分かりませんでした。

    どなたかご存知でしたら教えていただけると幸いです。

    2009年2月2日 4:42

回答

  • こちらの環境でも再現しました。
    バグってますね、設計思想が致命的に。

    どういうつもりか分かりませんが、CKeyboardManager というやつが終了時にアクセラレータをレジストリに保存しています。 一度アクセラレータテーブルが保存されてしまうとそれを一生使い続けることになってしまうため、新しい項目を追加しても当然ながら無視されてしまいます。

    JANEQUIN の発言:
    さて、この問題どうしたらいいのでしょう?

    根本的な解決ではないと思いますが、自前でアクセラレータを消去してしまえば、不必要なセーブを防ぐことが出来ます。

    void CMainFrame::OnClose()
    {
        if (m_hAccelTable) {
            ::DestroyAcceleratorTable(m_hAccelTable);
            m_hAccelTable = NULL;
        }
        CFrameWndEx::OnClose();
    }

    ただ、これで全てうまくいくかどうかは分かりませんし、こんな基本的な部分がうまく動かないようでは、他の部分も怪しいと思ったほうが良いでしょう。

    • 編集済み zakio 2009年2月12日 2:33 this を削除
    • 回答としてマーク JANEQUIN 2009年2月12日 7:45
    2009年2月12日 2:25

すべての返信

  • JANEQUINさん、こんにちは。中川俊輔です。

    実装状況がわからないので想像ですが、LoadAccelerators(), TranslateAccelerator()等を記述していないのではないでしょうか?

    英語のMSDNライブラリですが、このページが参考になると思います。
    Using Keyboard Accelerators
    http://msdn.microsoft.com/en-us/library/ms646337(VS.85).aspx

    また外部サイトですが、こちらのページで非常にわかりやすく解説されています。
    Win32API(C言語)編 第33章 アクセラレータキー(外部サイト)
    http://www.geocities.jp/ky_webid/win32c/033.html

    参考になると幸いです。それでは!

    この投稿は現状のまま何の保証もなく掲載しているものであり、何らかの権利を許諾するものでもありません。
    コミュニティにおけるマイクロソフト社員による発言やコメントは、マイクロソフトの正式な見解またはコメントではありません。
    詳しくは
    http://www.microsoft.com/japan/communities/msp.mspx をご覧ください。


    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年2月4日 9:56
  • 中川俊輔 さん、

    実装状況がわからないので想像ですが、LoadAccelerators(), TranslateAccelerator()等を記述していないのではないでしょうか?

     
    そういうこともあるかもと思っていたのですが、とりあえずプロジェクトの新規作成で作成したスケルトンなのであまり疑っていませんでした。

    念のため、LoadFrameをオーバーライドしてトレースしてみたのですが、CFrameWnd::LoadAccelTable()でリソース128(=IDR_MAINFRAME)を読み込んでいるようです。

    それとも、何か特殊なことをしなければならないのでしょうか?

    2009年2月5日 9:03
  • あ、MFCアプリケーションですね。。
    ごめんなさい勘違いしてました。

    JANEQUINさんと同じと思われる手順で試してみましたが、正常にCtrl + Tでメッセージボックスが表示されました。
    簡単にこちらで試した手順を記述します。

    1. シングルドキュメントでMFCアプリケーションを作成。他の選択肢は初期値のまま。
    2. IDR_MAINFRAMEアクセラレータリソースに、ID="ID_TEST",修飾子="Ctrl",キー="T"で新規作成
    3. IDR_MAINFRAMEメニューリソースの適当な場所に、Caption="テスト",ID="ID_TEST"で作成
    4. 4を右クリックし、イベントハンドラーの追加
    5. イベントハンドラーに"MessageBox( L"test", L"test");"を記述

    この投稿は現状のまま何の保証もなく掲載しているものであり、何らかの権利を許諾するものでもありません。
    コミュニティにおけるマイクロソフト社員による発言やコメントは、マイクロソフトの正式な見解またはコメントではありません。
    詳しくは
    http://www.microsoft.com/japan/communities/msp.mspx をご覧ください。


    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年2月9日 4:59
  • 中川俊輔 さん、

    中川 俊輔 さんの発言:
    1. シングルドキュメントでMFCアプリケーションを作成。他の選択肢は初期値のまま。

    ここが違うんです。
    SP1のMFC Feature Packを使っています。
    ウィザード6ページ目の「コマンドバー」のところで、「メニューとツールバーを使用する」を選択して作成しました。
    こうすると、CMainFrameはCFrameWndExから派生しますし、メニューもCMFCMenuBarが使われます。
    このときにアクセラレータが無視されるし、その前にメニューのキャプションに登録した\tCtrl+Tなども表示されません。

    ためしに、出来上がったスケルトンのCMainFrameにあるCMFCMenuBarをCreateしているようなコードをカットすると、通常のメニューバーが表示され、このときはキャプションにCtrl+Tと表示されるようになります。それでも、アクセラレータは無視されます。

    このあたりの仕組みが謎ですが、とりあえずはFeaturePackのクールなUIで作成するアプリケーションで、アクセラレータを使えるようにしたいのですが、それができずに大変困っています。

    よろしくお願いします。

    2009年2月10日 5:35
  •  ひとつ手がかりというか、間接的な原因が分かりました。
    最初に私が提示した手順、

    JANEQUIN の発言:

    次の手順で簡単なアプリケーションを作ってみました。

    1. アプリケーションウィザードの「ユーザーインターフェイス機能」のプロパティページで、「メニューバーとツールバーを使用する」のラジオボタンをチェックして作成。
    2. IDR_MAINFRAMEメニューリソースの適当な場所に、「テスト\tCtrl+T」などをCaptionとしてID_TESTを作成。
    3. IDR_MAINFRAMEアクセラレータリソースに、ID_TESTをCtrl+Tとなるように設定。
    4. このメニューのメッセージハンドラを作成して、メッセージボックスを表示するなどの適当なコードを記述。
    の1と2の間で、つまりリソースを追加する前に一度ビルドして実行したときにこの問題が発生します。1~4まで一気にやったときは問題ありません。それで、他の方も再現できずに私一人が狼少年になっていたのかも知れません。手順を正確に確認せずに申し訳ありませんでした。

    原因は、CMainFrameが保存するレジストリにありそうです。ためしに、レジストリ

    HKEY_CURRENT_USER\Software\アプリケーション ウィザードで生成されたローカル アプリケーション\(アプリ名)\Workspace

    を削除して起動すれば、アクセラレータはメニューのキャプションに表示されるし、正しく機能してくれます。その後、アクセラレータを追加するたびに、レジストリを消してやらないと新しいアクセラレータは無視されます。

    さて、この問題どうしたらいいのでしょう?
    2009年2月11日 4:55
  • こちらの環境でも再現しました。
    バグってますね、設計思想が致命的に。

    どういうつもりか分かりませんが、CKeyboardManager というやつが終了時にアクセラレータをレジストリに保存しています。 一度アクセラレータテーブルが保存されてしまうとそれを一生使い続けることになってしまうため、新しい項目を追加しても当然ながら無視されてしまいます。

    JANEQUIN の発言:
    さて、この問題どうしたらいいのでしょう?

    根本的な解決ではないと思いますが、自前でアクセラレータを消去してしまえば、不必要なセーブを防ぐことが出来ます。

    void CMainFrame::OnClose()
    {
        if (m_hAccelTable) {
            ::DestroyAcceleratorTable(m_hAccelTable);
            m_hAccelTable = NULL;
        }
        CFrameWndEx::OnClose();
    }

    ただ、これで全てうまくいくかどうかは分かりませんし、こんな基本的な部分がうまく動かないようでは、他の部分も怪しいと思ったほうが良いでしょう。

    • 編集済み zakio 2009年2月12日 2:33 this を削除
    • 回答としてマーク JANEQUIN 2009年2月12日 7:45
    2009年2月12日 2:25
  • zakio さん、

    詳しく調べていただいてありがとうございます。


    zakioさん の発言:

    根本的な解決ではないと思いますが、自前でアクセラレータを消去してしまえば、不必要なセーブを防ぐことが出来ます。

    void CMainFrame::OnClose()
    {
        if (m_hAccelTable) {
            ::DestroyAcceleratorTable(m_hAccelTable);
            m_hAccelTable = NULL;
        }
        CFrameWndEx::OnClose();
    }



    その方法で、とりあえずうまくいくようになりました。


    zakioさん の発言:


    ただ、これで全てうまくいくかどうかは分かりませんし、こんな基本的な部分がうまく動かないようでは、他の部分も怪しいと思ったほうが良いでしょう。



    これは、FeaturePack全体のお話ですよね。困ったもんです。(中川俊輔さん、ごめんなさい。)

    FeaturePackのSP2が出るまで、仕事には使えないですね(爆)


     
    2009年2月12日 7:45
  • こんにちは。中川俊輔です。

    zakioさん、再現テストと回避法の投稿ありがとうございます。

    JANEQUINさん、どうも不具合の可能性が高そうですね。。ご迷惑をおかけしています。

    もしよろしければ、下記のフィードバックセンターに障害報告をしてください。
    確実ではないのですが、USの開発者から回答が期待できます。

    Visual Studio & .NET Framework プロダクト フィードバック センター
    http://connect.microsoft.com/VisualStudioJapan
    (参考)
    http://blogs.msdn.com/dd_jpn/archive/2008/03/04/8025047.aspx
    http://blogs.msdn.com/dd_jpn/archive/2008/07/31/8793096.aspx
    http://www.microsoft.com/japan/msdn/vstudio/feedback/

    今後ともフォーラムをよろしくお願いします。
    それでは!

    この投稿は現状のまま何の保証もなく掲載しているものであり、何らかの権利を許諾するものでもありません。
    コミュニティにおけるマイクロソフト社員による発言やコメントは、マイクロソフトの正式な見解またはコメントではありません。
    詳しくは
    http://www.microsoft.com/japan/communities/msp.mspx をご覧ください。

    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年2月12日 8:55
  • 中川俊輔 さん、

    そうですね。フィードバックセンターにフィードバックしてご協力なければと思っていますが、きちんとサーベイしてからでないとと思いながら、なかなか時間が取れていません。

    メニューのアクセラレータの他にもいろんな状態をレジストリに保存しているようで、他にも不具合らしきものがその後見つかっています。自分なりに状況が整理できたらいつか投稿してみようと思います。

    ありがとうございました。
    2009年2月20日 2:52