TN021: Comando e roteamento de mensagens

ObservaçãoObservação

A seguinte nota técnica não foi atualizada desde que foi incluída pela primeira vez na documentação online.Como resultado, alguns procedimentos e tópicos podem estar desatualizado ou incorreto.As informações mais recentes, é recomendável que você procure o tópico de interesse no índice de documentação on-line.

Esta anotação descreve a arquitetura de roteamento e despacho de comando bem como tópicos avançados geral janela roteamento de mensagens.

Consulte Visual C++ para obter detalhes gerais 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 familiarizado com os problemas descritos na documentação impressa e apenas aborda tópicos muito avançados.

Roteamento de comando e despacho de MFC 1.0 funcionalidade evolui para MFC 2.0 arquitetura

O Windows tem o WM_COMMAND mensagem sobrecarregada para fornecer notificações de comandos de menu, teclas de aceleração e notificações de controle de caixa de diálogo.

MFC 1.0 criado em que um pouco, permitindo que um manipulador de comando (por exemplo, "OnFileNew") um CWnd derivado classe chamado em resposta a um determinado WM_COMMAND.Isso está colado junto com uma estrutura de dados chamada mapa da mensagem e resulta em um mecanismo muito eficiente de espaço de comando.

1.0 MFC também fornecida funcionalidade adicional para separar as notificações de controle de mensagens de comando.Comandos são representados por uma identificação de 16 bits, algumas vezes conhecida como uma identificação de comando.Comandos normalmente Iniciar de um CFrameWnd (ou seja, selecionar uma menu ou um acelerador traduzido) e são roteados para uma variedade de outras janelas.

MFC 1.0 usado comando roteamento em um sentido limitado para a implementação de Interface de documentos múltiplos (MDI).(Uma janela de quadro MDI delegar comandos para a janela filho MDI ativo.)

Essa funcionalidade foi generalizada e estendida no 2.0 MFC para permitir comandos deve ser tratado por uma variedade 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 não apenas a manipulação de comandos, mas também para atualizar objetos de interface do usuário (como itens de menu e botões da barra de ferramentas) para refletir a disponibilidade atual de um comando.

IDs de comando

Consulte Visual C++ para obter uma explicação do comando roteamento e o processo de ligação.Técnico anotação 20 contém informações sobre identificação de nomeação.

Usamos o prefixo genérico "ID _" para IDs de comando.IDs de comando são > 0x8000.A barra de status ou de linha de mensagem mostrará a seqüência de caracteres de descrição do comando se houver um recurso STRINGTABLE com as identificações mesmos como a ID de comando.

Recursos do seu aplicativo, um comando que ID pode aparece em vários lugares:

  • Em um recurso STRINGTABLE que tem a mesma identificação de prompt de linha de mensagem.

  • Possivelmente muitos MENU recursos que estão anexados a itens de menu que chamar o mesmo comando.

  • (Avançado) em um botão de caixa de diálogo para um comando GOSUB.

No código fonte do seu aplicativo, um comando que ID pode aparece em vários lugares:

  • No recurso.H (ou outro arquivo de cabeçalho principal símbolo) para definir específicas do aplicativo comando identificações.

  • 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 que requer IDs de comando ser > = 0x8000 é a implementação de caixas de diálogo GOSUB/comandos.

A arquitetura de comando do roteamento e ativando comandos funciona bem com windows de quadro, itens de menu, botões da barra de ferramentas, botões da barra de diálogo, outras barras de controle e outros elementos de interface de usuário projetados para atualizar em comandos de demanda e rotear ou controlar identificações para um destino de comando principal (geralmente a janela de quadro principal).Destino principal comando pode rotear as notificações de comando ou controle a outros objetos de destino de comando conforme apropriado.

Uma caixa de diálogo (restrita ou sem janela restrita) pode se beneficiar de alguns dos recursos da arquitetura do comando se você atribuir a identificação de controle do controle caixa de diálogo para a identificação de comando apropriado.Suporte para caixas de diálogo não é automático, portanto, talvez você precise escrever código adicional.

Observe que, para todos esses recursos funcionem corretamente, as IDs de comando devem ser > = 0x8000.Como muitas caixas de diálogo poderiam obter roteadas para o mesmo quadro, comandos compartilhados devem ser > = 0x8000, 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 identificação de comando apropriado.Quando o usuário seleciona o botão, o proprietário da caixa de diálogo (geralmente a janela de quadro principal) obtém o comando exatamente como qualquer outro comando.Isso é chamado um comando GOSUB como ele geralmente é 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 janela do quadro principal.Esta função irá habilitar ou desabilitar os controles de caixa de diálogo baseados se eles têm manipuladores de comandos no quadro.Essa função é chamada automaticamente para você para barras de controle no loop ocioso do aplicativo, mas você deverá chamá-la diretamente para caixas de diálogo normais que você queira ter esse recurso.

