Nasıl yapılır: Bir Şablon Sınıfı için İleti Eşlemesi Oluşturma
MFC'de ileti eşleme, Windows iletilerini uygun bir C++ nesne örneğine yönlendirmek için verimli bir yol sağlar. MFC ileti eşleme hedeflerine örnek olarak uygulama sınıfları, belge ve görünüm sınıfları, denetim sınıfları vb. verilebilir.
Geleneksel MFC ileti eşlemeleri, ileti eşlemesinin başlangıcını bildirmek için BEGIN_MESSAGE_MAP makro, her ileti işleyicisi sınıfı yöntemi için bir makro girişi ve son olarak ileti eşlemesinin sonunu bildirmek için END_MESSAGE_MAP makro kullanılarak bildirilir.
şablon bağımsız değişkenlerini içeren bir sınıfla birlikte kullanıldığında BEGIN_MESSAGE_MAP makroyla ilgili bir sınırlama oluşur. Şablon sınıfıyla kullanıldığında, bu makro, makro genişletme sırasında eksik şablon parametreleri nedeniyle derleme zamanı hatasına neden olur. BEGIN_TEMPLATE_MESSAGE_MAP makro, tek bir şablon bağımsız değişkeni içeren sınıfların kendi ileti eşlemelerini bildirmesine izin verecek şekilde tasarlanmıştır.
Örnek
Bir dış veri kaynağıyla eşitleme sağlamak için MFC CListBox sınıfının genişletildiği bir örneği düşünün. Kurgusal CSyncListBox
sınıf aşağıdaki gibi bildirilir:
// 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
};
CSyncListBox
sınıfı, eşitlenecek veri kaynağını tanımlayan tek bir tür üzerinde şablonlanır. Ayrıca sınıfının ileti eşlemesine katılacak üç yöntem de bildirir: OnPaint
, OnDestroy
ve OnSynchronize
. OnSynchronize
yöntemi aşağıdaki gibi uygulanır:
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;
}
Yukarıdaki uygulama, sınıfının , ve gibi yöntemini uygulayan herhangi bir sınıf türünde özelleştirilmesine GetCount
olanak tanırCSyncListBox
.CArray
CMap
CList
StringizeElement
İşlev, aşağıdakiler tarafından prototip olarak oluşturulan bir şablon işlevidir:
// Template function for converting an element within a collection
// to a CString object
template<typename CollectionT>
CString StringizeElement(CollectionT* pCollection, INT iIndex);
Normalde, bu sınıfın ileti eşlemesi şöyle tanımlanır:
BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()
burada LBN_SYNCHRONIZE , uygulama tarafından tanımlanan özel bir kullanıcı iletisidir, örneğin:
#define LBN_SYNCHRONIZE (WM_USER + 1)
Yukarıdaki makro eşlemesi, makro genişletme sırasında sınıfın şablon belirtiminin CSyncListBox
eksik olması nedeniyle derlenmez. BEGIN_TEMPLATE_MESSAGE_MAP makro, belirtilen şablon parametresini genişletilmiş makro eşlemesine ekleyerek bunu çözer. Bu sınıfın ileti eşlemesi şöyle olur:
BEGIN_TEMPLATE_MESSAGE_MAP(CSyncListBox, CollectionT, CListBox)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()
Aşağıda, bir CStringList
nesne kullanarak sınıfın CSyncListBox
örnek kullanımı gösterilmektedir:
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);
}
}
Testi tamamlamak için işlevin StringizeElement
sınıfıyla CStringList
çalışacak şekilde özelleşmiş olması gerekir:
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
}
Ayrıca bkz.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin