Delen via


Procedure: Een berichtoverzicht maken voor een sjabloonklasse

Berichttoewijzing in MFC biedt een efficiënte manier om Windows-berichten te verwijzen naar een geschikt C++-objectexemplaar. Voorbeelden van MFC-berichttoewijzingsdoelen zijn toepassingsklassen, document en weergaveklassen, besturingsklassen, enzovoort.

Traditionele MFC-berichttoewijzingen worden gedeclareerd met behulp van de BEGIN_MESSAGE_MAP macro om het begin van de berichtkaart te declareren, een macro-item voor elke berichthandlerklassemethode en ten slotte de END_MESSAGE_MAP macro om het einde van de berichtkaart te declareren.

Een beperking met de BEGIN_MESSAGE_MAP macro treedt op wanneer deze wordt gebruikt in combinatie met een klasse met sjabloonargumenten. Wanneer deze macro wordt gebruikt met een sjabloonklasse, veroorzaakt deze macro een compilatietijdfout vanwege de ontbrekende sjabloonparameters tijdens de macro-uitbreiding. De BEGIN_TEMPLATE_MESSAGE_MAP macro is ontworpen voor klassen met een enkel sjabloonargument om hun eigen berichtkaarten te declareren.

Voorbeeld

Bekijk een voorbeeld waarbij de MFC CListBox-klasse wordt uitgebreid om synchronisatie met een externe gegevensbron te bieden. De fictieve CSyncListBox klasse wordt als volgt gedeclareerd:

// Extends the CListBox class to provide synchronization with 
// an external data source
template <typename CollectionT>
class CSyncListBox : public CListBox
{
public:
   CSyncListBox();
   virtual ~CSyncListBox();

   afx_msg void OnPaint();
   afx_msg void OnDestroy();
   afx_msg LRESULT OnSynchronize(WPARAM wParam, LPARAM lParam);
   DECLARE_MESSAGE_MAP()

   // ...additional functionality as needed
};

De CSyncListBox klasse is gebaseerd op één type dat de gegevensbron beschrijft waarmee wordt gesynchroniseerd. Het declareert ook drie methoden die deelnemen aan de berichtkaart van de klasse: OnPaint, OnDestroyen OnSynchronize. De OnSynchronize methode wordt als volgt geïmplementeerd:

template <class CollectionT>
LRESULT CSyncListBox<CollectionT>::OnSynchronize(WPARAM, LPARAM lParam)
{
   CollectionT* pCollection = (CollectionT*)(lParam);

   ResetContent();

   if (pCollection != NULL)
   {
      INT nCount = (INT)pCollection->GetCount();
      for (INT n = 0; n < nCount; n++)
      {
         CString s = StringizeElement(pCollection, n);
         AddString(s);
      }
   }

   return 0L;
}

Met de bovenstaande implementatie kan de CSyncListBox klasse worden gespecialiseerd op elk klassetype dat de GetCount methode implementeert, zoals CArray, CListen CMap. De StringizeElement functie is een sjabloonfunctie die als prototype is gemaakt door het volgende:

// Template function for converting an element within a collection
// to a CString object
template<typename CollectionT>
CString StringizeElement(CollectionT* pCollection, INT iIndex);

Meestal zou de berichttoewijzing voor deze klasse worden gedefinieerd als:

BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)
  ON_WM_PAINT()
  ON_WM_DESTROY()
  ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()

waarbij LBN_SYNCHRONIZE een aangepast gebruikersbericht is dat door de toepassing is gedefinieerd, zoals:

#define LBN_SYNCHRONIZE (WM_USER + 1)

De bovenstaande macromap zal niet worden gecompileerd, omdat de sjabloonspecificatie voor de CSyncListBox klasse ontbreekt tijdens de macro-uitbreiding. De BEGIN_TEMPLATE_MESSAGE_MAP macro lost dit op door de opgegeven sjabloonparameter te integreren in de uitgevouwen macrokaart. Het berichtenoverzicht voor deze klasse wordt:

BEGIN_TEMPLATE_MESSAGE_MAP(CSyncListBox, CollectionT, CListBox)
   ON_WM_PAINT()
   ON_WM_DESTROY()
   ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
   END_MESSAGE_MAP()

Hieronder ziet u een voorbeeld van het gebruik van de CSyncListBox klasse met behulp van een CStringList object:

void CSyncListBox_Test(CWnd* pParentWnd)
{
   CSyncListBox<CStringList> ctlStringLB;
   ctlStringLB.Create(WS_CHILD | WS_VISIBLE | LBS_STANDARD | WS_HSCROLL,
      CRect(10, 10, 200, 200), pParentWnd, IDC_MYSYNCLISTBOX);

   // Create a CStringList object and add a few strings
   CStringList stringList;
   stringList.AddTail(_T("A"));
   stringList.AddTail(_T("B"));
   stringList.AddTail(_T("C"));

   // Send a message to the list box control to synchronize its
   // contents with the string list
   ctlStringLB.SendMessage(LBN_SYNCHRONIZE, 0, (LPARAM)& stringList);

   // Verify the contents of the list box by printing out its contents
   INT nCount = ctlStringLB.GetCount();
   for (INT n = 0; n < nCount; n++)
   {
      TCHAR szText[256];
      ctlStringLB.GetText(n, szText);
      TRACE(_T("%s\n"), szText);
   }
}

Om de test te voltooien, moet de StringizeElement functie speciaal zijn om met de CStringList klasse te kunnen werken:

template<>
CString StringizeElement(CStringList* pStringList, INT iIndex)
{
   if (pStringList != NULL && iIndex < pStringList->GetCount())
   {
      POSITION pos = pStringList->GetHeadPosition();
      for (INT i = 0; i < iIndex; i++)
      {
         pStringList->GetNext(pos);
      }
      return pStringList->GetAt(pos);
   }
   return CString(); // or throw, depending on application requirements
}

Zie ook

BEGIN_TEMPLATE_MESSAGE_MAP
Berichtafhandeling en toewijzing