Quando ON_UPDATE_COMMAND_UI é chamado

Manter o estado ativado/verificado dos itens de menu todo um programa sempre pode ser um problema dispendioso.Uma técnica comum é ativar/verificar itens de menu apenas quando o usuário seleciona o POPUP.A implementação MFC 2.0 CFrameWnd alças de WM_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 também manipula o WM_ENTERIDLE mensagem para descrever o menu atual item selecionado no status da barra (também conhecido como a linha de mensagem).

Estrutura de menu do aplicativo, editada pelo Visual C++, é usada para representar os comandos possíveis disponíveis em WM_INITMENUPOPUP tempo.ON_UPDATE_COMMAND_UI manipuladores podem modificar o estado ou o texto de um menu ou para usos avançados (como a lista MRU de arquivo ou o menu de verbos OLE pop-up), a estrutura de menu antes de modificar o menu é desenhado.

O mesmo tipo de ON_UPDATE_COMMAND_UI o processamento é feito para barras de ferramentas (e outras barras de controle) quando o aplicativo insere seu loop ocioso.Consulte o Referência de biblioteca de classe e técnico anotação 31 para obter mais informações sobre barras de controle.

Se você estiver usando uma estrutura de menu aninhados, você notará que o ON_UPDATE_COMMAND_UI manipulador para o primeiro item de menu no menu pop-up é chamado em dois casos diferentes.

Primeiro, ele é chamado o próprio menu pop-up.Isso é necessário porque menus pop-up não têm IDs e usamos o ID do primeiro item de menu do menu pop-up para se referir a todo o menu pop-up.Nesse caso, o m_pSubMenu variável de membro de CCmdUI objeto será nula e irá apontar para o menu pop-up.

Segundo, ele é chamado antes dos itens de menu no menu pop-up estão a ser desenhada.Nesse caso, a identificação refere-se apenas para o primeiro item de menu e o m_pSubMenu variável de membro de CCmdUI objeto será NULL.

Isso permite que você ative o menu pop-up diferente de seus itens de menu, mas exige que você escreva algum código ciente do 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 ativados ou desativados independentemente.O nova menu pop-up deve ser ativada se qualquer um dos dois está habilitado.

O manipulador de comando para ID_NEW_SHEET (o primeiro comando no menu pop-up) seria algo como:

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 comando para 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 mapa da mensagem para ON_COMMAND e ON_BN_CLICKED são os mesmos.O MFC comando e controle notificação roteamento mecanismo apenas usa a identificação de comando para decidir onde rotear.Controlar notificações com código de notificação do controle de zero (BN_CLICKED) são interpretadas como comandos.

ObservaçãoObservação

Na verdade, todas as mensagens de notificação de controle passam por cadeia de manipulador de comando.Por exemplo, é tecnicamente possível para escrever um manipulador de notificação do controle para EN_CHANGE na sua classe de documento.Não é aconselhável geralmente porque são algumas aplicações práticas desse recurso, o recurso não é suportado pelo ClassWizard e uso do recurso pode resultar em código frágil.

Desativação desativação automática de controles de botão

Se você colocar um controle de botão em uma barra de diálogo ou uma caixa de diálogo usar onde você está chamando CWnd::UpdateDialogControls por conta própria, você irá notar que botões que não têm ON_COMMAND ou ON_UPDATE_COMMAND_UI manipuladores serão automaticamente desativadas para você pela estrutura.Em alguns casos, você não precisará ter um manipulador, mas deseja o botão permaneça ativado.A maneira mais fácil de conseguir isso é adicionar um manipulador de comando fictício (fácil de fazer com ClassWizard) e não fazer nada nele.

Roteamento de mensagens de janela

A seguir descreve alguns tópicos mais avançados de classes MFC e como roteamento de mensagens do Windows e outros tópicos impactam-los.As informações aqui só são descritas resumidamente.Consulte o Referência de biblioteca de classe para obter detalhes sobre APIs públicas.Consulte o código fonte da biblioteca MFC para obter mais informações sobre detalhes de implementação.

Consulte técnico Observação 17 para obter detalhes sobre a limpeza de janela, um tópico muito importante para todas as CWnd-classes derivadas.

Problemas de CWnd

A função de membro de implementação CWnd::OnChildNotify fornece uma arquitetura extensível e eficiente para janelas filho (também conhecido como controles) conectar ou caso contrário, ser informado de mensagens, comandos e notificações de controle vá para seu pai (ou "proprietário").Se a janela filho (/ controle) é um C++ CWnd objeto propriamente dito, a função virtual OnChildNotify é chamado primeiro com os parâmetros da mensagem original (ou seja, um MSG estrutura).A janela filho deixa a mensagem sozinho, comê-lo ou modificar a mensagem para o pai (raro).

