次の方法で共有


テクニカル ノート 21: コマンドとメッセージのルーティング

注意

次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。

ここでは、一般的なウィンドウ メッセージのルーティングのコマンド ルーティングとディスパッチのアーキテクチャ、上級者向けのトピックで説明します。

相違点、コントロール通知とコマンドを次、Windows メッセージの間に特に説明した一般的なアーキテクチャの詳細については、" Visual C++ "を参照してください。 ここでは、印刷されたドキュメントと Address 非常に説明した問題を十分理解している高度なトピックのみであることを前提としています。

Command Routing およびディスパッチ MFC 1.0 では、MFC 2.0 アーキテクチャに進化します

Windows は、メニュー コマンド、アクセラレータ キーとダイアログ コントロール通知の通知されるようにオーバーロードされる WM_COMMAND メッセージがあります。

CWnd の派生クラスでコマンド ハンドラーの特定の WM_COMMANDに対する応答として呼び出されるため、それに小さい (たとえば、「OnFileNew」) は、MFC 1.0。 これは、メッセージ マップというデータ構造と非常に効率的なコマンド機構の結果とともに設定します。

コマンド メッセージからコントロール通知を分離するための MFC 1.0 の、指定された追加機能。 コマンドは、コマンド ID と呼ばれる 16 ビット ID で、表されます。 コマンドは CFrameWnd (つまり、メニュー選択または変換されたアクセラレータ) から通常どおり起動し、他のさまざまなウィンドウに送られます。

MFC 1.0 はマルチ ドキュメント インターフェイス (MDI) の実装のために対して意味でコマンド ルーティングを使用します。(MDI フレーム ウィンドウのデリゲートはアクティブな MDI 子ウィンドウへ)。

この機能は、より広い範囲のオブジェクト (単にウィンドウ オブジェクト) によって処理される割り当てコマンドに MFC 2.0 に汎化され、拡張されました。 これはメッセージをルーティングするために正式により、拡張性に優れたアーキテクチャを提供し、コマンドだけでなく、処理のコマンドの対象のルーティングを再利用して、コマンドの現在の可用性を反映するように、更新の UI (メニュー項目やツール バー ボタンなど) を表示します。

コマンド ID

コマンド ルーティングとバインディング プロセスの詳細については、" Visual C++ を参照してください。 テクニカル ノート 20 は ID の名前付けに関する情報が含まれています。

これは、コマンド ID に一般的なプリフィックス「ID_」を使用します。 コマンド ID = 0x8000 です >。 同じ ID の STRINGTABLE リソースがコマンド ID にあるメッセージ行またはステータス バーにコマンドの説明文字列を示します。

アプリケーションのリソースでは、コマンド ID の機能は、複数の場所で表示:

  • メッセージ行のプロンプトと同じ ID を持つ 1 個の STRINGTABLE リソース。

  • 。同じコマンドを呼び出すメニュー項目に接続する多くのメニュー リソース。

  • (詳細) GOSUB コマンドのダイアログ ボタンです。

アプリケーションのソース・コードでは、コマンド ID の機能は、複数の場所で表示:

  • アプリケーション固有のコマンド ID を定義する RESOURCE.H (またはそのほかの主要なシンボル ヘッダー ファイル)。

  • 多くのツール バーを作成するために使用される ID の配列です。

  • ON_COMMAND マクロ。

  • 多く ON_UPDATE_COMMAND_UI マクロで。

現在、コマンド ID が必要な MFC の実装は = 0x8000 です GOSUB ダイアログとコマンドの実装です >。

ダイアログのコマンド アーキテクチャを使用して、GOSUB コマンド

ルーティングおよび有効なコマンドのコマンド アーキテクチャは、フレーム ウィンドウ、メニュー項目、ツール バー ボタン、ダイアログ バーのボタンと、オンデマンドで更新し、主要なコマンドの対象 (通常はメイン フレーム ウィンドウ) にコマンドやコントロールの ID をルーティングするようにされている他のすべてのコントロール バーなどのユーザー インターフェイス要素が使用されます。 主要なコマンドの対象は、必要に応じて、他のコマンド ターゲット オブジェクトにコマンドやコントロール通知をルーティングすること。

