TN021: Comando e roteamento de mensagens

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

Por favor, consulte Guia do programador do Visual C++ para geral detalhes sobre as arquiteturas descritas aqui, especialmente a distinção entre Windows mensagens, notificações de Controlarar e comandos. Esta anotação supõe que você estiver muito familiarizado com os problemas descritos na documentação impressa e apenas aborda tópicos muito avançados.

Expedição e roteamento de comando do MFC 1.0 funcionalidade evolui para MFC 2.0 arquitetura

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

MFC 1.0 construída sobre isso um pouco, permitindo que um manipulador de comando (por exemplo, "OnFileNew") em um CWnd derivado classe para obter chamado em resposta a um específico WM_COMMAND. Isso está colado junto com uma estrutura de dados chamada o 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 notificações de Controlarar de mensagens de comando. Comandos são representados por um ID de 16 bits, algumas vezes conhecida como uma identificação de comando. Comandos normalmente Iniciar de um CFrameWnd (por exemplo: um menu Selecionar ou um acelerador traduzido) e são roteadas 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 do quadro MDI delegate comandos para sua janela de filho MDI ativo.)

Esta funcionalidade foi generalizada e estendida no 2.0 MFC para permitir comandos deve ser tratado por uma gama maior de objetos (não apenas objetos de janela). Ele fornece uma mais formal e arquitetura extensível para roteamento de mensagens e reutiliza o roteamento de destino de comando para não somente 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 o Guia do programador do Visual C++ para obter uma explicação do comando roteamento e ligação processo. Técnico Anotação 20 contém informações sobre a nomeação de identificação.

Nós usamos o prefixo genérico "ID _" de IDs de comando. Comando identificações são gt; = 0 x 8000. A barra de status ou linha de mensagem vai mostrar a Cadeia de caracteres de descrição do comando se há um recurso STRIN>ABLE com as mesmas identificações como o ID de comando.

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

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

Atualmente, a implementação única no MFC que requer IDs de comando ser gt; = 0 x 8000 é a implementação de caixas de diálogo &GOSUB/comandos.

Comandos GOSUB, usando a arquitetura de comando nas caixas de diálogo

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

Uma caixa de diálogo (restrita ou sem janela restrita) pode beneficiar de algumas das características da arquitetura do comando se você atribuir a identificação de Controlarar do Controlarar de caixa de diálogo para a identificação de comando apropriado. Suporte para caixas de diálogo não é automático, assim você pode ter que escrever algum código adicional.

Observe que, para todos esses recursos funcionem corretamente, suas IDs de comando devem ser gt; = 0 x 8000. Uma vez que muitas caixas de diálogo poderiam obter roteadas para o mesmo quadro, comandos compartilhados devem ser > = 0 x 8000, enquanto o não compartilhado IDC em uma caixa de diálogo específica deve ser < = 0x7FFF.

Você pode colocar um botão normal em uma caixa de diálogo modal normal com o 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 do quadro principal) Obtém o comando exatamente como qualquer outro comando. Isto é chamado um comando GOSUB pois ele geralmente é usado para abrir outra caixa de diálogo (um GOSUB da primeiro diálogo).

Você também pode chamar a função CWnd:: UpdateDialogControls na sua caixa de diálogo e passá-lo o endereço da janela do quadro principal. Esta vontade de função habilitado ou desativar seus controles de caixa de diálogo com base em se eles têm manipuladores de comando no quadro. Essa função é chamada automaticamente para você para barras de Controlarar no loop ocioso do seu aplicativo, mas você deve chamá-lo diretamente para caixas de diálogo normais que você deseja ter esse recurso.

Quando ON_UPDATE_COMMAND_UI é chamado

Manter o estado habilitado/marcado de itens de menu do todo um programa o tempo todo pode ser um problema computacionalmente caro. Uma técnica comum é habilitar/Marcar itens de menu apenas quando o usuário seleciona o pop-up. A implementação MFC 2.0 de CFrameWnd manipula a mensagem WM_INITMENUPOPUP 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 a mensagem WM_ENTERIDLE para descrever o menu atual item selecionado na barra de status (também conhecida como a linha de mensagem).

Estrutura de menus do aplicativo, editada por 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 no menu de verbos OLE), modificar a estrutura de menu antes que o menu é desenhado.

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

Menus pop-up aninhados

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

Em primeiro lugar é chamado para o pop-up propriamente dito. Isso é necessário pois menus pop-up não têm IDs e usamos o ID do primeiro item de menu do popup para se referir ao popup inteiro. Neste caso, a variável de membro m_pSubMenu do objeto CCmdUI será não-NULL e apontará para menu popup.

Em segundo lugar ele é chamado apenas antes que são os itens de menu pop-up. Neste caso o ID refere-se apenas para o primeiro item de menu e a variável de membro m_pSubMenu do objeto CCmdUI será NULL.

Isso permite que você ative o 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:

