Compartir a través de


How to: Create a Message Map for a Template (Clase)

Asignación de mensajes en MFC proporciona una manera eficaz de tratar los mensajes de Windows en una instancia de objeto adecuada de C++. Los ejemplos de mapa de mensajes MFC incluyen clases de la aplicación, el documento y las clases de vista, clases de control, y así sucesivamente.

Los mapas tradicionales de mensajes MFC se declaran con la macro de BEGIN_MESSAGE_MAP para declarar el inicio del mapa de mensajes, entrada de macro para cada método de la clase de controlador de mensajes, y por último de la macro de END_MESSAGE_MAP de declarar el final del mapa de mensajes.

Una limitación con la macro de BEGIN_MESSAGE_MAP aparece cuando se utiliza junto con una clase que contiene los argumentos de plantilla. Cuando se utiliza con una clase de plantilla, esta macro producirá un error en tiempo de compilación debido a los parámetros que faltan de plantilla durante la expansión de macro. La macro de BEGIN_TEMPLATE_MESSAGE_MAP está diseñada para permitir las clases que contienen un solo argumento de plantilla para declarar mapas de mensajes.

Ejemplo

Considere un ejemplo donde la clase MFC CListBox se extiende para proporcionar la sincronización con un origen de datos externo. Se declara la clase ficticia de CSyncListBox como sigue:

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

La clase de CSyncListBox plantilla en un tipo único que describe el origen de datos que se sincronizará con. También declara tres métodos que participan en el mapa de mensajes de la clase: OnPaint, OnDestroy, y OnSynchronize. Se implementa el método de OnSynchronize como sigue:

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

La implementación anterior permite que la clase de CSyncListBox sea especializada en cualquier tipo de clase que implemente el método de GetCount , como CArray, CList, y CMap. La función de StringizeElement es una función de plantilla prototipo mediante:

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

Normalmente, el mapa de mensajes para esta clase se definiría como:

BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)

ON_WM_PAINT()

ON_WM_DESTROY()

ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)

END_MESSAGE_MAP()

donde es un mensaje LBN_SYNCHRONIZE de usuario personalizado definido por la aplicación, por ejemplo:

#define LBN_SYNCHRONIZE (WM_USER + 1)

El mapa anterior de la macro no se compilará, debido al hecho de que la especificación de plantilla para la clase de CSyncListBox faltará durante la expansión de macro. La macro de BEGIN_TEMPLATE_MESSAGE_MAP soluciona esto especificando el parámetro de plantilla especificado en el mapa expandida de la macro. El mapa de mensajes para esta clase se convierte en:

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

A continuación se muestra el ejemplo del uso de la clase de CSyncListBox utilizando un objeto de 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);
   }
}

Para completar la prueba, la función de StringizeElement debe especializar para trabajar con la clase de 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
}

Vea también

Referencia

BEGIN_TEMPLATE_MESSAGE_MAP

Conceptos

Controlar y asignar mensajes