ダイアログ ボックスがコマンド アーキテクチャの機能 (モーダルまたはモードレス) 適切なコマンド ID にダイアログ コントロールのコントロール ID を割り当てることができます。 ダイアログのサポートは自動ではないため、追加のコードを記述する必要があります。

正しく動作するすべての機能に対するコマンド ID が = 0x8000 である >ことに注意してください。 多数のダイアログが同じフレームにルーティングすることができるため、共有コマンドでは、特定の >ダイアログの非共有 IDCs = 0x7FFF 必要ですが、= 0x8000 <必要です。

適切なコマンド ID に設定したボタンで IDC を正常にモーダル ダイアログに正常にボタンを配置できます。 ユーザーがボタンをクリックした場合、ダイアログ (通常はメイン フレーム ウィンドウ) の所有者は他のコマンドなどのコマンドが、取得します。 これは、ダイアログ (最初のダイアログ GOSUB) を呼び出すことを通常使用するため GOSUB コマンドと呼ばれます。

このダイアログ CWnd::UpdateDialogControls 関数を呼び出し、それにメイン フレーム ウィンドウのアドレスを渡すことができます。 この関数は、フレームでコマンド ハンドラーがあるかどうかに基づいて、ダイアログ コントロールを有効または無効にします。 この関数は、アプリケーションのアイドル ループ コントロール バーの使用を自動的に対しては、この機能を使用すると、通常のダイアログの直接呼び出す必要があります。

ON_UPDATE_COMMAND_UI が呼び出されます。

有効/すべてオンの状態管理のプログラムのメニュー項目に負荷の高い問題になることがあります。 一般的な方法は、ユーザーがポップアップを選択した場合のみ有効にするために、チェックのメニュー項目です。 CFrameWnd の MFC 2.0 の実装は WM_INITMENUPOPUP メッセージを処理し、ON_UPDATE_COMMAND_UI ハンドラーを通じてメニューの状態を判断するときにコマンド ルーティング アーキテクチャを使用します。

CFrameWnd は、ステータス バーのメッセージ行 (エイリアス) で選択した現在のメニュー項目を説明する WM_ENTERIDLE メッセージを処理します。

Visual C++ で編集されたアプリケーションのメニュー構造が WM_INITMENUPOPUP 時に使用できる潜在的なコマンドを表すために使用されます。 ON_UPDATE_COMMAND_UI ハンドラーは、メニューが描画される前に (MRU ファイル リストまたは OLE 動詞ポップアップ メニューなど) を実際に変更して、メニュー構造をメニュー内、または高度な使い方の状態またはテキストを変更できます。

アプリケーションがアイドル ループに入るときに同じ処理、一種の ON_UPDATE_COMMAND_UI の処理はツール バー行われます (および他のすべてのコントロール バーの場合)。 コントロール バーの詳細については、" クラス ライブラリ リファレンステクニカル ノート 31 を参照してください。

入れ子のポップアップ メニュー

入れ子になったメニュー構造を使用して、ポップアップ メニューの最初のメニュー項目の ON_UPDATE_COMMAND_UI ハンドラーが 2 の場合に呼び出されることがわかります。

まず、ポップアップ メニュー自体に対して呼び出されます。 これは、ポップアップ メニューに ID がなく、全体のポップアップ メニューを表示するために、本来はポップアップ メニューの最初のメニュー項目の ID を使用するためです。 この場合、CCmdUI オブジェクトの m_pSubMenu のメンバー変数が null 以外では、ポップアップ メニューを指します。

第 2 に、ポップアップ メニューのメニュー項目を描画する必要がある直前に呼び出されます。 この場合、ID は、最初のメニュー項目にのみ関連します。また、CCmdUI オブジェクトの m_pSubMenu のメンバー変数が null です。

これは、メニュー項目の個々のポップアップ メニューを有効にすることができますが、メニューに対応するコードを記述する必要があります。 たとえば、次の構造を持つ入れ子になったメニューの:

File>
    New>
        Sheet (ID_NEW_SHEET)
        Chart (ID_NEW_CHART)

ID_NEW_SHEET と ID_NEW_CHART コマンドは個別に有効または無効にすることができます。 新規作成 ポップアップ メニューは 2 のいずれかが有効な場合は有効になります。

