Partilhar via


TN062: Reflexão de mensagem para controles do Windows

Observação

A nota técnica a seguir não foi atualizada desde que foi incluída pela primeira vez na documentação on-line. Como resultado, alguns procedimentos e tópicos podem estar desatualizados ou incorretos. Para obter as informações mais recentes, recomenda-se que pesquise o tópico de interesse no índice de documentação online.

Esta nota técnica descreve a reflexão da mensagem, um novo recurso no MFC 4.0. Ele também contém instruções para criar um controle reutilizável simples que usa reflexão de mensagem.

Esta nota técnica não discute a reflexão de mensagens como ela se aplica a controles ActiveX (anteriormente chamados de controles OLE). Consulte o artigo Controles ActiveX: Subclassificando um controle do Windows.

O Que É Reflexão de Mensagem

Os controles do Windows frequentemente enviam mensagens de notificação para as janelas pai. Por exemplo, muitos controles enviam uma mensagem de notificação de cor de controle (WM_CTLCOLOR ou uma de suas variantes) para seu pai para permitir que o pai forneça um pincel para pintar o plano de fundo do controle.

No Windows e no MFC antes da versão 4.0, cabe à janela pai, normalmente uma caixa de diálogo, a responsabilidade de manipular essas mensagens. Isso significa que o código para manipular a mensagem precisa estar na classe da janela pai e que ele deve ser duplicado em todas as classes que precisam lidar com essa mensagem. No caso acima, cada caixa de diálogo que desejasse controlos com planos de fundo personalizados teria que lidar com a mensagem de notificação da cor do controlo. Seria muito mais fácil reutilizar o código se uma classe de controle pudesse ser escrita para lidar com sua própria cor de plano de fundo.

No MFC 4.0, o antigo mecanismo ainda está a funcionar — as janelas pai podem gerir as mensagens de notificação. Além disso, MFC 4.0 facilita a reutilização, fornecendo um recurso chamado "reflexão de mensagem" que permite que essas mensagens de notificação sejam tratadas na janela de controle filho ou na janela pai, ou em ambos. No exemplo de cor de plano de fundo de controlo, pode-se agora escrever uma classe de controlo que define a sua própria cor de plano de fundo manipulando a mensagem refletida WM_CTLCOLOR — tudo sem depender do elemento pai. (Observe que, como a reflexão de mensagens é implementada pela MFC, não pelo Windows, a classe de janela pai deve ser derivada de CWnd para que a reflexão de mensagens funcione.)

As versões mais antigas do MFC faziam algo semelhante à reflexão de mensagens, fornecendo funções virtuais para algumas mensagens, como mensagens para caixas de listagem desenhadas pelo proprietário (WM_DRAWITEM e assim por diante). O novo mecanismo de reflexão da mensagem é generalizado e consistente.

A reflexão de mensagens é compatível retroativamente com código escrito para versões do MFC anteriores à 4.0.

Se tiver fornecido um manipulador para uma mensagem específica, ou para um intervalo de mensagens, na classe da janela-mãe, este irá sobrepor os manipuladores de mensagens refletidos para a mesma mensagem, desde que não chame a função do manipulador da classe base no seu próprio manipulador. Por exemplo, se você manipular WM_CTLCOLOR em sua classe de caixa de diálogo, seu tratamento substituirá quaisquer manipuladores de mensagens refletidos.

Se, em sua classe de janela pai, você fornecer um manipulador para uma mensagem WM_NOTIFY específica ou um intervalo de mensagens WM_NOTIFY, seu manipulador será chamado somente se o controle filho que envia essas mensagens não tiver um manipulador de mensagens refletido através ON_NOTIFY_REFLECT()do . Se usar ON_NOTIFY_REFLECT_EX() no mapa de mensagens, o manipulador de mensagens poderá ou não permitir que a janela-mãe trate a mensagem. Se o manipulador retornar FALSE, a mensagem também será manipulada pelo pai, enquanto uma chamada que retorna TRUE não permitirá que o pai a manipule. Observe que a mensagem refletida é manipulada antes da mensagem de notificação.

Quando uma mensagem WM_NOTIFY é enviada, o controle recebe a primeira chance de lidar com ela. Se qualquer outra mensagem refletida for enviada, a janela pai terá a primeira chance de manipulá-la e o controle receberá a mensagem refletida. Para fazer isso, ele precisará de uma função de manipulador e uma entrada apropriada no mapa de mensagens de classe do controle.

