Procedura: creare una mappa messaggi per una classe modello

Il mapping dei messaggi in MFC consente di indirizzare i messaggi di Windows a un'istanza di oggetto C++ appropriata. Esempi di destinazioni mappa messaggi MFC includono classi di applicazioni, classi di documento e visualizzazione, classi di controllo e così via.

Le mappe messaggi MFC tradizionali vengono dichiarate utilizzando la macro BEGIN_MESSAGE_MAP per dichiarare l'inizio della mappa messaggi, una voce di macro per ogni metodo di classe del gestore messaggi e infine la macro END_MESSAGE_MAP per dichiarare la fine della mappa messaggi.

Una limitazione della macro BEGIN_MESSAGE_MAP si verifica quando viene usata insieme a una classe contenente argomenti di modello. Se utilizzata con una classe modello, questa macro genererà un errore in fase di compilazione a causa dei parametri di modello mancanti durante l'espansione della macro. La macro BEGIN_TEMPLATE_MESSAGE_MAP è stata progettata per consentire alle classi contenenti un singolo argomento di modello di dichiarare le proprie mappe messaggi.

Esempio

Si consideri un esempio in cui la classe CListBox MFC viene estesa per fornire la sincronizzazione con un'origine dati esterna. La classe fittizia CSyncListBox viene dichiarata come segue:

// 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 CSyncListBox classe è basato su un singolo tipo che descrive l'origine dati con cui verrà sincronizzata. Dichiara inoltre tre metodi che faranno parte della mappa messaggi della classe : OnPaint, OnDestroye OnSynchronize. Il OnSynchronize metodo viene implementato nel modo seguente:

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

L'implementazione precedente consente alla CSyncListBox classe di essere specializzata in qualsiasi tipo di classe che implementa il GetCount metodo , ad esempio CArray, CListe CMap. La StringizeElement funzione è una funzione modello prototipo da quanto segue:

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

In genere, la mappa dei messaggi per questa classe viene definita come:

BEGIN_MESSAGE_MAP(CSyncListBox, CListBox)
  ON_WM_PAINT()
  ON_WM_DESTROY()
  ON_MESSAGE(LBN_SYNCHRONIZE, OnSynchronize)
END_MESSAGE_MAP()

dove LBN_SYNCHRONIZE è un messaggio utente personalizzato definito dall'applicazione, ad esempio:

#define LBN_SYNCHRONIZE (WM_USER + 1)

La mappa macro precedente non verrà compilata, a causa del fatto che la specifica del modello per la classe non sarà presente durante l'espansione CSyncListBox della macro. La macro BEGIN_TEMPLATE_MESSAGE_MAP risolve questo problema incorporando il parametro di modello specificato nella mappa macro espansa. La mappa dei messaggi per questa classe diventa:

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

Di seguito viene illustrato l'utilizzo di esempio della CSyncListBox classe usando un CStringList oggetto :

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

Per completare il test, la StringizeElement funzione deve essere specializzata per lavorare con la CStringList classe :

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
}

Vedi anche

BEGIN_TEMPLATE_MESSAGE_MAP
Gestione e mapping dei messaggi