ID_NEW_SHEET (ポップアップの最初のコマンド) のコマンド ハンドラーは次のような表示:

void CMyApp::OnUpdateNewSheet(CCmdUI* pCmdUI)
{
    if (pCmdUI->m_pSubMenu != NULL)
    {
        // enable entire pop-up for "New" sheet and chart
        BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;

        // CCmdUI::Enable is a no-op for this case, so we
        //   must do what it would have done.
        pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex,
            MF_BYPOSITION | 
                (bEnable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
        return;
    }
    // otherwise just the New Sheet command
    pCmdUI->Enable(m_bCanCreateSheet);
}

ID_NEW_CHART のコマンド ハンドラーは、正常な更新コマンド ハンドラーの外観や動作などです:

void CMyApp::OnUpdateNewChart(CCmdUI* pCmdUI)
{
    pCmdUI->Enable(m_bCanCreateChart);
}

ON_COMMAND および ON_BN_CLICKED

ON_COMMANDON_BN_CLICKED のメッセージ マップ マクロは同じです。 MFC コマンドとコントロール通知のルーティングの機能は、どこにルーティングするかを決定するためにコマンド ID だけを使用しています。 ゼロ コントロール通知コード コントロール通知はコマンド (BN_CLICKED) として解釈されます。

注意

実際、すべてコントロール通知メッセージは、コマンド ハンドラーのチェーンを通過します。たとえば、ドキュメント クラスの EN_CHANGE のコントロール通知ハンドラーを記述することは技術的には可能です。これは、ClassWizard でこの機能が実用化の数になるため、一般に、勧められない機能はサポートされない、機能の使用は、脆弱なコードを生成できます。

ボタン コントロールを自動的に無効になることを無効にする。

ダイアログ バー、を使用して CWnd::UpdateDialogControls を手動で呼び出しているダイアログに Button コントロールを配置すると、ON_COMMAND または ON_UPDATE_COMMAND_UI ハンドラーがないボタンがフレームワークによって自動的に無効になることがわかります。 場合によっては、ハンドラーは必要ではありませんが、ボタンに有効にしたままにする必要があります。 これを実現するための最も簡単な方法は、ダミー コマンド ハンドラー (ClassWizard としやすい) 追加し、では機能しません。

ウィンドウ メッセージのルーティング

次に、Windows メッセージ ルーティングなどのトピックがユーザーにどのように影響するか MFC クラスのいくつかの高度なトピックについて説明します。 次の情報は、簡単に説明します。 パブリックな API については クラス ライブラリ リファレンス"を 参照してください。 実装の詳細の詳細については、MFC ライブラリのソース・コードを参照してください。

ウィンドウのクリーンアップの詳細については テクニカル ノート 17、すべての CWndにとって重要なトピック-派生クラスを参照してください。

CWnd の問題

実装のメンバー関数 CWnd::OnChildNotify は子ウィンドウ (またはコントロール) にフックする強力かつ拡張可能なアーキテクチャを提供するか、別の方法では親移動コマンド メッセージ、およびコントロールの通知機能のある (または「所有者に」)。 子ウィンドウ (/control) によって. C++ CWnd オブジェクト自体は、仮想関数 OnChildNotify は元のメッセージ (つまり、MSG 構造体) からパラメーターを最初に呼び出されます。 子ウィンドウはメッセージをそのまま、いるか、または親のメッセージを (ほとんど) を変更できます。

既定の CWnd の実装に次のメッセージを処理し、メッセージに初めてアクセスに子ウィンドウ (コントロール) を有効にするために OnChildNotify フックを使用します:

  • WM_MEASUREITEMWM_DRAWITEM 自己描画の場合)

  • WM_COMPAREITEMWM_DELETEITEM 自己描画の場合)

  • WM_HSCROLLWM_VSCROLL

  • WM_CTLCOLOR

  • WM_PARENTNOTIFY

OnChildNotify フックが自己描画メッセージにオーナー描画メッセージを変更するために使用されることを確認します。

OnChildNotify フックに加えて、スクロール メッセージにそれ以上のルーティングの動作が異なります。 WM_HSCROLLWM_VSCROLL メッセージのスクロール バーとソースの詳細については、次を参照してください。