A macro de mapa de mensagens para mensagens refletidas é ligeiramente diferente do que para notificações regulares: tem _REFLECT anexado ao seu nome usual. Por exemplo, para manipular uma mensagem WM_NOTIFY no pai, use a macro ON_NOTIFY no mapa de mensagens do pai. Para manipular a mensagem refletida no controle filho, use a macro ON_NOTIFY_REFLECT no mapa de mensagens do controle filho. Em alguns casos, os parâmetros também são diferentes. Observe que o ClassWizard geralmente pode adicionar as entradas do mapa de mensagens para você e fornecer implementações de função esqueleto com parâmetros corretos.

Consulte TN061: ON_NOTIFY e WM_NOTIFY Mensagens para obter informações sobre a nova mensagem WM_NOTIFY.

Message-Map entradas e protótipos de funções para o manuseio de mensagens refletidas

Para manipular uma mensagem de notificação de controle refletida, use as macros de mapa de mensagem e protótipos de função listados na tabela abaixo.

ClassWizard geralmente pode adicionar essas entradas de mapa de mensagem para você e fornecer implementações de função esqueleto. Consulte Definindo um manipulador de mensagens para uma mensagem refletida para obter informações sobre como definir manipuladores para mensagens refletidas.

Para converter do nome da mensagem para o nome da macro refletida, anexe ON_ e acrescente _REFLECT. Por exemplo, WM_CTLCOLOR torna-se ON_WM_CTLCOLOR_REFLECT. (Para ver quais mensagens podem ser refletidas, faça a conversão oposta nas entradas de macro na tabela abaixo.)

As três exceções à regra acima referidas são as seguintes:

  • A macro para notificações WM_COMMAND é ON_CONTROL_REFLECT.

  • A macro para reflexões de WM_NOTIFY é ON_NOTIFY_REFLECT.

  • A macro para reflexão de ON_UPDATE_COMMAND_UI é ON_UPDATE_COMMAND_UI_REFLECT.

Em cada um dos casos especiais acima, você deve especificar o nome da função de membro do manipulador. Nos outros casos, você deve usar o nome padrão para sua função de manipulador.

Os significados dos parâmetros e dos valores de retorno das funções são documentados sob o nome da função, ou com On anteposto ao nome da função. Por exemplo, CtlColor está documentado em OnCtlColor. Vários manipuladores de mensagens refletidas precisam de menos parâmetros do que os manipuladores semelhantes numa janela pai. Basta combinar os nomes na tabela abaixo com os nomes dos parâmetros formais na documentação.

Entrada do mapa Protótipo de função
ON_CONTROL_REFLECT(wNotifyCode,memberFxn) afx_msg vaziomemberFxn( );
ON_NOTIFY_REFLECT(wNotifyCode,memberFxn) afx_msg voidmemberFxn( NMHDR*pNotifyStruct, LRESULT*resultado);
ON_UPDATE_COMMAND_UI_REFLECT(memberFxn) afx_msg vaziomemberFxn( CCmdUI*pCmdUI);
ON_WM_CTLCOLOR_REFLECT( ) afx_msg HBRUSH CtlColor ( CDC*pDC, UINTnCtlColor);
ON_WM_DRAWITEM_REFLECT( ) afx_msg void DrawItem (LPDRAWITEMSTRUCTlpDrawItemStruct);
ON_WM_MEASUREITEM_REFLECT( ) afx_msg anular MeasureItem ( LPMEASUREITEMSTRUCTlpMeasureItemStruct);
ON_WM_DELETEITEM_REFLECT( ) afx_msg void DeleteItem (LPDELETEITEMSTRUCTlpDeleteItemStruct);
ON_WM_COMPAREITEM_REFLECT( ) afx_msg int CompareItem ( LPCOMPAREITEMSTRUCTlpCompareItemStruct);
ON_WM_CHARTOITEM_REFLECT( ) afx_msg int CharToItem (UINT,nKeyUINT);nIndex
ON_WM_VKEYTOITEM_REFLECT( ) afx_msg int VKeyToItem (UINT,nKeyUINT);nIndex
ON_WM_HSCROLL_REFLECT( ) afx_msg vazio HScroll (UINTnSBCode, UINTnPos);
ON_WM_VSCROLL_REFLECT( ) afx_msg void VScroll (UINT,nSBCodeUINT);nPos
ON_WM_PARENTNOTIFY_REFLECT( ) afx_msg ParentNotify nulo (UINTmessage, LPARAM);lParam

