Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Mapování zpráv v prostředí MFC poskytuje efektivní způsob, jak směrovat zprávy systému Windows na příslušnou instanci objektu C++. Mezi příklady cílů mapování zpráv MFC patří třídy aplikací, třídy dokumentů a zobrazení, třídy ovládacích prvků atd.
Tradiční mapy zpráv MFC jsou deklarovány pomocí makra BEGIN_MESSAGE_MAP deklarovat začátek mapy zpráv, položku makra pro každou metodu třídy obslužné rutiny zpráv a nakonec makro END_MESSAGE_MAP deklarovat konec mapy zpráv.
Jedno omezení s BEGIN_MESSAGE_MAP makrem nastane, když se používá ve spojení s třídou obsahující argumenty šablony. Při použití s třídou šablony způsobí toto makro chybu v době kompilace kvůli chybějícím parametrům šablony během rozšíření makra. Makro BEGIN_TEMPLATE_MESSAGE_MAP bylo navrženo tak, aby umožňovalo třídám obsahujícím jeden argument šablony deklarovat vlastní mapy zpráv.
Příklad
Představte si příklad, ve kterém je třída MFC CListBox rozšířena tak, aby poskytovala synchronizaci s externím zdrojem dat. Fiktivní CSyncListBox třída je deklarována takto:
// 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
};
Třída CSyncListBox je šablonována pro jediný typ, který určuje zdroj dat, s nímž se bude synchronizovat. Také deklaruje tři metody, které se budou účastnit mapy zpráv třídy: OnPaint, OnDestroya OnSynchronize. Metoda OnSynchronize se implementuje takto:
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;
}
Výše uvedená implementace umožňuje CSyncListBox , aby třída byla specializovaná na jakýkoli typ třídy, který implementuje metodu GetCount , například CArray, CLista CMap. Funkce StringizeElement je prototyp funkce šablony s následujícími funkcemi:
// Template function for converting an element within a collection
// to a CString object
template<typename CollectionT>
CString StringizeElement(CollectionT* pCollection, INT iIndex);
Za normálních okolností by mapa zpráv pro tuto třídu byla definována takto:
BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()
kde LBN_SYNCHRONIZE je vlastní uživatelská zpráva definovaná aplikací, například:
#define LBN_SYNCHRONIZE (WM_USER + 1)
Výše uvedená mapa maker se nezkompiluje, protože během rozšíření makra chybí specifikace šablony pro CSyncListBox třídu. Makro BEGIN_TEMPLATE_MESSAGE_MAP to řeší zahrnutím zadaného parametru šablony do expandované makro mapy. Mapa zpráv pro tuto třídu se stane:
BEGIN_TEMPLATE_MESSAGE_MAP(CSyncListBox, CollectionT, CListBox)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()
Následující ukázka demonstruje využití třídy CSyncListBox pomocí objektu CStringList:
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);
}
}
Aby bylo možné dokončit test, funkci StringizeElement je nutné specializovat pro práci s třídou CStringList.
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
}