Dela via


TN062: Meddelandereflektion för Windows-kontroller

Anmärkning

Följande tekniska anmärkning har inte uppdaterats sedan den först inkluderades i onlinedokumentationen. Därför kan vissa procedurer och ämnen vara inaktuella eller felaktiga. För den senaste informationen rekommenderar vi att du söker efter det intressanta ämnet i onlinedokumentationsindexet.

Den här tekniska anmärkningen beskriver meddelandereflektion, en ny funktion i MFC 4.0. Den innehåller också anvisningar för att skapa en enkel återanvändbar kontroll som använder meddelandereflektion.

Den här tekniska anmärkningen beskriver inte meddelandereflektion eftersom den gäller för ActiveX-kontroller (kallades tidigare OLE-kontroller). Vänligen läs artikeln ActiveX-kontroller: Underklassning av en Windows-kontroll.

Vad är meddelandereflektion

Windows-kontroller skickar ofta meddelanden till sina överordnade fönster. Många kontroller skickar till exempel ett meddelande om kontrollfärg (WM_CTLCOLOR eller någon av dess varianter) till sina överordnade så att den överordnade enheten kan ange en pensel för att måla kontrollens bakgrund.

I Windows och I MFC före version 4.0 ansvarar det överordnade fönstret, ofta en dialogruta, för att hantera dessa meddelanden. Det innebär att koden för att hantera meddelandet måste finnas i det överordnade fönstrets klass och att den måste dupliceras i varje klass som behöver hantera meddelandet. I fallet ovan skulle varje dialogruta som ville ha kontroller med anpassade bakgrunder behöva hantera meddelandet om kontrollfärgmeddelanden. Det skulle vara mycket enklare att återanvända kod om en kontrollklass kunde skrivas som skulle hantera sin egen bakgrundsfärg.

I MFC 4.0 fungerar den gamla mekanismen fortfarande – överordnade fönster kan hantera meddelanden. Dessutom underlättar dock MFC 4.0 återanvändning genom att tillhandahålla en funktion som kallas "meddelandereflektion" som gör att dessa meddelanden kan hanteras i antingen det underordnade kontrollfönstret eller det överordnade fönstret eller i båda. I exemplet med kontrollens bakgrundsfärg kan du nu skriva en kontrollklass som själv ställer in sin bakgrundsfärg genom att hantera det reflekterade WM_CTLCOLOR-meddelandet – helt utan att förlita dig på föräldrakontrollen. (Observera att eftersom meddelandereflektion implementeras av MFC, inte av Windows, måste den överordnade fönsterklassen härledas från CWnd för att meddelandereflektion ska fungera.)

Äldre versioner av MFC gjorde något liknande meddelandereflektion genom att tillhandahålla virtuella funktioner för några meddelanden, till exempel meddelanden för egenritade listrutor (WM_DRAWITEM, och så vidare). Den nya mekanismen för meddelandereflektion är generaliserad och konsekvent.

Meddelandereflektion är bakåtkompatibel med kod som skrivits för versioner av MFC före 4.0.

Om du har angett en hanterare för ett visst meddelande, eller för ett antal meddelanden, i det överordnade fönstrets klass, åsidosätter den reflekterade meddelandehanterare för samma meddelande förutsatt att du inte anropar basklasshanterarfunktionen i din egen hanterare. Om du till exempel hanterar WM_CTLCOLOR i din dialogruteklass åsidosätter hanteringen eventuella reflekterade meddelandehanterare.

Om du i den överordnade fönsterklassen anger en hanterare för ett visst WM_NOTIFY meddelande eller ett intervall med WM_NOTIFY meddelanden anropas hanteraren endast om den underordnade kontrollen som skickar dessa meddelanden inte har en reflekterad meddelandehanterare via ON_NOTIFY_REFLECT(). Om du använder ON_NOTIFY_REFLECT_EX() i meddelandekartan kan meddelandehanteraren tillåta eller inte tillåta att det överordnade fönstret hanterar meddelandet. Om hanteraren returnerar FALSE hanteras även meddelandet av den överordnade, medan ett anrop som returnerar TRUE inte tillåter att det överordnade objektet hanterar det. Observera att det reflekterade meddelandet hanteras före notifikationsmeddelandet.

