TN062: Meldungsreflektion für Windows-Steuerelemente

Hinweis

Der folgende technische Hinweis wurde seit dem ersten Erscheinen in der Onlinedokumentation nicht aktualisiert. Daher können einige Verfahren und Themen veraltet oder falsch sein. Um aktuelle Informationen zu erhalten, wird empfohlen, das gewünschte Thema im Index der Onlinedokumentation zu suchen.

In diesem technischen Hinweis wird die Meldungsreflektion beschrieben, ein neues Feature in MFC 4.0. Es enthält auch Anweisungen zum Erstellen eines einfachen wiederverwendbaren Steuerelements, das Nachrichtenspiegelung verwendet.

In diesem technischen Hinweis wird die Nachrichtenreflektion nicht behandelt, da sie für ActiveX-Steuerelemente (früher ALS OLE-Steuerelemente bezeichnet) gilt. Lesen Sie den Artikel ActiveX-Steuerelemente: Unterklassen eines Windows-Steuerelements.

Was ist Nachrichtenreflektion?

Windows-Steuerelemente senden Benachrichtigungen häufig an die übergeordneten Fenster. Beispielsweise senden viele Steuerelemente eine Benachrichtigung über die Farbe eines Steuerelements (WM_CTLCOLOR oder eine seiner Varianten) an das übergeordnete Element, damit das übergeordnete Element einen Pinsel zum Zeichnen des Hintergrunds des Steuerelements bereitstellen kann.

In Windows und in MFC vor Version 4.0 ist das übergeordnete Fenster, häufig ein Dialogfeld, für die Verarbeitung dieser Nachrichten verantwortlich. Dies bedeutet, dass der Code für die Verarbeitung der Nachricht in der Klasse des übergeordneten Fensters enthalten sein muss und dass er in jeder Klasse dupliziert werden muss, die diese Nachricht verarbeiten muss. Im obigen Fall müsste jedes Dialogfeld, in dem Steuerelemente mit benutzerdefinierten Hintergründen verwendet werden sollen, die Benachrichtigung über die Farbe des Steuerelements behandeln. Es wäre viel einfacher, Code wiederzuverwenden, wenn eine Steuerelementklasse geschrieben werden könnte, die eine eigene Hintergrundfarbe behandelt.

In MFC 4.0 funktioniert der alte Mechanismus weiterhin – übergeordnete Fenster können Benachrichtigungen verarbeiten. Darüber hinaus erleichtert MFC 4.0 die Wiederverwendung, indem ein Feature namens "Nachrichtenspiegelung" bereitgestellt wird, das es diesen Benachrichtigungen ermöglicht, entweder im untergeordneten Steuerelementfenster oder im übergeordneten Fenster oder in beiden Zugängen behandelt zu werden. Im Beispiel für die Hintergrundfarbe des Steuerelements können Sie jetzt eine Steuerelementklasse schreiben, die eine eigene Hintergrundfarbe festlegt, indem Sie die reflektierte WM_CTLCOLOR Nachricht behandeln – alles, ohne sich auf das übergeordnete Element zu verlassen. (Beachten Sie, dass die übergeordnete Fensterklasse abgeleitet werden muss, da die Nachrichtenspiegelung von MFC und nicht von Windows implementiert wird CWnd , damit die Nachrichtenreflexion funktioniert.)

Ältere Versionen von MFC haben etwas ähnliches wie die Nachrichtenreflexion gemacht, indem virtuelle Funktionen für einige Nachrichten bereitgestellt werden, z. B. Nachrichten für vom Besitzer gezeichnete Listenfelder (WM_DRAWITEM usw.). Der neue Nachrichtenspiegelungsmechanismus ist generalisiert und konsistent.

Die Nachrichtenspiegelung ist abwärtskompatibel mit Code, der für MFC-Versionen vor 4.0 geschrieben wurde.

