다음을 통해 공유


방법: 템플릿 클래스에 대한 메시지 맵 만들기

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 클래스는 동기화할 데이터 원본을 설명하는 단일 형식에 템플릿으로 지정됩니다. 또한 클래스의 메시지 맵에 참여할 세 가지 OnPaintOnDestroyOnSynchronize메서드를 선언합니다. 메서드 OnSynchronize 는 다음과 같이 구현됩니다.

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 구현하는 모든 클래스 형식(예: CArray, CListCMap)에서 클래스를 특수화 GetCount 할 수 있습니다. 이 StringizeElement 함수는 다음에 의해 프로토타입화된 템플릿 함수입니다.

// 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()

다음은 개체를 사용하는 CStringList 클래스의 CSyncListBox 샘플 사용 방법을 보여 줍니다.

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
메시지 처리 및 매핑