Controles ActiveX MFC: subclasses de um controle do Windows
Este artigo descreve o processo de subclasse de um controle comum do Windows para criar um controle ActiveX. A subclasse de um controle do Windows é um modo rápido de desenvolver um controle ActiveX. O novo controle terá as habilidades do controle do Windows com subclasse, como pintar e responder a cliques do mouse. O BUTTON de amostra de controles do ActiveX do MFC é um exemplo de criar uma subclasse do controle do Windows.
Importante
O ActiveX é uma tecnologia herdada que não deve ser usada para novo desenvolvimento. Para mais informações sobre tecnologias modernas que substituem o ActiveX, confira Controles do ActiveX.
Para criar uma subclasse de um controle do Windows, conclua as seguintes tarefas:
Substituir as funções de membro IsSubclassedControl e PreCreateWindow do COleControl
Manipular qualquer OCM (mensagem de controle ActiveX) refletida para o controle
Observação
Grande parte desse trabalho será feita para você pelo Assistente de Controle ActiveX se você selecionar o controle a ter uma subclasse criada usando a lista suspensa Selecionar Classe de Janela Pai na página Configurações de Controle.
Como substituir IsSubclassedControl e PreCreateWindow
Para substituir PreCreateWindow
e IsSubclassedControl
, adicione as seguintes linhas de código à seção protected
da declaração da classe de controle:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL IsSubclassedControl();
No arquivo de implementação de controle (.CPP), adicione as seguintes linhas de código para implementar as duas funções substituídas:
// CMyAxSubCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
BOOL CMyAxSubCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = _T("BUTTON");
return COleControl::PreCreateWindow(cs);
}
// CMyAxSubCtrl::IsSubclassedControl - This is a subclassed control
BOOL CMyAxSubCtrl::IsSubclassedControl()
{
return TRUE;
}
Observe que, neste exemplo, o controle de botão Windows é especificado em PreCreateWindow
. No entanto, é possível criar uma subclasse para qualquer controle padrão do Windows. Para mais informações sobre controles padrão do Windows, confira Controles.
Ao criar uma subclasse de um controle do Windows, especifique sinalizadores de estilo de janela específico (WS_) ou estilo de janela estendido (WS_EX_) a serem usados na criação da janela do controle. Você pode definir valores para esses parâmetros na função de membro PreCreateWindow
modificando os campos de estrutura cs.style
e cs.dwExStyle
. As modificações nesses campos devem ser feitas usando uma operação OR, para preservar os sinalizadores padrão definidos por classe COleControl
. Por exemplo, se o controle estiver subclasse do controle BUTTON e você quiser que o controle apareça como uma caixa de seleção, insira a seguinte linha de código na implementação de CSampleCtrl::PreCreateWindow
antes da instrução return:
cs.style |= BS_CHECKBOX;
Essa operação adiciona o sinalizador de estilo BS_CHECKBOX, deixando o sinalizador de estilo padrão (WS_CHILD) da classe COleControl
intacto.
Como modificar a função de membro OnDraw
Se você quiser que o controle subclasse mantenha a mesma aparência que o controle do Windows correspondente, a função de membro OnDraw
do controle deverá conter apenas uma chamada para a função de membro DoSuperclassPaint
, como no seguinte exemplo:
void CMyAxSubCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (!pdc)
return;
DoSuperclassPaint(pdc, rcBounds);
}
A função de membro DoSuperclassPaint
, implementada por COleControl
, usa o procedimento de janela do controle do Windows para desenhar o controle no contexto do dispositivo especificado, dentro do retângulo delimitador. Isso torna o controle visível mesmo quando ele não está ativo.
Observação
A função de membro DoSuperclassPaint
funcionará somente com os tipos de controle que permitem que um contexto de dispositivo seja passado como o wParam de uma mensagem WM_PAINT. Isso inclui alguns dos controles padrão do Windows, como SCROLLBAR e BUTTON, e todos os controles comuns. Para controles que não dão suporte a esse comportamento, você precisará fornecer seu código para exibir corretamente um controle inativo.
IDs de mensagem da janela refletida
Os controles do Windows normalmente enviam determinadas mensagens de janela para a janela pai. Algumas dessas mensagens, como WM_COMMAND, fornecem notificação de uma ação do usuário. Outras, como WM_CTLCOLOR, são usadas para obter informações da janela pai. Um controle ActiveX geralmente se comunica com a janela pai por outros meios. As notificações são comunicadas disparando eventos (enviando notificações de evento) e informações sobre o contêiner de controle são obtidas acessando as propriedades ambientes do contêiner. Como essas técnicas de comunicação existem, os contêineres de controle ActiveX não devem processar nenhuma mensagem de janela enviada pelo controle.
Para impedir que o contêiner receba as mensagens de janela enviadas por um controle do Windows com subclasse, COleControl
cria uma janela extra para servir como pai do controle. Essa janela extra, chamada de "refletor", é criada apenas para um controle ActiveX que cria uma subclasse de um controle do Windows e tem o mesmo tamanho e posição que a janela de controle. A janela do refletor intercepta determinadas mensagens de janela e as envia de volta ao controle. O controle, em seu procedimento de janela, pode processar essas mensagens refletidas tomando ações apropriadas para um controle ActiveX (por exemplo, disparando um evento). Confira IDs de mensagem de janela refletida para uma lista de mensagens interceptadas do Windows e suas mensagens refletidas correspondentes.
Um contêiner de controle ActiveX pode ser projetado para executar a reflexão da mensagem em si, eliminando a necessidade de COleControl
criar a janela do refletor e reduzindo a sobrecarga de tempo de execução para um controle do Windows subclasse. COleControl
detecta se o contêiner dá suporte a essa funcionalidade verificando se há uma propriedade ambiente MessageReflect com um valor true.
Para manipular uma mensagem de janela refletida, adicione uma entrada ao mapa da mensagem de controle e implemente uma função de manipulador. Como as mensagens refletidas não fazem parte do conjunto padrão de mensagens definidas pelo Windows, o Modo de Exibição de Classe não dá suporte à adição desses manipuladores de mensagens. No entanto, não é difícil adicionar um manipulador manualmente.
Para adicionar um manipulador de mensagens a uma mensagem de janela refletida manualmente, faça o seguinte:
No arquivo .H da classe de controle, declare uma função de manipulador. A função deve ter um tipo de retorno de LRESULT e dois parâmetros, com os tipos WPARAM e LPARAM, respectivamente. Por exemplo:
class CMyAxSubCtrl : public COleControl {
protected: LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam); };
No arquivo .CPP da classe de controle, adicione uma entrada ON_MESSAGE ao mapa da mensagem. Os parâmetros dessa entrada devem ser o identificador de mensagem e o nome da função de manipulador. Por exemplo:
BEGIN_MESSAGE_MAP(CMyAxSubCtrl, COleControl) ON_MESSAGE(OCM_COMMAND, &CMyAxSubCtrl::OnOcmCommand) END_MESSAGE_MAP()
Também no arquivo .CPP, implemente a função de membro
OnOcmCommand
para processar a mensagem refletida. Os parâmetros wParam e lParam são iguais aos da mensagem de janela original.
Para um exemplo de como as mensagens refletidas são processadas, confira o BUTTON de amostra de controles ActiveX do MFC. Ele demonstra um manipulador OnOcmCommand
que detecta o código de notificação BN_CLICKED e responde disparando (enviando) um evento Click
.