Wenn Sie in der Klasse des übergeordneten Fensters einen Handler für eine bestimmte Nachricht oder für einen Bereich von Nachrichten angegeben haben, überschreibt er die reflektierten Nachrichtenhandler für dieselbe Nachricht, sofern Sie die Basisklassenhandlerfunktion nicht in Ihrem eigenen Handler aufrufen. Wenn Sie z. B. WM_CTLCOLOR in Ihrer Dialogfeldklasse behandeln, überschreibt die Behandlung alle reflektierten Nachrichtenhandler.

Wenn Sie in der übergeordneten Fensterklasse einen Handler für eine bestimmte WM_NOTIFY Nachricht oder einen Bereich von WM_NOTIFY Nachrichten bereitstellen, wird der Handler nur aufgerufen, wenn das untergeordnete Steuerelement, das diese Nachrichten sendet, keinen Reflektierten Nachrichtenhandler über ON_NOTIFY_REFLECT(). Wenn Sie die Nachrichtenzuordnung verwenden ON_NOTIFY_REFLECT_EX() , kann der Nachrichtenhandler die Verarbeitung der Nachricht im übergeordneten Fenster zulassen oder nicht. Wenn der Handler FALSE zurückgibt, wird die Nachricht auch vom übergeordneten Element behandelt, während ein Aufruf, der WAHR zurückgibt, das übergeordnete Element nicht verarbeiten kann. Beachten Sie, dass die reflektierte Nachricht vor der Benachrichtigung behandelt wird.

Wenn eine WM_NOTIFY Nachricht gesendet wird, bietet das Steuerelement die erste Möglichkeit, sie zu verarbeiten. Wenn eine andere reflektierte Nachricht gesendet wird, hat das übergeordnete Fenster die erste Möglichkeit, sie zu behandeln, und das Steuerelement empfängt die angezeigte Nachricht. Dazu benötigen sie eine Handlerfunktion und einen entsprechenden Eintrag in der Klassennachrichtenzuordnung des Steuerelements.

Das Nachrichtenzuordnungsmakro für reflektierte Nachrichten unterscheidet sich geringfügig von den regulären Benachrichtigungen: Es wurde _REFLECT an den üblichen Namen angefügt. Um beispielsweise eine WM_NOTIFY Nachricht im übergeordneten Element zu behandeln, verwenden Sie das Makro ON_NOTIFY in der Nachrichtenzuordnung des übergeordneten Elements. Um die reflektierte Nachricht im untergeordneten Steuerelement zu behandeln, verwenden Sie das ON_NOTIFY_REFLECT Makro in der Nachrichtenzuordnung des untergeordneten Steuerelements. In einigen Fällen unterscheiden sich auch die Parameter. Beachten Sie, dass ClassWizard in der Regel die Nachrichtenzuordnungseinträge für Sie hinzufügen und Skelettfunktionsimplementierungen mit korrekten Parametern bereitstellen kann.

Informationen zur neuen WM_NOTIFY Nachricht finden Sie unter TN061: ON_NOTIFY und WM_NOTIFY Nachrichten .

Message-Map-Einträge und Handler-Funktionsprototypen für reflektierte Nachrichten

Verwenden Sie die in der folgenden Tabelle aufgeführten Makros und Funktionsprototypen, um eine reflektierte Steuerelementbenachrichtigung zu behandeln.

ClassWizard kann diese Nachrichtenzuordnungseinträge normalerweise für Sie hinzufügen und Skelettfunktionsimplementierungen bereitstellen. Informationen zum Definieren eines Nachrichtenhandlers für eine reflektierte Nachricht finden Sie unter Definieren von Handlern für reflektierte Nachrichten.

Um aus dem Nachrichtennamen in den widergespiegelten Makronamen zu konvertieren, stellen Sie ON_ voran, und fügen Sie _REFLECT an. Beispielsweise wird WM_CTLCOLOR ON_WM_CTLCOLOR_REFLECT. (Um zu sehen, welche Nachrichten angezeigt werden können, führen Sie die gegenteilige Konvertierung für die Makroeinträge in der nachstehenden Tabelle aus.)

