共用方式為


How to: Create a Message Map for a Template 類別

在 MFC 中的訊息對應提供有效率的方式,來指示 Windows 訊息至適當的 C++ 物件執行個體。 MFC 訊息對應目標的範例包括應用程式類別、 文件和檢視類別、 控制項類別等等。

使用宣告傳統 MFC 訊息對應BEGIN_MESSAGE_MAP巨集來宣告開頭的訊息對應,而每個訊息處理常式類別方法,一個巨集項目,最後END_MESSAGE_MAP來宣告最後的訊息對應巨集。

有一個限制BEGIN_MESSAGE_MAP與包含的樣板引數類別一起使用時,就會發生巨集。 與樣板類別使用時,此巨集會導致編譯時期錯誤,遺漏的範本參數受限於巨集展開時。 BEGIN_TEMPLATE_MESSAGE_MAP巨集為了讓類別,其中內含單一樣板引數宣告他們自己的訊息對應。

範例

請試想,MFC CListBox 類別會擴充以提供與外部資料來源的同步處理。 虛構 CSyncListBox 類別宣告,如下所示:

// 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 類別是樣板化對於單一型別,描述會同步處理與資料來源。 它也宣告了三種方法,將加入訊息對應的類別: OnPaintOnDestroy,以及 OnSynchronizeOnSynchronize 方法實作,如下所示:

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;
}

上述的實作允許 CSyncListBox 類別會實作任何類別型別上特殊化 GetCount 方法,例如 CArrayCList,和 CMapStringizeElement 函式是由下列原型成為樣板函式:

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

一般情況下,這個類別的訊息對應會定義為:

BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)

ON_WM_PAINT()

ON_WM_DESTROY()

ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)

END_MESSAGE_MAP()

其中 LBN_SYNCHRONIZE 是由應用程式,例如定義的自訂使用者訊息:

#define LBN_SYNCHRONIZE (WM_USER + 1)

上述的巨集對應不會進行編譯,因為用樣板規格的 CSyncListBox 巨集展開時,類別將會遺失。 BEGIN_TEMPLATE_MESSAGE_MAP 巨集可以解決這透過展開的巨集對應至加入指定的樣板參數。 這個類別的訊息對應會變成:

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

下列示範範例用法的 CSyncListBox 類別使用 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);
   }
}

若要完成本測試中, StringizeElement 函式必須專門用來處理 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
}

請參閱

參考

BEGIN_TEMPLATE_MESSAGE_MAP

概念

訊息處理和對應