TN006: Mapas de mensagem
Esta nota descreve o recurso de MAP de mensagem MFC.
O problema
Microsoft Windows implementa funções virtual em classes de janela que usam seu recurso de sistema de sistema sistema de mensagens.Devido ao grande número de mensagens envolvidos, fornecendo uma função virtual separada para cada mensagem de Windows criaria uma vtable excessivamente grande.
Porque o número de mensagens definidas pelo sistema do Windows muda ao longo do time e mapas de mensagem porque os aplicativos podem definir suas próprias mensagens do Windows, fornecem um nível de indireção que impede alterações na interface de quebra de código existente.
Visão Geral
MFC fornece uma alternativa para a demonstrativo comutador que foi usada no tradicionais programas baseados no baseado no Windows para lidar com as mensagens enviadas para uma janela.Um mapeamento de mensagens para métodos pode ser definido para que quando uma mensagem é recebida por uma janela, o método apropriado é chamado automaticamente.Esse recurso de MAP da mensagem foi projetado para se parecer com funções virtual mas tem benefícios adicionais não é possíveis com funções virtual do C++.
Definindo um MAP de mensagens
The DECLARE_MESSAGE_MAP macro declara três membros para uma classe.
Um conjunto particular de AFX_MSGMAP_ENTRY entradas chamadas _messageEntries.
Um protegido AFX_MSGMAP estrutura de chamada messageMap que aponta para o _messageEntries matriz.
Uma função virtual protegida chamado GetMessageMap que retorna o endereço do messageMap.
Essa macro deve ser colocada na declaração de qualquer classe usando mapas de mensagem.Por convenção, ele está no participante da declaração da classe.Por exemplo:
class CMyWnd : public CMyParentWndClass
{
// my stuff...
protected:
//{{AFX_MSG(CMyWnd)
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Este é o formato gerado por AppWizard e ClassWizard ao criarem novas classes.O / / {{e / /}} colchetes são necessários para ClassWizard.
Tabela do MAP da mensagem é definida usando um conjunto de macros que se expandem para entradas de MAP da mensagem.Uma tabela começa com um BEGIN_MESSAGE_MAP telefonar de macro, que define a classe que é tratada por esse MAP da mensagem e a classe pai ao qual as mensagens sem tratamento são passadas. A tabela termina com o END_MESSAGE_MAP macro telefonar.
Entre essas duas macro chamadas é uma entrada para cada mensagem deve ser tratado por este MAP da mensagem.Cada mensagem padrão do Windows tenha uma macro do formulário ON_WM_ MESSAGE_NAME que gera uma entrada para essa mensagem.
Uma assinatura de função padrão tiver sido definida para descompactar os parâmetros de cada mensagem do Windows e fornecendo segurança de tipos.Essas assinaturas podem ser encontradas no arquivo Afxwin.h na declaração de CWnd.Cada um deles é marcado com a palavra-chave afx_msg para facilitar a identificação.
Observação: |
---|
ClassWizard exige que você use o afx_msg palavra-chave em suas declarações de manipulador de MAP de mensagem. |
Essas assinaturas de função foram geradas através de uma convenção simples.O nome da função sempre começa com "On". Isso é seguido o nome da mensagem do Windows com o "WM_" removido e a primeira letra de cada palavra em maiúsculas.A ordem dos parâmetros é wParam seguido por LOWORD(lParam), em seguida, HIWORD(lParam). Parâmetros não utilizados não são passados.Os identificadores delimitados por classes MFC são convertidos em ponteiros para os objetos adequados do MFC.O exemplo a seguir mostra como para manipular o WM_PAINT mensagem e fazer com que o CMyWnd::OnPaint função seja chamada:
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
A tabela de mapeamento de mensagem deve ser definida fora do escopo de qualquer definição de função ou classe.Não deve ser colocado em bloco extern "C".
Observação: |
---|
ClassWizard modificará as entradas de MAP de mensagem que ocorrem entre o / /{ {e / /}} colchete de comentário. |
Mensagens do Windows definidos pelo usuário
As mensagens definidas pelo usuário podem ser incluídas em um MAP da mensagem usando o ON_MESSAGE macro. Essa macro aceita um número da mensagem e um método do formulário:
// inside the class declaration
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
#define WM_MYMESSAGE (WM_USER + 100)
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()
Neste exemplo, podemos estabelecer um manipulador para uma mensagem personalizada que tenha uma ID de mensagem Windows derivada do padrão WM_USER base para as mensagens definidas pelo usuário. O exemplo a seguir mostra como chamar esse manipulador:
CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);
O intervalo de mensagens definidas pelo usuário que use essa abordagem deve estar no intervalo de WM_USER para que 0x7fff.
Observação: |
---|
ClassWizard não oferece suporte à inserção ON_MESSAGE rotinas de manipulador da interface do usuário ClassWizard. Você deve inseri-los manualmente do editor do Visual C++ de.ClassWizard irá analisar essas entradas e permitem que você procure-os assim como quaisquer outras entradas de MAP da mensagem. |
Mensagens registrado do Windows
The RegisterWindowMessage função é usada para definir uma nova mensagem de janela garantida como exclusivas em todo o sistema.A macro ON_REGISTERED_MESSAGE é usado para lidar com essas mensagens. Essa macro aceita um nome de um UINT NEAR ID de variável que contém a mensagem windows registrado. Por exemplo
class CMyWnd : public CMyParentWndClass
{
public:
CMyWnd();
//{{AFX_MSG(CMyWnd)
afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
static UINT NEAR WM_FIND = RegisterWindowMessage("COMMDLG_FIND");
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
A variável de ID de mensagem do Windows registrada (WM_FIND neste exemplo) deve ser um NEAR variável por causa da maneira como ON_REGISTERED_MESSAGE é implementada.
O intervalo de mensagens definidas pelo usuário que use essa abordagem será no intervalo 0xC000 a 0xFFFF.
Observação: |
---|
ClassWizard não oferece suporte à inserção ON_REGISTERED_MESSAGE rotinas de manipulador da interface do usuário ClassWizard. Você deve inseri-los manualmente do editor de texto.ClassWizard irá analisar essas entradas e permitem que você procure-os assim como quaisquer outras entradas de MAP da mensagem. |
Mensagens de comando
As mensagens do comando de menus e aceleradores são tratadas em mapas de mensagem com o ON_COMMAND macro. Essa macro aceita uma ID de comando e um método.Somente o específicos WM_COMMAND mensagem que possui um wParam igual à ID de comando especificado é tratado pelo método especificado na entrada do MAP da mensagem. Funções de membro de manipulador de comando tomar sem parâmetros e retornam void. A macro tem a seguinte forma:
ON_COMMAND(id, memberFxn)
Mensagens de atualização de comando são roteadas pelo mesmo mecanismo, mas usam o ON_UPDATE_COMMAND_UI macro em vez disso. Funções de membro de manipulador de comando de atualização recebem um parâmetro único, um ponteiro para um CCmdUI objeto e de retornovoid. A macro tenha o formulário
ON_UPDATE_COMMAND_UI(id, memberFxn)
Os usuários avançados podem usar o ON_COMMAND_EX macro, que é um estendida formulário de manipuladores de mensagem de comando. A macro fornece um superconjunto do ON_COMMAND funcionalidade. Funções de membro de manipulador de comandos estendido utilizam um único parâmetro, um UINT que contém a ID de comando e retornar uma BOOL. O valor retornado deve ser TRUE para indicar que o comando tiver sido tratado. Caso contrário, o roteamento continuará a outros objetos de comando do destino.
Exemplos dessas formas:
recurso.h interna (normalmente gerado pelo Visual C++)
#define ID_MYCMD 100 #define ID_COMPLEX 101
Dentro da declaração de classe
afx_msg void OnMyCommand(); afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI); afx_msg BOOL OnComplexCommand(UINT nID);
Dentro da definição de MAP da mensagem
ON_COMMAND(ID_MYCMD, OnMyCommand) ON_UPDATE_COMMAND_UI(ID_MYCMD, OnUpdateMyCommand) ON_COMMAND_EX(ID_MYCMD, OnComplexCommand)
No arquivo de implementação
void CMyClass::OnMyCommand() { // handle the command } void CMyClass::OnUpdateMyCommand(CCmdUI* pCmdUI) { // set the UI state with pCmdUI } BOOL CMyClass::OnComplexCommand(UINT nID) { // handle the command return TRUE; }
Usuários avançados podem lidar com um intervalo de comandos usando um manipulador de comandos único: ON_COMMAND_RANGE or ON_COMMAND_RANGE_EX. Consulte a documentação do produto para obter mais informações sobre essas macros.
Observação: |
---|
ClassWizard dá suporte para a criação ON_COMMAND e ON_UPDATE_COMMAND_UI manipuladores, mas não oferece suporte à criação de ON_COMMAND_EX ou ON_COMMAND_RANGE manipuladores. No entanto, o Assistente de classe irá analisar e permitem que você procurar todas as variantes do manipulador de comando quatro. |
Mensagens de notificação de controle
As mensagens enviadas dos controles filho em uma janela têm um extra bit de informações em sua mensagem mapeiam entrada: ID. do controleO manipulador de mensagens especificado em uma entrada de MAP da mensagem é chamado somente se as seguintes condições forem verdadeiras:
O código de controle de notificação (palavra alta de lParam), sistema autônomo BN_CLICKED, corresponde ao código de notificação especificado na entrada de MAP da mensagem.
A ID do controle (wParam) corresponde a ID do controle especificada na entrada de MAP da mensagem.
Mensagens de notificação do controle personalizado podem usar o ON_CONTROL macro para definir uma entrada de MAP da mensagem com um código personalizado de notificação. Essa macro tem o seguinte formato:
ON_CONTROL(wNotificationCode, id, memberFxn)
Para uso avançado ON_CONTROL_RANGE pode ser usado para manipular uma notificação de controle específico em uma variedade de controles com o mesmo manipulador.
Observação: |
---|
ClassWizard não oferece suporte à criação de um ON_CONTROL ou ON_CONTROL_RANGE manipulador na interface do usuário. Você deve inseri-los manualmente com o editor de texto.ClassWizard irá analisar essas entradas e permitem que você procure-os assim como quaisquer outras entradas de MAP da mensagem. |
Controles comuns do Windows usam o mais poderoso WM_NOTIFY para notificações de controle complexos.Esta versão do MFC tem suporte direto para essa nova mensagem usando o ON_NOTIFY e ON_NOTIFY_RANGE macros. Consulte a documentação do produto para obter mais informações sobre essas macros.