Aracılığıyla paylaş


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, OnDestroyve 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.CArrayCMapCList 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.

BEGIN_TEMPLATE_MESSAGE_MAP
İleti İşleme ve Eşleme