Compartilhar via


TN014: Controles personalizados

Esta nota descreve o suporte do MFC para controles personalizados e auto-desenho. Ele também descreve a subclasse 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 para o exemplo geral do MFC CTRLTEST e ajuda online.

Controles/Menus de Owner-Draw

O Windows fornece suporte para menus e controles de desenho de proprietário usando 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.

O MFC dá suporte diretamente ao 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.

Essa abordagem não leva 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 auto-desenho com suporte do MFC resolve esse problema.

Controles e menus do Self-Draw

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

Usando controles de autodesenho, você pode criar classes de controle reutilizáveis que utilizam semântica de desenho proprietário para exibir o controle. O código para desenhar o controle está na classe do controle, não em sua classe pai. Essa é uma abordagem orientada a objetos para programação de controle personalizada. Adicione a seguinte lista de funções às classes de auto-desenho:

  • Para botões de auto-desenho:

    CButton::DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw this button
    
  • Para menus de auto-desenho:

    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 auto-desenhadas:

    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::OnMeasureIteme CWnd::OnCompareItemCWnd::OnDeleteItem respectivamente.

Usando controles e menus de auto-desenho

Para menus autodesenhados, você deve substituir os métodos OnMeasureItem e OnDrawItem.

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

Alternar para o 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 forem de 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 autodesenho e caixas de combinação com o estilo LBS_SORT ou CBS_SORT, você deve substituir o método OnCompareItem.

Geralmente, para caixas de listagem e caixas de combinação auto desenhadas, OnDeleteItem 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 controles e menus de Self-Drawing

O exemplo geral do MFC CTRLTEST fornece exemplos de um menu de desenho automático e uma lista de desenho automático.

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

Subclasse dinâmica

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

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

Isso não deve ser confundido com derivação de classe C++. Para esclarecimento, a classe base de termos C++ e a classe derivada são análogas à superclasse e à subclasse no modelo de objeto do Windows. A derivação em C++ com subclassificação do MFC e do Windows é funcionalmente semelhante, 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 relacionadas a elas:

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

  • O aplicativo anexa um CWnd a um HWND existente. O comportamento da janela existente não é modificado. Esse é um caso de delegação e é possível fazendo isso ao chamar CWnd::Attach para definir um alias para um objeto existente de HWND para um objeto CWnd.

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

Você pode obter subclasse dinâmica usando os métodos CWnd::SubclassWindow e CWnd::SubclassDlgItem.

Ambas as rotinas anexam um CWnd objeto a um existente HWND. SubclassWindow assume diretamente HWND . SubclassDlgItem é uma função auxiliar que usa uma 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 caixa de diálogo.

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

Consulte também

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