När ett WM_NOTIFY meddelande skickas erbjuds kontrollen den första chansen att hantera det. Om något annat reflekterat meddelande skickas har det överordnade fönstret den första chansen att hantera det och kontrollen tar emot det reflekterade meddelandet. För att göra det behöver den en hanteringsfunktion och en lämplig post i klassens meddelandekarta för kontrollen.

Makrot för meddelandekartan för reflekterade meddelanden skiljer sig något från vanliga meddelanden: det har _REFLECT lagts till i sitt vanliga namn. Om du till exempel vill hantera ett WM_NOTIFY meddelande i det överordnade objektet använder du makrot ON_NOTIFY i den överordnade meddelandekartan. Om du vill hantera det reflekterade meddelandet i barnkontrollen, använder du makrot ON_NOTIFY_REFLECT i barnkontrollens meddelandekarta. I vissa fall är parametrarna också olika. Observera att ClassWizard vanligtvis kan lägga till posterna för meddelandekartan åt dig och tillhandahålla implementeringar av skelettfunktioner med rätt parametrar.

Mer information om det nya WM_NOTIFY meddelandet finns i TN061: ON_NOTIFY och WM_NOTIFY Meddelanden .

Message-Map Inlägg och hanterings- och funktionsprototyper för reflekterade meddelanden

Om du vill hantera ett meddelande om reflekterad kontroll använder du makron för meddelandekartan och funktionsprototyperna som anges i tabellen nedan.

ClassWizard kan vanligtvis lägga till dessa posterna för meddelandekartan åt dig och tillhandahålla implementeringar av skelettfunktioner. Se Definiera en meddelandehanterare för ett reflekterat meddelande för information om hur du definierar hanterare för reflekterade meddelanden.

För att konvertera från meddelandenamnet till det reflekterade makronamnet, föregå det med ON_ och lägg till _REFLECT. Till exempel blir WM_CTLCOLOR ON_WM_CTLCOLOR_REFLECT. (Om du vill se vilka meddelanden som kan återspeglas gör du den motsatta konverteringen på makroposterna i tabellen nedan.)

De tre undantagen till regeln ovan är följande:

  • Makrot för WM_COMMAND meddelanden är ON_CONTROL_REFLECT.

  • Makrot för WM_NOTIFY reflektioner är ON_NOTIFY_REFLECT.

  • Makrot för ON_UPDATE_COMMAND_UI reflektioner är ON_UPDATE_COMMAND_UI_REFLECT.

I vart och ett av ovanstående specialfall måste du ange namnet på hanteringsmedlemsfunktionen. I andra fall måste du använda standardnamnet för hanteringsfunktionen.

Innebörden av parametrarna och returvärdena för funktionerna dokumenteras under antingen funktionsnamnet eller funktionsnamnet som inleds med . Till exempel CtlColor dokumenteras i OnCtlColor. Flera reflekterade meddelandehanterare behöver färre parametrar än liknande hanterare i ett överordnat fönster. Matcha bara namnen i tabellen nedan med namnen på de formella parametrarna i dokumentationen.

Kartpost Funktionsprototyp
ON_CONTROL_REFLECT(wNotifyCode,memberFxn) afx_msg tomrummemberFxn( );
ON_NOTIFY_REFLECT(wNotifyCode,memberFxn) afx_msg tomrummemberFxn( NMHDR*pNotifyStruct, LRESULT*resultat);
ON_UPDATE_COMMAND_UI_REFLECT(memberFxn) afx_msg tomrummemberFxn( CCmdUI*pCmdUI);
ON_WM_CTLCOLOR_REFLECT( ) afx_msg HBRUSH CtlColor ( CDC*pDC, UINTnCtlColor);
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, UINTnIndex);
ON_WM_VKEYTOITEM_REFLECT( ) afx_msg int VKeyToItem (UINTnKey, UINTnIndex);
ON_WM_HSCROLL_REFLECT( ) afx_msg void HScroll ( UINTnSBCode, UINTnPos);
ON_WM_VSCROLL_REFLECT( ) afx_msg void VScroll ( UINTnSBCode, UINTnPos);
ON_WM_PARENTNOTIFY_REFLECT( ) afx_msg void ParentNotify ( UINTmessage, LPARAMlParam);

