TN021: Comando e roteamento de mensagens
Observação: |
---|
A seguinte nota técnica não foi atualizada desde que foi incluída pela primeira vez na documentação online.sistema autônomo resultado, alguns procedimentos e tópicos podem estar desatualizado ou incorreto.Para obter informações mais recentes, é recomendável que você procurar o tópico de interesse no índice de documentação online. |
Esta observação descreve a arquitetura de expedição e roteamento de comando, assim sistema autônomo tópicos avançados no roteamento de mensagens de janela geral.
Consulte Visual C++ para obter detalhes Geral sobre as arquiteturas descritas aqui, especialmente a distinção entre mensagens, notificações de controle e comandos do Windows.Esta nota supõe que você esteja muito familiarizado com os problemas descritos na documentação impressa e aborda apenas tópicos muito avançados.
O roteamento de comando e despacho de MFC 1.0 funcionalidade evolui ao MFC 2.0 Architecture
O Windows tem o WM_COMMAND mensagem sobrecarregada para fornecer notificações de comandos de menu, teclas aceleradoras e notificações de controle de caixa de diálogo.
MFC 1.0 incorporada que um pouco, permitindo que um manipulador de comandos (por exemplo, "OnFileNew") umaCWnd classe obter chamado em resposta a um determinado derivadaWM_COMMAND.Isso está colado junto com uma estrutura de dados chamada MAP da mensagem e resultados em um mecanismo muito eficiente de espaço de comando.
MFC 1.0 também fornece funcionalidade adicional para separar as notificações de controle de mensagens de comando.Comandos são representados por uma ID de 16 bit, às vezes conhecida sistema autônomo uma ID de comando.Comandos normalmente iniciar a partir de um CFrameWnd (isto é, um menu, selecionar ou um acelerador traduzido) e são roteados para uma variedade de outras janelas.
MFC 1.0 usava comando roteamento em um sentido limitado para a implementação de interface de documentos múltiplos (MDI).(Uma janela de quadro MDI delegado comandos para sua janela filho MDI ativo).
Essa funcionalidade foi generalizada e estendida no MFC 2.0 para permitir comandos sejam tratadas por um número maior de objetos (não apenas objetos de janela).Ele fornece mais formais e arquitetura extensível para roteamento de mensagens e reutiliza o roteamento de destino de comando para tratamento não apenas de comandos, mas também para atualizar os objetos de interface do usuário (como itens de menu e botões da barra de ferramentas) para refletir a disponibilidade de um comando corrente.
IDs de comando
Consulte Visual C++ para obter uma explicação do comando de roteamento e processo de vinculação.Observação técnica 20 contém informações sobre ID de nomeação.
Usamos o prefixo "ID_" genérico para IDs de comando.IDs de comando são > = 0 x 8000.Linha da mensagem ou BAR de status mostrará a seqüência de caracteres de descrição do comando se há um recurso STRINGTABLE com sistema autônomo identificações mesmos que a ID de comando.
Nos recursos do seu aplicativo, um comando que pode ID aparece em vários lugares:
Em um recurso STRINGTABLE que tem a mesma ID de aviso de linha de mensagem.
Em possivelmente muitos MENU recursos anexados a itens de menu que chamar o mesmo comando.
(Avançadas) em um botão de caixa de diálogo para um comando GOSUB.
No código-fonte do seu aplicativo, um comando que pode ID aparece em vários lugares:
Seu recurso.H (ou Outros arquivo de cabeçalho de símbolo principal) para definir específicas do aplicativo IDs de comando.
TALVEZ em uma matriz de ID usada para criar uma barra de ferramentas.
Em um ON_COMMAND macro.
TALVEZ em um ON_UPDATE_COMMAND_UI macro.
Atualmente, a implementação única no MFC requer IDs de comando ser > = 0 x 8000 é a implementação de caixas de diálogo GOSUB/comandos.
Comandos GOSUB, usando a arquitetura de comando em caixas de diálogo
A arquitetura de comando do roteamento e ativando comandos funciona bem com janelas de quadro, itens de menu, botões da BAR de ferramentas, botões da BAR de diálogo, outras barras de controle e outros elementos da interface do usuário criados para atualizar em comandos de rota e por solicitação ou controlar IDs para um destino de comando principal (geralmente a janela do quadro principal).Esse destino principal pode rotear sistema autônomo notificações de comando ou controle a outros objetos de destino de comando conforme apropriado.
Uma caixa de diálogo (janela restrita ou sem janela restrita) pode se beneficiar de alguns dos recursos da arquitetura do comando se você atribuir a ID de controle do controle caixa de diálogo para a ID do comando apropriado.Suporte para as caixas de diálogo não é automático, portanto, talvez seja necessário escrever algum código adicional.
Observe que, para todos esses recursos funcionem corretamente, IDs de comando devem ser > = 0 x 8000.Como muitas caixas de diálogo poderiam obter roteadas para o mesmo quadro, comandos compartilhados devem ser > = 0 x 8000, enquanto os IDCs compartilhadas em uma caixa de diálogo específica devem ser < = 0x7FFF.
Você pode colocar um botão normal em uma caixa de diálogo modal normal com a IDC do botão definido para a ID do comando apropriado.Quando o usuário seleciona o botão, o proprietário da caixa de diálogo (geralmente a janela do quadro principal) obtém o comando exatamente como qualquer Outros comando.Isso é chamado de um comando GOSUB visto que ele normalmente é usado para exibir outra caixa de diálogo (GOSUB da primeira caixa de diálogo).
Você também pode chamar a função CWnd::UpdateDialogControls na sua caixa de diálogo e passar o endereço da sua janela do quadro principal.Esta função irá ativar ou desabilitar os controles de caixa de diálogo baseados se eles têm manipuladores de comandos no quadro.Esta função é telefonar automaticamente para você para barras de controle no loop ocioso do aplicativo, mas você deverá chamá-la diretamente para diálogos normais que você deseja tem esse recurso.
Quando é chamado ON_UPDATE_COMMAND_UI
Manter o estado ativado/check-dos itens de menu de todos os de um programa sempre pode ser um problema computacionalmente caro.Uma técnica comum é habilitar/seleção itens de menu apenas quando o usuário seleciona a popups.A implementação do MFC 2.0 de CFrameWnd o lida comWM_INITMENUPOPUP mensagem e usa a arquitetura de roteamento de comando para determinar os estados dos menus através de ON_UPDATE_COMMAND_UI manipuladores.
CFrameWnd o também lida comWM_ENTERIDLE mensagem para descrever o menu corrente item selecionado no status da BAR (também conhecido sistema autônomo a linha da mensagem).
Estrutura de menus do aplicativo, editada pelo Visual C++, é usada para representar os comandos possíveis disponível em WM_INITMENUPOPUP time.ON_UPDATE_COMMAND_UI manipuladores podem modificar o estado ou texto de um menu ou para usos avançados (como a lista MRU de arquivo ou o menu pop-up de verbos OLE), na verdade, modificar a estrutura de menu antes que o menu é desenhado.
O mesmo tipo de ON_UPDATE_COMMAND_UI processamento é concluído para barras de ferramentas (e outras barras de controle) quando o aplicativo insere seu loop ocioso.Consulte o Referência da biblioteca de classes and Observação técnica 31 para obter mais informações sobre barras de controle.
Menus pop-up aninhados
Se você estiver usando uma estrutura de menu aninhados, você irá notar que o ON_UPDATE_COMMAND_UI manipulador para o primeiro item de menu no menu pop-up é chamado nos dois casos diferentes.
Primeiro, ele é chamado o próprio menu pop-up.Isso é necessário porque os menus pop-up não têm IDs e usamos o ID do primeiro item de menu do menu pop-up para consulte o menu pop-up inteiro.Nesse caso, a m_pSubMenu variável de membro do CCmdUI objeto será não-nulo e apontará para o menu pop-up.
Segundo, ele é chamado pouco antes dos itens de menu no menu pop-up estão a ser desenhada.Nesse caso, a ID refere-se apenas ao primeiro item de menu e o m_pSubMenu variável de membro do CCmdUI objeto será nulo.
Isso permite que você ativar o menu pop-up diferente de seus itens de menu, mas requer que você gravar alguns códigos com reconhecimento de menu.Por exemplo, em um menu aninhado com a seguinte estrutura:
File>
New>
Sheet (ID_NEW_SHEET)
Chart (ID_NEW_CHART)
Os comandos ID_NEW_SHEET e ID_NEW_CHART podem ser habilitados independentemente ou desabilitado.The Novo menu pop-up deve ser ativada se qualquer um dos dois está ativado.
O manipulador de comandos ID_NEW_SHEET (o primeiro comando o pop-up) poderia ser algo assim:
void CMyApp::OnUpdateNewSheet(CCmdUI* pCmdUI)
{
if (pCmdUI->m_pSubMenu != NULL)
{
// enable entire pop-up for "New" sheet and chart
BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;
// CCmdUI::Enable is a no-op for this case, so we
// must do what it would have done.
pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex,
MF_BYPOSITION |
(bEnable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
return;
}
// otherwise just the New Sheet command
pCmdUI->Enable(m_bCanCreateSheet);
}
O manipulador de comandos ID_NEW_CHART seria um manipulador de comandos de atualização normal e aparência algo como:
void CMyApp::OnUpdateNewChart(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_bCanCreateChart);
}
ON_COMMAND e ON_BN_CLICKED
As macros de MAP da mensagem para ON_COMMAND and ON_BN_CLICKED são os mesmos.O MFC comando e controle de notificação de mecanismo de roteamento somente usa a ID de comando para decidir onde rotear para.Notificações de controle com o código de controle de notificação do zero (BN_CLICKED) são interpretadas sistema autônomo comandos.
Observação: |
---|
Na verdade, todas as mensagens de notificação de controle passam por cadeia de manipulador de comando.Por exemplo, é tecnicamente possível para que você escreva um manipulador de notificação de controle EN_CHANGE na sua classe de documento.Isso não é aconselhável geralmente porque as aplicações práticas desse recurso são alguns, não há suporte para o recurso ClassWizard e uso do recurso pode resultar em código frágil. |
Desativação desativação automático de controles de botão
Se você colocar um controle de botão em uma BAR de diálogo ou em uma caixa de diálogo com onde você está chamando CWnd::UpdateDialogControls por conta própria, você irá notar que botões que não têm ON_COMMAND or ON_UPDATE_COMMAND_UI manipuladores serão desativados automaticamente para você pela estrutura.Em alguns casos, você não precisará ter um manipulador mas será que o botão permaneça ativado.A maneira mais fácil para conseguir isso é adicionar um manipulador de comandos fictício (fácil de fazer com ClassWizard) e não fazer nada nela.
Janela mensagem roteamento
A seguir descreve alguns tópicos mais avançados em classes MFC e como o roteamento de mensagens do Windows e outros tópicos afetam-los.As informações aqui somente são descritas resumidamente.Consulte o Referência da biblioteca de classes para obter detalhes sobre APIs públicas.Consulte o código de fonte de biblioteca MFC para obter mais informações sobre detalhes de implementação.
Consulte o Observação técnica 17 para obter detalhes sobre a janela limpeza, um tópico muito importante para todos os CWnd-classes derivadas.
Problemas de CWnd
A implementação membro função CWnd::OnChildNotify fornece uma arquitetura extensível e eficiente para janelas filho (também conhecido sistema autônomo controles) conectar ou caso contrário, ser informado de mensagens, comandos e sistema autônomo notificações de controle que levam a seu pai (ou "proprietário").Se a janela filho (/ controle) é um C++ CWnd próprio objeto, a função virtual OnChildNotify é chamado pela primeira vez com os parâmetros da mensagem original (ou seja, um MSG estrutura).A janela filho deixe a mensagem está, comê-lo ou modificar a mensagem para o pai (raro).
O padrão de CWnd implementação lida com as seguintes mensagens de e usa o OnChildNotify gancho para permitir janelas (controles) para o primeiro acesso a mensagem filho:
WM_MEASUREITEM and WM_DRAWITEM (para self-draw)
WM_COMPAREITEM and WM_DELETEITEM (para self-draw)
WM_HSCROLL and WM_VSCROLL
WM_CTLCOLOR
WM_PARENTNOTIFY
Você observará a OnChildNotify cabo é usado para alteração proprietário-draw mensagens em mensagens self-draw.
Juntamente com o OnChildNotify gancho, rolar mensagens possuem um comportamento de roteamento ainda mais.Por favor, consulte abaixo para obter mais detalhes nas barras de rolar e fontes de WM_HSCROLL and WM_VSCROLL mensagens.
Problemas de CFrameWnd
The CFrameWnd classe fornece a maioria do roteamento de comando e interface do usuário atualizar a implementação.Isso é usado principalmente para a janela do quadro principal do aplicativo (CWinApp::m_pMainWnd) mas se aplica a todas as janelas de quadro.
A janela do quadro principal é a janela com a BAR de menus e é o pai do BAR de status ou linha da mensagem.Consulte a discussão acima sobre roteamento de comando e WM_INITMENUPOPUP.
The CFrameWnd classe fornece gerenciamento do modo de exibição ativo.As seguintes mensagens são roteadas pelo modo de exibição ativo:
Todas as mensagens de comando (modo de exibição ativo é primeiro acesso a eles).
WM_HSCROLL and WM_VSCROLL mensagens irmão rolar barras (veja abaixo).
WM_ACTIVATE (and WM_MDIACTIVATE MDI) obter transformado em chamadas para a função virtual CView::OnActivateView.
Problemas de CMDIFrameWnd/CMDIChildWnd
Ambas as classes de janela de quadro MDI derivam de CFrameWnd e, portanto, são habilitados para o mesmo tipo de roteamento de comando e interface do usuário atualização fornecida no CFrameWnd.Em um aplicativo MDI típico, apenas a janela do quadro principal (ou seja, a CMDIFrameWnd objeto) mantém a BAR de menus e BAR de status e, portanto, é a principal fonte de implementação de roteamento do comando.
O esquema geral de roteamento é a janela de filho MDI ativo obtém primeiro acesso a comandos.O padrão de PreTranslateMessage funções manipular tabelas de acelerador para ambas sistema autônomo janelas filho MDI (primeiro) e o quadro MDI (segundo), bem sistema autônomo sistema autônomo aceleradores de comando do sistema MDI padrão normalmente manipulados por TranslateMDISysAccel (último).
BAR de rolar Problemas
Ao manipular a mensagem de rolar (WM_HSCROLL/OnHScroll and/or WM_VSCROLL/OnVScroll), você deve tentar escrever o código de manipulador para que ela não depende de onde o BAR de rolar proveniente de mensagem.Isso não é apenas um geral Windows problema desde que as mensagens de rolar podem ser provenientes de true BAR de rolar controles ou a partir de WS_HSCROLL/WS_VSCROLL BAR de rolar s que não são BAR de rolar controles.
MFC estende que permitem BAR de rolar controles filho ou irmãos da janela que está sendo colocada (na verdade, a relação pai/filho entre o BAR de rolar e janela sendo rolada pode ser qualquer coisa).Isso é especialmente importante para as barras de rolar compartilhado com janelas do divisor.Consulte o Observação técnica 29 para obter detalhes sobre a implementação de CSplitterWndcompartilhados incluindo mais informações no BAR de rolar problemas.
Em uma anotação rápida, há dois CWnd classes derivadas onde o BAR de rolar estilos especificados na hora de criar são interceptadas e passadas para o Windows.Quando passados para uma rotina de criação, WS_HSCROLL and WS_VSCROLL pode ser independentemente conjunto, mas após a criação não pode ser alterada.Claro, você deve testar ou conjunto o WS_ não diretamente? rolar bits de estilo da janela que criaram.
For CMDIFrameWnd o BAR de rolar estilos você passar para Criar or LoadFrame são usados para criar o MDICLIENT.Se você desejar ter uma área rolável MDICLIENT (como o Windows gerente) não se esqueça de conjunto ambos BAR de rolar estilos (WS_HSCROLL | WS_VSCROLL) para o estilo usado para criar o CMDIFrameWnd.
For CSplitterWnd o BAR de rolar estilos aplicam-se no especial compartilhada BAR de rolar s para as regiões do divisor.Para janelas de divisor estático, você normalmente não definirá um BAR de rolar estilo.Para janelas de divisor dinâmico, você geralmente terá BAR conjunto de estilo para a direção que será dividida, ou seja, de rolarWS_HSCROLL se você pode dividir linhas, WS_VSCROLL se você pode dividir colunas.