Condividi tramite


Procedura: creare una mappa messaggi per una classe modello

Il mapping del messaggio in MFC fornisce un modo efficace per indirizzare i messaggi di windows a un'istanza di oggetto appropriata di C++. Esempi delle destinazioni della mappa messaggi MFC includono le classi delle classi di applicazione, di documento e di visualizzazione, classi di controlli, e così via.

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

Una limitazione con la macro di BEGIN_MESSAGE_MAP si verifica quando viene utilizzata insieme A una classe contenente gli argomenti di modello. Una volta utilizzata con una classe template, questa macro genera un errore in fase di compilazione a causa dei parametri di modello mancanti durante l'espansione della macro. La macro di BEGIN_TEMPLATE_MESSAGE_MAP è stata progettata per consentire le classi che contengono un solo argomento di template per dichiarare le rispettive mappe messaggi.

Esempio

Si consideri un esempio in cui la classe MFC CListBox viene estesa per fornire la sincronizzazione con un'origine dati esterna. La classe fittizia di 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 classe di CSyncListBox è basata su modelli in un unico tipo che descrive l'origine dati che verrà sincronizzata con. Anche dichiara tre metodi che prenderanno parte alla mappa messaggi della classe: OnPaint, OnDestroy e OnSynchronize. Il metodo di OnSynchronize viene implementato come segue:

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 sopra riportato consente la classe di CSyncListBox di rendere specifico a qualsiasi tipo di classe che implementa il metodo di GetCount, come CArray, CList e su CMap. La funzione di StringizeElement è una funzione di modello con 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 messaggi per questa classe è definita come segue:

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 macro mappa sopraindicato non viene compilato, dovuto al fatto che la specifica del modello per la classe di CSyncListBox risulterà durante l'espansione della macro. La macro di BEGIN_TEMPLATE_MESSAGE_MAP risolve questa incorporando il parametro di modello specificato nella mappa macro espansa. La mappa 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 classe di CSyncListBox utilizzo di un oggetto di 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);
   }
}

Per completare il test, la funzione di StringizeElement deve essere specializzata per utilizzare la classe di 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
}

Vedere anche

Riferimenti

BEGIN_TEMPLATE_MESSAGE_MAP

Concetti

Gestione e mapping dei messaggi