O padrão CWnd implementação trata as seguintes mensagens e usa o OnChildNotify gancho para permitir filho windows (controles) para o primeiro acesso a mensagem:

  • WM_MEASUREITEM e WM_DRAWITEM (para self-draw)

  • WM_COMPAREITEM e WM_DELETEITEM (para self-draw)

  • WM_HSCROLL e WM_VSCROLL

  • WM_CTLCOLOR

  • WM_PARENTNOTIFY

Você observará a OnChildNotify gancho é usado para alterar o desenho proprietário mensagens em mensagens self-draw.

Além de OnChildNotify mensagens de rolagem de gancho, para ter ainda mais o comportamento de roteamento.Consulte abaixo para obter mais detalhes sobre as barras de rolagem e fontes de WM_HSCROLL e WM_VSCROLL mensagens.

Problemas de CFrameWnd

O CFrameWnd classe fornece a maioria do roteamento de comando e interface de usuário atualização implementação.Isso é usado principalmente para a janela do quadro principal do aplicativo (CWinApp::m_pMainWnd), mas se aplica a todas as janelas do quadro.

A janela do quadro principal é a janela com a barra de menu e é o pai da barra de status ou a linha da mensagem.Consulte a discussão acima sobre roteamento de comando e WM_INITMENUPOPUP.

O CFrameWnd classe fornece gerenciamento de exibição ativo.As seguintes mensagens são roteadas por meio do modo de exibição ativo:

  • Todas as mensagens de comando (modo de exibição ativo obtém primeiro acesso a eles).

  • WM_HSCROLL e WM_VSCROLL mensagens de irmãos rolagem barras (veja abaixo).

  • WM_ACTIVATE (e WM_MDIACTIVATE para MDI) obter transformados em chamadas de função virtual CView::OnActivateView.

Problemas de CMDIFrameWnd/CMDIChildWnd

Ambas as classes de janela de quadro MDI derivam de CFrameWnd e, portanto, estão habilitados para o mesmo tipo de roteamento de comando e atualização da interface do usuário fornecidas no CFrameWnd.Em um aplicativo MDI típico, somente a janela do quadro principal (isto é, o CMDIFrameWnd objeto) mantém a barra de menu e barra de status e, portanto, é a fonte principal da implementação de roteamento de comando.

O esquema de roteamento geral é que a janela de filho MDI ativo obtém primeiro acesso a comandos.O padrão PreTranslateMessage funções manipulam tabelas accelerator Windows filho MDI (primeiro) e o quadro MDI (segundo), bem como os aceleradores de comando do sistema MDI padrão normalmente processados por TranslateMDISysAccel (último).

Problemas de barra de rolagem

Ao manipular a mensagem de rolagem (WM_HSCROLL/OnHScroll e/ou WM_VSCROLL/OnVScroll), você deve tentar escrever o código de manipulador para que ele não depende de onde veio a mensagem de barra de rolagem.Isso não é só é um problema Windows geral, como mensagens de rolagem podem vir de rolagem verdadeira barra controles ou de WS_HSCROLL/WS_VSCROLL barras que não são controles de barra de rolagem de rolagem.

MFC estende que para controles de barra de rolagem ser filho ou irmãos da janela que está sendo rolada (na verdade, a relação pai/filho entre a barra de rolagem e a janela que está sendo rolada pode ser qualquer coisa).Isso é especialmente importante para as barras de rolagem compartilhado com o windows do divisor.Consulte técnico anotação 29 para obter detalhes sobre a implementação de CSplitterWnd incluindo mais informações sobre problemas de barra de rolagem compartilhado.

Em uma nota lateral, há dois CWnd classes derivadas onde os estilos de barra de rolagem especificados em criar tempo são interceptadas e não são passadas para o Windows.Quando passado para uma rotina de criação, WS_HSCROLL e WS_VSCROLL podem ser definidas independentemente, mas após a criação não pode ser alterada.Claro, você deve testar não diretamente ou definir o WS_?Bits de estilo de ROLAGEM da janela que criaram.

Para CMDIFrameWnd estilos de barra de rolagem para o você passar criar ou LoadFrame são usadas para criar o MDICLIENT.Se você deseja ter uma área MDICLIENT rolável (como o Windows programa Gerenciador) certifique-se de definir ambos barra de rolagem estilos (WS_HSCROLL | WS_VSCROLL) para o estilo usado para criar o CMDIFrameWnd.

Para CSplitterWnd aplicam estilos de barra de rolagem para as barras de rolagem compartilhado especial para as regiões do divisor.Para windows divisor estático, você normalmente não irá definir dois estilos de barra de rolagem.Para windows divisor dinâmico, você geralmente terá a barra de estilo definido para a direção que você irá dividir, isto é, de rolagem WS_HSCROLL se dividir linhas, WS_VSCROLL se dividir colunas.

Consulte também

Outros recursos

Notas técnicas por número

Notas técnicas por categoria