テクニカル ノート 62: Windows コントロールへのメッセージ リフレクション (メッセージ返送)
注意
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
このテクニカル ノートはメッセージ リフレクション、MFC 4.0 の新機能について説明します。 また、メッセージ リフレクションを使用する簡単な再利用可能なコントロールを作成する手順を示します。
このテクニカル ノートは ActiveX コントロールに適用するときにメッセージ リフレクションについては説明しません (以前の OLE コントロールとも呼ばれます)。 ActiveX コントロール: Windows のコントロールをサブクラス化する。記事を参照してください。
メッセージ リフレクションは何ですか。
Windows のコントロールが親ウィンドウに頻繁に通知メッセージを送信します。 たとえば、多くのコントロールには親コントロールの親の背景を描画するためのブラシを指定できるように、コントロールの色の通知メッセージ (バリアントのWM_CTLCOLOR または 1) します。
Windows とバージョン 4.0 以前の MFC、親ウィンドウ、ダイアログ ボックスで次のメッセージを処理する必要があります。 これにより、メッセージを親ウィンドウ クラスになる必要があることを、そのメッセージを処理する必要があるすべてのクラスで重複している処理のためのコードを示します。 上記のときにカスタムの背景の望まれたコントロールがコントロールのカラー通知メッセージが処理しなければならない場合は、必ずダイアログ ボックス。 独自の背景色を処理するコントロール クラスを記述しているが、コードの再利用が簡単です。
MFC 4.0 で、古い機能は引き続き動作しますが、親ウィンドウに通知メッセージを処理できます。 また、MFC 4.0 は「メッセージ リフレクション」と呼ばれる機能を提供して再利用を割り当てと子コントロールのウィンドウまたは親ウィンドウ、またはその両方で処理される必要も通知メッセージしやすくなります。 コントロールの背景色の例で、WM_CTLCOLOR 反映されたメッセージの—親に依存しないですべて処理して独自の背景色を設定するコントロール クラスを記述できます。(メッセージ リフレクションが Windows による MFC ではなく、親ウィンドウのクラス実装されるため、メッセージ リフレクションの CWnd から始めるに派生されなければならないください。)
MFC の古いバージョンがオーナー描画のリスト ボックスWM_DRAWITEM (提供してメッセージ リフレクションに似たものなど) のメッセージなどの一部のメッセージに仮想関数が、しました。 新しいメッセージ リフレクションの機能は、汎化され、一貫性があります。
メッセージ リフレクションは、MFC 4.0 以前のバージョン用に記述されたコードと下位互換性があります。
特定のメッセージ、またはメッセージの範囲のハンドラーを、親ウィンドウのクラスで渡す場合、同じメッセージのリフレクション メッセージ ハンドラーを提供しました呼び出しません独自のハンドラーの基本クラスのハンドラー関数をオーバーライドします。 たとえば、ダイアログ ボックス クラスで WM_CTLCOLOR を処理すれば、処理はリフレクション メッセージ ハンドラーをオーバーライドします。
、親ウィンドウのクラスでは、WM_NOTIFY メッセージの WM_NOTIFY 特定のメッセージまたは範囲のハンドラーを指定した場合、ハンドラーはメッセージを送信する子コントロールが **ON_NOTIFY_REFLECT()**でリフレクション メッセージ ハンドラーがない場合にのみ呼び出されます。 メッセージ マップで ON_NOTIFY_REFLECT_EX() を使用して親ウィンドウがメッセージを処理するようにことなく、メッセージ ハンドラーがされたり、そうでない場合があります。 ハンドラーが FALSEを返した場合、メッセージは親によって TRUE を返す呼び出しは親を処理しないようにようにしていても、同様に処理されます。 リフレクション メッセージが通知メッセージの前に処理されることに注意してください。
WM_NOTIFY メッセージが送信されると、コントロールはそれを処理する最初の可能性が提供されます。 そのほかのリフレクション メッセージ、つまり、親ウィンドウに処理する最初の可能性があり、コントロールはリフレクション メッセージを受け取ります。 そのためには、コントロールのクラスのメッセージ マップでハンドラー関数と適切なエントリが必要です。
リフレクション メッセージのメッセージ マップ マクロは通常の通知とは少し異なります: これは、通常の名前が付けられている _REFLECT があります。 たとえば、親の WM_NOTIFY メッセージを処理するために、親のメッセージ マップで ON_NOTIFY マクロを使用します。 子コントロールのリフレクション メッセージを処理するには、子コントロールのメッセージ マップで ON_NOTIFY_REFLECT マクロを使用します。 場合によっては、パラメーターが異なる場合は、同様に。 ClassWizard は通常、に対するメッセージ マップ エントリを追加し、適切なパラメーターをスケルトン関数の実装に付与できることに注意してください。
WM_NOTIFY 新しいメッセージについては、" TN061: ON_NOTIFY と WM_NOTIFY メッセージ を参照してください。
リフレクション メッセージに対するメッセージ マップ エントリとハンドラー関数プロトタイプ
反射したコントロール通知メッセージを処理するには、次の表に示すメッセージ マップ マクロや関数プロトタイプを使用します。
ClassWizard は通常、これらのメッセージ マップ エントリを追加して、スケルトン関数の実装を提供します。 リフレクション メッセージ ハンドラーを定義する方法の詳細については、" リフレクション メッセージのメッセージ ハンドラーを定義する を参照してください。
メッセージの名前が反映されたマクロ名に変換するには、ON_ をアタッチし、_REFLECTを追加します。 たとえば、WM_CTLCOLOR は ON_WM_CTLCOLOR_REFLECTになります。(メッセージが反映できるかを参照するには次の表のマクロ エントリの逆変換を)。
上記の規則の 3 点は次のとおりです。:
WM_COMMAND 通知のマクロは ON_CONTROL_REFLECTです。
WM_NOTIFY のリフレクションのマクロは ON_NOTIFY_REFLECTです。
ON_UPDATE_COMMAND_UI のリフレクションのマクロは ON_UPDATE_COMMAND_UI_REFLECTです。
上記の特殊なケースにはそれぞれ、ハンドラー メンバー関数の名前を指定する必要があります。 そのほかの場合は、ハンドラー関数には標準の名前を使用する必要があります。
関数のパラメーターと戻り値の意味は関数名で参照してまたは オン 関数名を結合します。 たとえば、CtlColor は OnCtlColor"で説明しています。 一部のリフレクション メッセージ ハンドラーが親ウィンドウに似たハンドラーよりも少ないパラメーターが必要です。 、ドキュメントの仮パラメーターの名前に次の表の名前と一致します。
マップ エントリ |
関数プロトタイプ |
---|---|
ON_CONTROL_REFLECT( wNotifyCode###,memberFxn ) |
afx_msg void memberFxn ( ); |
ON_NOTIFY_REFLECT( wNotifyCode###,memberFxn ) |
afx_msg void memberFxn ( NMHDR * pNotifyStruct, LRESULT* の結果 ); |
ON_UPDATE_COMMAND_UI_REFLECT( memberFxn ) |
afx_msg void memberFxn ( CCmdUI* pCmdUI ); |
ON_WM_CTLCOLOR_REFLECT () |
afx_msg HBRUSH CtlColor ( CDC* pDC, UINT nCtlColor ); |
ON_WM_DRAWITEM_REFLECT () |
afx_msg void DrawItem ( LPDRAWITEMSTRUCT lpDrawItemStruct ); |
ON_WM_MEASUREITEM_REFLECT () |
afx_msg void MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct ); |
ON_WM_DELETEITEM_REFLECT () |
afx_msg void DeleteItem ( LPDELETEITEMSTRUCT lpDeleteItemStruct ); |
ON_WM_COMPAREITEM_REFLECT () |
afx_msg int CompareItem ( LPCOMPAREITEMSTRUCT lpCompareItemStruct ); |
ON_WM_CHARTOITEM_REFLECT () |
afx_msg int CharToItem ( UINT nKey, UINT nIndex ); |
ON_WM_VKEYTOITEM_REFLECT () |
afx_msg int VKeyToItem ( UINT nKey, UINT nIndex ); |
ON_WM_HSCROLL_REFLECT () |
afx_msg void HScroll ( UINT nSBCode, UINT nPos ); |
ON_WM_VSCROLL_REFLECT () |
afx_msg void VScroll ( UINT nSBCode, UINT nPos ); |
ON_WM_PARENTNOTIFY_REFLECT () |
afx_msg void ParentNotify ( UINT message, LPARAM lParam ); |
ON_NOTIFY_REFLECT と ON_CONTROL_REFLECT マクロに複数のオブジェクト (コントロールや親などの特定のメッセージを処理するようにようなバリエーションがあります。
マップ エントリ |
関数プロトタイプ |
---|---|
ON_NOTIFY_REFLECT_EX( wNotifyCode###,memberFxn ) |
afx_msg BOOL memberFxn ( NMHDR * pNotifyStruct, LRESULT* の結果 ); |
ON_CONTROL_REFLECT_EX( wNotifyCode###,memberFxn ) |
afx_msg BOOL memberFxn ( ); |
処理のリフレクション メッセージ: 再利用可能なコントロールの例
この簡単な例を CYellowEditという再利用可能なコントロールを作成します。 コントロールは標準エディット コントロールと同じように動作しますが、黄色い背景に黒のテキストが表示されます。 CYellowEdit のコントロールが異なる色が表示されるようにするメンバー関数を追加したりできます。
再利用可能なコントロールを作成する例があります。
既存のアプリケーションの新しいダイアログ ボックスを作成します。 詳細については、ダイアログ エディター "を参照します。
再利用可能なコントロールを開発するアプリケーションが必要です。 使用する既存のアプリケーションがない場合は、AppWizard を使用してダイアログ ベースのアプリケーションを作成します。
Visual C++ でプロジェクトが読み込まれて CEditに基づいて CYellowEdit という名前の新しいクラスを作成するために ClassWizard を使用します。
CYellowEdit クラスに 3 個の変数を追加します。 最初の 2 つがテキストの色と背景色を保持する COLORREF の変数です。 番目には背景を描画するためのブラシを保持する CBrush オブジェクトです。 CBrush オブジェクトは CYellowEdit のコントロールを破棄すると、ブラシを使用して、その後は一度だけ作成し、ブラシを参照して自動的に破棄することができます。
コンストラクターを記述してメンバー変数を初期化して、次のような:
CYellowEdit::CYellowEdit() { m_clrText = RGB( 0, 0, 0 ); m_clrBkgnd = RGB( 255, 255, 0 ); m_brBkgnd.CreateSolidBrush( m_clrBkgnd ); }
ClassWizard を使用して、CYellowEdit クラスに WM_CTLCOLOR 反映されたメッセージのハンドラーを追加します。 メッセージが反映されるように、処理できるメッセージ ボックスの一覧でメッセージの名前の前に等号を示すことに注意してください。 これは リフレクション メッセージのメッセージ ハンドラーを定義するで説明します。
ClassWizard では以下のメッセージ マップ マクロとスケルトン関数を追加する:
ON_WM_CTLCOLOR_REFLECT() // Note: other code will be in between.... HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor) { // TODO: Change any attributes of the DC here // TODO: Return a non-NULL brush if the // parent's handler should not be called return NULL; }
次のコードでは、関数の本体を置き換えます。 コードでは、コントロール内のテキストの色、テキストの背景色と背景色を指定します。
pDC->SetTextColor( m_clrText ); // text pDC->SetBkColor( m_clrBkgnd ); // text bkgnd return m_brBkgnd; // ctl bkgnd
エディット コントロールをダイアログ ボックスで作成し、メンバー変数にエディット コントロールをダブルクリックして接続して、Ctrl キーを押したまま中。 メンバー変数の追加ダイアログ ボックスで、変数名を終了し、カテゴリの「コントロール」、および変数の型の「CYellowEdit」選択します。 ダイアログ ボックスのタブ オーダーを設定するのを忘れないしないでください。 このダイアログ ボックスのヘッダー ファイルに CYellowEdit のコントロールのヘッダー ファイルをインクルードするようにしてください。
アプリケーションをビルドして実行します。 エディット コントロールは、黄色い背景があります。