Partilhar via


TN014: Controles personalizados

Esta nota descreve o suporte MFC para controles personalizados e de desenho automático. Ele também descreve a subclassificação dinâmica e descreve a relação entre objetos CWnd e HWNDs.

O aplicativo de exemplo MFC CTRLTEST ilustra como usar muitos controles personalizados. Consulte o código-fonte do exemplo geral MFC CTRLTEST e ajuda online.

Owner-Draw Controlos/Menus

O Windows fornece suporte para controlos de desenho próprio e menus através de mensagens do Windows. A janela pai de qualquer controle ou menu recebe essas mensagens e chama funções em resposta. Você pode substituir essas funções para personalizar a aparência visual e o comportamento do seu controle ou menu de desenho do proprietário.

MFC suporta diretamente o desenho do proprietário com as seguintes funções:

Você pode substituir essas funções em sua CWnd classe derivada para implementar o comportamento de desenho personalizado.

Esta abordagem não conduz a código reutilizável. Se você tiver dois controles semelhantes em duas classes diferentes CWnd , deverá implementar o comportamento de controle personalizado em dois locais. A arquitetura de controle de autodesenho suportada pelo MFC resolve esse problema.

Self-Draw Controles e Menus

MFC fornece uma implementação padrão (nas classes CWnd e CMenu) para as mensagens owner-draw padrões. Essa implementação padrão decodificará os parâmetros owner-draw e delegará as mensagens owner-draw aos controles ou menu. Isso é chamado de desenho automático porque o código de desenho está na classe do controlo ou menu, não na janela do proprietário.

Utilizando controles de desenho próprio, é possível criar classes de controle reutilizáveis que usam semântica de desenho personalizada para exibir o controle. O código para desenhar o controle está na classe de controle, não em seu pai. Esta é uma abordagem orientada a objetos para programação de controle personalizada. Adicione a seguinte lista de funções às suas classes de desenho automático:

  • Para botões de desenho automático:

    CButton::DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw this button
    
  • Para menus de desenho próprio:

    CMenu::MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this menu
    CMenu::DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this menu
    
  • Para caixas de listagem auto-desenhadas:

    CListBox::MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this list box
    CListBox::DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this list box
    
    CListBox::CompareItem(LPCOMPAREITEMSTRUCT);
    // insert code to compare two items in this list box if LBS_SORT
    CListBox::DeleteItem(LPDELETEITEMSTRUCT);
    // insert code to delete an item from this list box
    
  • Para caixas de combinação de desenho automático:

    CComboBox::MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this combo box
    CComboBox::DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this combo box
    
    CComboBox::CompareItem(LPCOMPAREITEMSTRUCT);
    // insert code to compare two items in this combo box if CBS_SORT
    CComboBox::DeleteItem(LPDELETEITEMSTRUCT);
    // insert code to delete an item from this combo box
    

Para obter detalhes sobre as estruturas de desenho do proprietário (DRAWITEMSTRUCT, MEASUREITEMSTRUCT, COMPAREITEMSTRUCT e DELETEITEMSTRUCT), consulte a documentação do MFC para CWnd::OnDrawItem, CWnd::OnMeasureItem, CWnd::OnCompareItem, e CWnd::OnDeleteItem respectivamente.

Usando controles e menus de desenho automático

Para menus de desenho próprio, deve substituir ambos os métodos, OnMeasureItem e OnDrawItem.

Para caixas de listagem de desenho automático e caixas de combinação, você deve substituir OnMeasureItem e OnDrawItem. Você deve especificar o estilo LBS_OWNERDRAWVARIABLE para caixas de listagem ou estilo CBS_OWNERDRAWVARIABLE para caixas de combinação no modelo de diálogo. O estilo OWNERDRAWFIXED não funcionará com itens de desenho automático porque a altura fixa do item é determinada antes que os controles de autodesenho sejam anexados à caixa de listagem. (Você pode usar os métodos CListBox::SetItemHeight e CComboBox::SetItemHeight para superar essa limitação.)

Mudar para um estilo OWNERDRAWVARIABLE forçará o sistema a aplicar o estilo NOINTEGRALHEIGHT ao controle. Como o controle não pode calcular uma altura integral com itens de tamanho variável, o estilo padrão de INTEGRALHEIGHT é ignorado e o controle é sempre NOINTEGRALHEIGHT. Se os itens tiverem altura fixa, você poderá impedir que itens parciais sejam desenhados especificando o tamanho do controle como um multiplicador inteiro do tamanho do item.

Para caixas de listagem de autodesenho e caixas de combinação com o estilo LBS_SORT ou CBS_SORT, deve-se substituir o método OnCompareItem.

Para caixas de listagem de auto-desenho e caixas de combinação, OnDeleteItem geralmente não é substituído. Você pode substituir OnDeleteItem se quiser executar qualquer processamento especial. Um caso em que isso seria aplicável é quando memória adicional ou outros recursos são armazenados com cada caixa de listagem ou item de caixa de combinação.

Exemplos de Self-Drawing controles e menus

O exemplo geral do MFC CTRLTEST fornece amostras de um menu de auto-desenho e uma caixa de listagem de auto-desenho.

O exemplo mais típico de um botão de autodesenho é um botão bitmap. Um botão bitmap é um botão que mostra uma, duas ou três imagens bitmap para os diferentes estados. Um exemplo disso é fornecido na classe MFC CBitmapButton.

Subclassificação dinâmica

Ocasionalmente, você desejará alterar a funcionalidade de um objeto que já existe. Os exemplos anteriores exigiam que você personalizasse os controles antes que eles fossem criados. A subclassificação dinâmica permite personalizar um controle que já foi criado.

Subclassificação é o termo do Windows para substituir o WndProc de uma janela por um personalizado WndProc e chamar o antigo WndProc para a funcionalidade padrão.

Isso não deve ser confundido com derivação de classe C++. Para esclarecimento, os termos C++ classe base e classe derivada são análogos a superclasse e subclasse no modelo de objeto do Windows. A derivação C++ com MFC e a subclassificação do Windows são funcionalmente semelhantes, exceto que C++ não suporta subclassificação dinâmica.

A CWnd classe fornece a conexão entre um objeto C++ (derivado de CWnd) e um objeto de janela do Windows (conhecido como ).HWND

Há três maneiras comuns de como estes se relacionam:

  • CWnd cria o HWND. Você pode modificar o comportamento em uma classe derivada criando uma classe derivada de CWnd. O HWND é criado quando seu aplicativo chama CWnd::Create.

  • A aplicação anexa um CWnd a um HWND. O comportamento da janela existente não é modificado. Este é um caso de delegação e é tornado possível ao chamar CWnd::Attach para criar um alias de um HWND num objecto CWnd.

  • CWnd está anexado a um existente HWND e você pode modificar o comportamento em uma classe derivada. Isso é chamado de subclassificação dinâmica porque estamos alterando o comportamento e, portanto, a classe de um objeto do Windows em tempo de execução.

Você pode obter subclassificação dinâmica usando os métodos CWnd::SubclassWindow e CWnd::SubclassDlgItem.

Ambas as rotinas anexam um objeto CWnd a um HWND existente. SubclassWindow toma diretamente o HWND. SubclassDlgItem é uma função auxiliar que usa um ID de controle e a janela pai. SubclassDlgItem foi projetado para anexar objetos C++ a controles de diálogo criados a partir de um modelo de diálogo.

Consulte o exemplo CTRLTEST para obter vários exemplos de quando usar SubclassWindow e SubclassDlgItem.

Ver também

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