Makrona ON_NOTIFY_REFLECT och ON_CONTROL_REFLECT har varianter som gör att fler än ett objekt (till exempel kontrollen och dess överordnade) kan hantera ett visst meddelande.

Kartpost Funktionsprototyp
ON_NOTIFY_REFLECT_EX(wNotifyCode,memberFxn) afx_msg BOOLmemberFxn( NMHDR*pNotifyStruct, LRESULT*resultat);
ON_CONTROL_REFLECT_EX(wNotifyCode,memberFxn) afx_msg BOOLmemberFxn( );

Hantering av reflekterade meddelanden: Ett exempel på en återanvändbar kontroll

Det här enkla exemplet skapar en återanvändbar kontroll med namnet CYellowEdit. Kontrollen fungerar på samma sätt som en vanlig redigeringskontroll, förutom att den visar svart text i en gul bakgrund. Det skulle vara enkelt att lägga till medlemsfunktioner som gör att CYellowEdit kontrollen kan visa olika färger.

Prova exemplet som skapar en återanvändbar kontroll

  1. Skapa en ny dialogruta i ett befintligt program. Mer information finns i avsnittet om dialogredigeraren .

    Du måste ha ett program där du kan utveckla den återanvändbara kontrollen. Om du inte har ett befintligt program att använda skapar du ett dialogbaserat program med AppWizard.

  2. När projektet har lästs in i Visual C++använder du ClassWizard för att skapa en ny klass med namnet CYellowEdit baserat på CEdit.

  3. Lägg till tre medlemsvariabler i klassen CYellowEdit . De två första är COLORREF-variabler som innehåller textfärgen och bakgrundsfärgen. Den tredje blir ett CBrush objekt som håller penseln för att måla bakgrunden. Med CBrush objektet kan du skapa penseln en gång, bara referera till den efter det och förstöra borsten automatiskt när CYellowEdit kontrollen förstörs.

  4. Initiera medlemsvariablerna genom att skriva konstruktorn på följande sätt:

    CYellowEdit::CYellowEdit()
    {
        m_clrText = RGB(0, 0, 0);
        m_clrBkgnd = RGB(255, 255, 0);
        m_brBkgnd.CreateSolidBrush(m_clrBkgnd);
    }
    
  5. Med Hjälp av ClassWizard lägger du till en hanterare för det reflekterade WM_CTLCOLOR meddelandet i klassen CYellowEdit . Observera att likhetstecknet framför meddelandenamnet i listan över meddelanden som du kan hantera anger att meddelandet återspeglas. Detta beskrivs i Definiera en meddelandehanterare för ett reflekterat meddelande.

    ClassWizard lägger till följande message-map-makro och skelettfunktion åt dig:

    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. Ersätt funktionens brödtext med följande kod. Koden anger textfärgen, textbakgrundsfärgen och bakgrundsfärgen för resten av kontrollen.

    pDC->SetTextColor(m_clrText);   // text
    pDC->SetBkColor(m_clrBkgnd);    // text bkgnd
    return m_brBkgnd;               // ctl bkgnd
    
  7. Skapa en redigeringskontroll i dialogrutan och koppla den sedan till en medlemsvariabel genom att dubbelklicka på redigeringskontrollen medan du håller ned en kontrollnyckel. I dialogrutan Lägg till medlemsvariabel avslutar du variabelnamnet och väljer "Kontroll" för kategorin och sedan "CYellowEdit" för variabeltypen. Glöm inte att ange tabbordningen i dialogrutan. Se också till att inkludera rubrikfilen för CYellowEdit kontrollen i dialogrutans huvudfil.

  8. Skapa och kör ditt program. Redigeringskontrollen har en gul bakgrund.

Se även

tekniska anteckningar efter nummer
tekniska anteckningar efter kategori