Gewusst wie: Erstellen einer Meldungszuordnung für eine Vorlagenklasse
Meldungszuordnung in MFC bietet eine effiziente Möglichkeit, Windows-Meldungen auf eine entsprechende C++-Objektinstanz zu verweisen. Beispiele für MFC-Meldungszuordnungszielen enthalten Anwendungsklassen, Dokument und Ansichtsklassen, Steuerelementklassen, u. a.
Herkömmliche MFC-Meldungszuordnungen werden mithilfe des Makros BEGIN_MESSAGE_MAP deklariert, um den Anfang der Meldungszuordnung, einen Makroeintrag für jede Meldungshandlerklassenmethode, und das END_MESSAGE_MAP-Makro deklarieren, das Ende der Meldungszuordnung schließlich zu deklarieren.
Eine Einschränkung mit dem Makro BEGIN_MESSAGE_MAP tritt auf, wenn sie in Verbindung mit einer Klasse verwendet wird, müssen die Vorlagenargumente enthält. Wenn es einer Vorlagenklasse verwendet wird, führt dieses Makro einen Kompilierungsfehler aufgrund von fehlenden Vorlagenparameter während der Erweiterung. Das Makro BEGIN_TEMPLATE_MESSAGE_MAP wurde entworfen, um die Klassen zu erstellen, die ein einzelnes Vorlagenargument enthalten, eigene Meldungszuordnungen zu deklarieren.
Beispiel
Betrachten Sie ein Beispiel, in dem die Klasse MFC- CListBox erweitert wird, um die Synchronisierung mit einer externen Datenquelle bereitgestellt. Die fiktive CSyncListBox-Klasse deklariert ist, wie folgt:
// 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
};
Die CSyncListBox-Klasse basiert auf einem einzelnen Typ vorlagenbasiert, der die Datenquelle, die beschreibt, sie mit synchronisiert. Es deklariert auch drei Methoden, die in der Meldungszuordnung der Klasse einbezogen werden: OnPaint, OnDestroy und OnSynchronize. Die OnSynchronize-Methode wird implementiert, wie folgt:
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;
}
Die obige Implementierung können die in einem Klassentyp, der die GetCount-Methode, wie CArray, CList implementiert, und CMap spezialisiert werden CSyncListBox-Klasse. Die StringizeElement-Funktion ist eine Vorlagenfunktion, die durch Folgendes einen Prototyp entwickelt wird:
// Template function for converting an element within a collection
// to a CString object
template<typename CollectionT>
CString StringizeElement(CollectionT* pCollection, INT iIndex);
Normalerweise würde die Meldungszuordnung für diese Klasse folgendermaßen definiert:
BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()
bei LBN_SYNCHRONIZE eine benutzerdefinierte Benutzermeldung ist, die von der Anwendung definiert ist, z:
#define LBN_SYNCHRONIZE (WM_USER + 1)
Die oben aufgeführten Makrozuordnung kompiliert, nicht aufgrund der Tatsache, den die Vorlagenspezifikation für die CSyncListBox-Klasse während der Makroerweiterung fehlen wird. Das Makro BEGIN_TEMPLATE_MESSAGE_MAP löst dies, indem den angegebenen Vorlagenparameter in die erweiterte Makrozuordnung integriert. Die Meldungszuordnung für diese Klasse wird:
BEGIN_TEMPLATE_MESSAGE_MAP(CSyncListBox, CollectionT, CListBox)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()
Im Folgenden wird veranschaulicht Beispielverwendung der CSyncListBox-Klasse mithilfe eines CStringList-Objekts:
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);
}
}
Um den Test abzuschließen, muss die StringizeElement-Funktion spezialisiert werden mit der CStringList-Klasse funktionieren:
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
}