次の方法で共有


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

[!メモ]

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

ここでは、一般的なウィンドウ メッセージのルーティングでコマンド ルーティングとディスパッチのアーキテクチャ、または高度なトピックについて説明します。

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

コマンド ルーティングとディスパッチの MFC 1.0 では、 MFC 2.0 アーキテクチャに配置します

ウィンドウは、メニュー コマンド、アクセラレータ キーとダイアログ コントロール通知の通知を提供するためにオーバーロード 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 コマンドは個別に有効または無効にできます。新規作成(&&N),新規作成,新規,new のポップアップ メニューは 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 を呼び出しているダイアログにボタン コントロールを配置する 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 のゾーン (秒)には、通常 TranslateMDISysAccel によって処理します (最後の処理)標準 MDI システム コマンド アクセラレータ。

スクロール バーの問題

スクロール メッセージ (WM_HSCROLL/OnHScrollWM_VSCROLL/OnVScroll)を処理する場合、ハンドラー コードを記述する必要があります。スクロール バー メッセージの位置にからのアセンブリまたは依存しません。これは、スクロール メッセージが true のスクロール バー コントロールまたはスクロール バー コントロールの WS_HSCROLL/WS_VSCROLL のスクロール バーから送信されることがあるため、のみの一般的なウィンドウの問題です。

MFC はスクロール バー コントロールを使用してにスクロールするペインの子または兄弟とされています (実際、スクロールされたスクロール バーの間の親子のリレーションシップ、およびウィンドウは何でもできます)。これは、分割ペインを使用して共有スクロール バーにとって特に重要です。 共有スクロール バーの問題の詳細を含める CSplitterWnd の実装の詳細については テクニカル ノート 29 を参照してください。

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

MDICLIENT を作成するに CMDIFrameWnd には、によってが 生成(&&C),create,作成,生成 に渡されるまたは LoadFrame を使用して、スクロール バーのフォーム。スクロール可能な MDICLIENT の区分がある場合は (Windows のプログラム マネージャーのように)の両方のスクロール バーのフォーム (WS_HSCROLLを設定してください |CMDIFrameWndを作成するために使用されるフォームのWS_VSCROLL)。

CSplitterWnd のようにスクロール バーのフォームは分割領域に共有される特別なスクロール バーに適用されます。静的分割ウィンドウの場合、通常、いずれかのスクロール バーの書式を設定しません。動的分割ウィンドウのために、通常スクロール バーのスタイルをあなたが分割する方向のためにセットします。すなわち、列を分割できれば WS_HSCROLL を、行を分割できれば WS_VSCROLL をセットします。

参照

その他の技術情報

番号順テクニカル ノート

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