As macros ON_NOTIFY_REFLECT e ON_CONTROL_REFLECT têm variações que permitem que mais de um objeto (como o controle e seu pai) manipulem uma determinada mensagem.

Entrada do mapa Protótipo de função
ON_NOTIFY_REFLECT_EX(wNotifyCode,memberFxn) afx_msg BOOLmemberFxn( NMHDR*pNotifyStruct, LRESULT*resultado);
ON_CONTROL_REFLECT_EX(wNotifyCode,memberFxn) afx_msg BOOLmemberFxn( );

Manipulando mensagens refletidas: um exemplo de um controle reutilizável

Este exemplo simples cria um controle reutilizável chamado CYellowEdit. O controle funciona da mesma forma que um controle de edição regular, exceto que ele exibe texto preto em um plano de fundo amarelo. Seria fácil adicionar funções de membro que permitiriam que o CYellowEdit controle exibisse cores diferentes.

Para tentar o exemplo que cria um controle reutilizável

  1. Crie uma nova caixa de diálogo em um aplicativo existente. Para obter mais informações, consulte o tópico do editor de diálogo .

    Você deve ter um aplicativo para desenvolver o controle reutilizável. Se você não tiver um aplicativo existente para usar, crie um aplicativo baseado em caixa de diálogo usando o AppWizard.

  2. Com seu projeto carregado no Visual C++, use ClassWizard para criar uma nova classe chamada CYellowEdit com base em CEdit.

  3. Adicione três variáveis de membro à sua CYellowEdit classe. As duas primeiras serão variáveis COLORREF para manter a cor do texto e a cor do plano de fundo. O terceiro será um CBrush objeto que segurará o pincel para pintar o fundo. O CBrush objeto permite que você crie o pincel uma vez, apenas referenciando-o depois disso, e destrua o pincel automaticamente quando o CYellowEdit controle for destruído.

  4. Inicialize as variáveis de membro escrevendo o construtor da seguinte maneira:

    CYellowEdit::CYellowEdit()
    {
        m_clrText = RGB(0, 0, 0);
        m_clrBkgnd = RGB(255, 255, 0);
        m_brBkgnd.CreateSolidBrush(m_clrBkgnd);
    }
    
  5. Usando ClassWizard, adicione um manipulador para a mensagem de WM_CTLCOLOR refletida à sua CYellowEdit classe. Observe que o sinal de igual na frente do nome da mensagem na lista de mensagens que você pode manipular indica que a mensagem está refletida. Isso é descrito em Definindo um manipulador de mensagens para uma mensagem refletida.

    ClassWizard adiciona a seguinte macro de mapa de mensagens e função de esqueleto para você:

    ON_WM_CTLCOLOR_REFLECT()
    // Note: other code will be in between....
    
    HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor)
    {
        // TODO: Change any attributes of the DC here
        // TODO: Return a non-NULL brush if the
        //       parent's handler should not be called
        return NULL;
    }
    
  6. Substitua o corpo da função pelo código a seguir. O código especifica a cor do texto, a cor do plano de fundo do texto e a cor do plano de fundo para o restante do controle.

    pDC->SetTextColor(m_clrText);   // text
    pDC->SetBkColor(m_clrBkgnd);    // text bkgnd
    return m_brBkgnd;               // ctl bkgnd
    
  7. Crie um controle de edição na caixa de diálogo e, em seguida, anexe-o a uma variável membro clicando duas vezes no controle de edição enquanto mantém pressionada uma tecla de controle. Na caixa de diálogo Adicionar variável de membro, termine o nome da variável e escolha "Control" para a categoria e, em seguida, "CYellowEdit" para o tipo de variável. Não se esqueça de definir a ordem de tabulação na caixa de diálogo. Além disso, certifique-se de incluir o arquivo de cabeçalho para o CYellowEdit controle no arquivo de cabeçalho da caixa de diálogo.

  8. Crie e execute seu aplicativo. O controle de edição terá um fundo amarelo.

Ver também

Notas técnicas por número
Notas técnicas por categoria