Die drei Ausnahmen der obigen Regel lauten wie folgt:

  • Das Makro für WM_COMMAND Benachrichtigungen ist ON_CONTROL_REFLECT.

  • Das Makro für WM_NOTIFY Spiegelungen ist ON_NOTIFY_REFLECT.

  • Das Makro für ON_UPDATE_COMMAND_UI Spiegelungen ist ON_UPDATE_COMMAND_UI_REFLECT.

In jedem der oben genannten Sonderfälle müssen Sie den Namen der Handlerelementfunktion angeben. In den anderen Fällen müssen Sie den Standardnamen für die Handlerfunktion verwenden.

Die Bedeutungen der Parameter und Rückgabewerte der Funktionen werden entweder unter dem Funktionsnamen oder dem Funktionsnamen mit "Ein " dokumentiert. Beispiel: CtlColor ist dokumentiert in OnCtlColor. Mehrere reflektierte Nachrichtenhandler benötigen weniger Parameter als die ähnlichen Handler in einem übergeordneten Fenster. Stimmen Sie einfach die Namen in der nachstehenden Tabelle mit den Namen der formalen Parameter in der Dokumentation überein.

Karteneintrag Funktionsprototyp
ON_CONTROL_REFLECT(wNotifyCode;)memberFxn afx_msg voidmemberFxn( );
ON_NOTIFY_REFLECT(wNotifyCode;)memberFxn afx_msg voidmemberFxn( NMHDR*pNotifyStruct, LRESULT-Ergebnis);*
ON_UPDATE_COMMAND_UI_REFLECT(memberFxn) afx_msg voidmemberFxn( CCmdUI);*pCmdUI
ON_WM_CTLCOLOR_REFLECT( ) afx_msg HBRUSH CtlColor ( CDCpDC*, UINT);nCtlColor
ON_WM_DRAWITEM_REFLECT( ) afx_msg void DrawItem ( LPDRAWITEMSTRUCTlpDrawItemStruct);
ON_WM_MEASUREITEM_REFLECT( ) afx_msg void MeasureItem ( LPMEASUREITEMSTRUCTlpMeasureItemStruct);
ON_WM_DELETEITEM_REFLECT( ) afx_msg void DeleteItem ( LPDELETEITEMSTRUCTlpDeleteItemStruct);
ON_WM_COMPAREITEM_REFLECT( ) afx_msg int CompareItem ( LPCOMPAREITEMSTRUCTlpCompareItemStruct);
ON_WM_CHARTOITEM_REFLECT( ) afx_msg int CharToItem ( UINTnKey, UINT);nIndex
ON_WM_VKEYTOITEM_REFLECT( ) afx_msg int VKeyToItem ( UINTnKey, UINT);nIndex
ON_WM_HSCROLL_REFLECT( ) afx_msg void HScroll ( UINTnSBCode, UINT);nPos
ON_WM_VSCROLL_REFLECT( ) afx_msg void VScroll ( UINTnSBCode, UINT);nPos
ON_WM_PARENTNOTIFY_REFLECT( ) afx_msg void ParentNotify ( UINTmessage, LPARAM);lParam

Die ON_NOTIFY_REFLECT und ON_CONTROL_REFLECT Makros weisen Variationen auf, mit denen mehrere Objekte (z. B. das Steuerelement und das übergeordnete Objekt) eine bestimmte Nachricht verarbeiten können.

Karteneintrag Funktionsprototyp
ON_NOTIFY_REFLECT_EX(wNotifyCode;)memberFxn afx_msg BOOLmemberFxn( NMHDR*pNotifyStruct, LRESULT-Ergebnis);*
ON_CONTROL_REFLECT_EX(wNotifyCode;)memberFxn afx_msg BOOLmemberFxn( );

Behandeln reflektierter Nachrichten: Ein Beispiel für ein wiederverwendbares Steuerelement