Filegt;
    Novo >
        Folha (ID_NEW_SHEET)
        Gráfico (ID_NEW_CHART)

Os comandos ID_NEW_SHEET e ID_NEW_CHART podem ser habilitados ou desabilitados independentemente. O menu de popup "Novo" deve ser ativado se qualquer uma das duas está habilitado.

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

privatevoid CMyApp::OnUpdateNewSheet (CCmdUI pCmdUI)
{
 nbsp;  se (pCmdUI - > m_pSubMenu! = NULL)
    {
        / / Habilitar popup inteira para "Novo" planilha e de gráfico
        BOOL bEnable = m_bCanCreateSheet | | m_bCanCreateChart;

/ / CCmdUI::Enable é um não-op para este caso, então nós
        / / deve fazer o que ele teria feito.
        pCmdUI - > m_pMenu - > EnableMenuItem (pCmdUI - > m_nIndex,
            MF_BYPOSITION | 
                (bEnable? MF_ENABLED: (MF_DISABLED | MF_GRAYED)));
        retornar;
    }
    / / caso contrário apenas o comando nova folha
    pCmdUI - > Enable(m_bCanCreateSheet);
}

O manipulador de comando para ID_NEW_CHART seria um manipulador de comando de atualização normal e aparência algo como:

privatevoid CMyApp::OnUpdateNewChart (CCmdUI pCmdUI)
{
 nbsp;  pCmdUI - > Enable(m_bCanCreateChart);
}

ON_COMMAND e ON_BN_CLICKED

As macros de mapa de 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 para. Notificações de Controlarar com código de notificação de Controlarar de zero (BN_CLICKED) são interpretadas como comandos.

Observação avançada: na realidade, todas as mensagens de notificação de Controlarar ir através da Cadeia de manipulador de comando. Por conseguinte, é tecnicamente possível para você gravar um manipulador de notificação de Controlarar para dizer EN_CHANGE na sua classe de documento. Isso não é geralmente aconselhável uma vez que as aplicações práticas desse recurso são poucas, o recurso não é suportado pelo ClassWizard e uso do recurso pode resultar em código frágil.

Desativando o desativando automática de controles de botão

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

Janela roteamento de Mensagemens

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

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

Problemas de CWnd

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

Implementação padrão CWnd manipula as mensagens seguintes e usa o gancho OnChildNotify para permitir filho windows (controles) para obter primeiro rachar a mensagem:

Você vai notar que o gancho OnChildNotify é usado para alterar o proprietário-desenhar mensagens em mensagens self-Desenhar.

Além do gancho OnChildNotify , mensagens de rolagem tem comportamento de roteamento ainda mais. Ver por favor abaixo para mais detalhes sobre as barras de rolagem e fontes de WM_HSCROLL e WM_VSCROLL mensagens.

Problemas de CFrameWnd

CFrameWnd classe fornece a maioria dos roteamento de comando e interface de usuário atualização implementação. Isto é 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 barra de menus e é o pai da barra de status ou linha da mensagem. Por favor, consulte a discussão acima sobre roteamento de comando e WM_INITMENUPOPUP.

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

Problemas de CMDIFrameWnd/CMDIChildWnd

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

O esquema de roteamento geral é que a janela de filho MDI ativo obtém primeiro crack em comandos. Funções padrão PreTranslateMessage tratar tabelas acelerador para ambas janelas de filho MDI (primeiro) e o quadro MDI (segundo), bem como os aceleradores de comando do sistema MDI padrão normalmente manipulados pelo TranslateMDISysAccel (último).

Problemas de barra de rolagem

Quando Manipulação rolagem-mensagem (WM_HSCROLL/OnHScroll e/ou WM_VSCROLL/OnVScroll ), você deve tentar escrever o código do manipulador, assim ele não dependem de onde veio a mensagem de barra de rolagem. Este não é apenas uma questão de Windows geral, desde mensagens de rolagem podem provir de rolagem verdadeira bar controles ou WS_HSCROLL/WS_VSCROLL as barras de rolagem que são não scroll barra controles.

MFC estende que para permitir a 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). Isto é especialmente importante para as barras de rolagem compartilhado com separador windows. 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 a barra de rolagem estilos especificada em criar tempo estão presos e não passou para Windows. Quando passada para uma rotina de criação, WS_HSCROLL e WS_VSCROLL podem ser independentemente definidas, mas após a criação não pode ser alterada. Claro, você não diretamente deve testar ou definir o WS _?Bits de estilo de rolagem da janela que eles criaram.

Para CMDIFrameWnd a barra de rolagem estilos que você passa para criar ou LoadFrame é usadas para criar o MDICLIENT. Se você deseja ter uma área MDICLIENT rolável (como o Windows programa gerente) Certifique-se de definir ambos barra de rolagem estilos (WS_HSCROLL | WS_VSCROLL) para o estilo usado para criar o CMDIFrameWnd.

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

Técnico anotações por número |nbsp; &Notas técnicas por categoria

Index