CFrameWnd 問題

実装を更新する CFrameWnd クラスは、コマンド ルーティングとユーザー インターフェイスのほとんどを提供します。 これは、アプリケーションCWinApp::m_pMainWnd () のメイン フレーム ウィンドウに主に使用されますが、すべてのフレーム ウィンドウに適用されます。

メイン フレーム ウィンドウにメニュー バーがあるウィンドウで、ステータス バーまたはメッセージ行の親です。 コマンド ルーティングと WM_INITMENUPOPUP.、上記の説明を参照してください。

CFrameWnd クラスはアクティブなビューの管理を提供します。 次のメッセージは、アクティブなビューを通じてルーティングされます:

  • すべてのコマンド メッセージ (アクティブなビューがそれらの最初のアクセスの取得など)。

  • 兄弟スクロール バー (以下を参照) からWM_HSCROLLWM_VSCROLL メッセージ。

  • WM_ACTIVATE (および MDI の WM_MDIACTIVATE) 仮想関数 CView::OnActivateView呼び出しに回転します。

CMDIFrameWnd/CMDIChildWnd 問題

したがって、MDI フレーム ウィンドウ クラスは両方とも CFrameWnd から派生し、同じ一種の CFrameWndで提供されるコマンド ルーティングとユーザー インターフェイスの更新の両方が有効になります。 この一般的な MDI アプリケーションでは、メイン フレーム ウィンドウに (つまり、CMDIFrameWnd オブジェクト) メニュー バー、ステータス バーを保持し、コマンド ルーティングの実装の主要なソースです。

一般的なルーティング スキームはアクティブな MDI 子ウィンドウが最初のコマンドにアクセスできます。 既定の PreTranslateMessage 関数は、MDI 子ウィンドウの両方のアクセラレータ テーブル (最初) と MDI フレーム (second) は、通常 TranslateMDISysAccel して処理します (最後の) 処理される標準 MDI システム コマンド アクセラレータ。

スクロール バーの問題

スクロール メッセージ (WM_HSCROLL/OnHScrollWM_VSCROLL/OnVScroll) を処理した場合、ハンドラー コードを記述することをお勧めします。スクロール バー メッセージの位置にからのアセンブリまたは依存しません。 これにより、スクロール メッセージが true のスクロール バー コントロールまたは WS_HSCROLLとスクロール バー コントロールのWS_VSCROLL のスクロール バーから取得される可能性があるため、だけでなく、汎用 Windows 終了です。

MFC では、スクロール バー コントロールにスクロールするウィンドウの子または兄弟であることを拡張 (実際、スクロール バーの間にスクロールされます親子のリレーションシップとウィンドウは何でもかまいません)。 これは、分割ウィンドウに共有スクロール バーにとって特に重要です。 共有スクロール バー問題の詳細情報を含む CSplitterWnd の実装の詳細については テクニカル ノート 29 "を参照してください。

注釈で指定されるスクロール バーのスタイルが Windows に時間をトラップして渡されていない作成する CWnd の 2 種類の派生クラスがあります。 作成ルーチンに渡されると、作成が変更できないと WS_HSCROLLWS_VSCROLL は個別に設定できます。 もちろん、直接 WS_ をテストしたり、設定するのでしょうか。作成したウィンドウのスタイル ビットをスクロールします。

MDICLIENT の作成に CMDIFrameWnd の場合は、作成 に渡されるまたは LoadFrame を使用して、スクロール バーのスタイル。 スクロール可能 MDICLIENT の領域がある場合は (Windows プログラム マネージャーなど) の両方のスクロール バーのスタイル (WS_HSCROLLを設定してください。 | CMDIFrameWndの作成に使用されるスタイルのWS_VSCROLL)。

CSplitterWnd にスクロール バーのスタイルは分割領域の Shared、スクロール バーに適用されます。 静的な分割ウィンドウの場合、通常、いずれかのスクロール バーのスタイルを設定します。 動的な分割ウィンドウで、列を分割して行を分割して、スクロール バーのスタイルを分割する方向、つまり WS_HSCROLLWS_VSCROLL を設定します。

参照

その他の技術情報

番号順テクニカル ノート

カテゴリ別テクニカル ノート