In diesem einfachen Beispiel wird ein wiederverwendbares Steuerelement erstellt, das aufgerufen wird CYellowEdit. Das Steuerelement funktioniert genauso wie ein normales Bearbeitungssteuerelement, mit der Ausnahme, dass es schwarzen Text auf einem gelben Hintergrund anzeigt. Es wäre einfach, Memberfunktionen hinzuzufügen, mit denen das CYellowEdit Steuerelement unterschiedliche Farben anzeigen kann.

So versuchen Sie das Beispiel, das ein wiederverwendbares Steuerelement erstellt

  1. Erstellen Eines neuen Dialogfelds in einer vorhandenen Anwendung. Weitere Informationen finden Sie im Dialogfeld-Editor-Thema .

    Sie müssen über eine Anwendung verfügen, in der das wiederverwendbare Steuerelement entwickelt werden kann. Wenn Sie nicht über eine vorhandene Anwendung verfügen, erstellen Sie eine dialogbasierte Anwendung mit AppWizard.

  2. Wenn Ihr Projekt in Visual C++ geladen wurde, verwenden Sie ClassWizard, um eine neue Klasse CYellowEdit zu erstellen, die basierend auf CEdit.

  3. Fügen Sie Ihrer CYellowEdit Klasse drei Membervariablen hinzu. Die ersten beiden Variablen sind COLORREF-Variablen , die die Textfarbe und die Hintergrundfarbe enthalten. Der dritte ist ein CBrush Objekt, das den Pinsel zum Zeichnen des Hintergrunds hält. Mit CBrush dem Objekt können Sie den Pinsel einmal erstellen, lediglich darauf verweisen und den Pinsel automatisch zerstören, wenn das CYellowEdit Steuerelement zerstört wird.

  4. Initialisieren Sie die Membervariablen, indem Sie den Konstruktor wie folgt schreiben:

    CYellowEdit::CYellowEdit()
    {
        m_clrText = RGB(0, 0, 0);
        m_clrBkgnd = RGB(255, 255, 0);
        m_brBkgnd.CreateSolidBrush(m_clrBkgnd);
    }
    
  5. Fügen Sie mithilfe von ClassWizard einen Handler für die reflektierte WM_CTLCOLOR Nachricht zu Ihrer CYellowEdit Klasse hinzu. Beachten Sie, dass das Gleichheitszeichen vor dem Nachrichtennamen in der Liste der Nachrichten, die Sie behandeln können, angibt, dass die Nachricht angezeigt wird. Dies wird unter Definieren eines Nachrichtenhandlers für eine reflektierte Nachricht beschrieben.

    ClassWizard fügt die folgende Nachrichtenzuordnungsmakro- und -skelettfunktion für Sie hinzu:

    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;
    }
    
  6. Ersetzen Sie den Textkörper der Funktion durch den folgenden Code. Der Code gibt die Textfarbe, die Texthintergrundfarbe und die Hintergrundfarbe für das restliche Steuerelement an.

    pDC->SetTextColor(m_clrText);   // text
    pDC->SetBkColor(m_clrBkgnd);    // text bkgnd
    return m_brBkgnd;               // ctl bkgnd
    
  7. Erstellen Sie ein Bearbeitungssteuerelement in Ihrem Dialogfeld, und fügen Sie es dann an eine Membervariable an, indem Sie auf das Bearbeitungssteuerelement doppelklicken, während Sie eine Steuerelementtaste gedrückt halten. Schließen Sie im Dialogfeld "Membervariable hinzufügen" den Variablennamen ab, und wählen Sie "Steuerelement" für die Kategorie und dann "CYellowEdit" für den Variablentyp aus. Vergessen Sie nicht, die Aktivierreihenfolge im Dialogfeld festzulegen. Achten Sie außerdem darauf, die Headerdatei für das Steuerelement in die CYellowEdit Kopfzeilendatei Ihres Dialogfelds einzuschließen.

  8. Erstellen Sie Ihre Anwendung, und führen Sie sie aus. Das Bearbeitungssteuerelement verfügt über einen gelben Hintergrund.

Siehe auch

Technische Hinweise – nach Nummern geordnet
Technische Hinweise – nach Kategorien geordnet