Partilhar via


Controles de subclassificação

Se um controle faz quase tudo o que você quer, mas você precisa de mais alguns recursos, você pode alterar ou adicionar recursos ao controle original subclassificando-o. Uma subclasse pode ter todos os recursos de uma classe existente, bem como quaisquer recursos adicionais que você queira dar-lhe.

Este documento discute como as subclasses são criadas e inclui os tópicos a seguir.

Controles de subclassificação anteriores à ComCtl32.dll versão 6

Você pode colocar um controle em uma subclasse e armazenar dados do usuário dentro de um controle. Você faz isso quando usa versões do ComCtl32.dll anteriores à versão 6. Existem algumas desvantagens na criação de subclasses com versões anteriores do ComCtl32.dll.

Para criar um novo controle, é melhor começar com um dos controles comuns do Windows e estendê-lo para atender a uma necessidade específica. Para estender um controle, crie um controle e substitua seu procedimento de janela existente por um novo. O novo procedimento interceta as mensagens do controle e age sobre elas ou as passa para o procedimento original para processamento padrão. Use a função SetWindowLong ou a função SetWindowLongPtr para substituir o WNDPROC do controlo. O exemplo de código a seguir mostra como substituir um WNDPROC.

OldWndProc = (WNDPROC)SetWindowLongPtr (hButton,
GWLP_WNDPROC, (LONG_PTR)NewWndProc);

Armazenando dados do usuário

Talvez você queira armazenar dados do usuário com uma janela individual. Esses dados podem ser usados pelo novo procedimento de janela para determinar como desenhar o controle ou para onde enviar determinadas mensagens. Por exemplo, você pode usar dados para armazenar um ponteiro de classe C++ para a classe que representa o controle. O exemplo de código a seguir mostra como usar SetProp para armazenar dados com uma janela.

SetProp (hwnd, TEXT("MyData"), (HANDLE)pMyData);

Desvantagens da antiga abordagem de subclassificação

A lista a seguir aponta algumas das desvantagens de usar a abordagem descrita anteriormente para subclassificar um controle.

  • O procedimento de janela só pode ser substituído uma vez.
  • É difícil remover uma subclasse depois que ela é criada.
  • Associar dados privados a uma janela é ineficiente.
  • Para chamar o próximo procedimento em uma cadeia de subclasses, você não pode converter o procedimento de janela antigo e chamá-lo, você deve chamá-lo usando a funçãoCallWindowProc.

Controles de subclassificação usando o ComCtl32.dll versão 6

Observação

versão 6 do ComCtl32.dll é apenas Unicode. Os controles comuns suportados pelo ComCtl32.dll versão 6 não devem ser subclassificados (ou superclassificados) com procedimentos de janela ANSI.

 

ComCtl32.dll versão 6 contém quatro funções que facilitam a criação de subclasses e eliminam as desvantagens discutidas anteriormente. As novas funções encapsulam o gerenciamento envolvido com vários conjuntos de dados de referência, portanto, o desenvolvedor pode se concentrar em recursos de programação e não no gerenciamento de subclasses. As funções de subclassificação são:

SetWindowSubclass

Esta função é usada inicialmente para subclassificar uma janela. Cada subclasse é identificada exclusivamente pelo endereço do pfnSubclass e pelo seu uIdSubclass. Ambos são parâmetros da funçãoSetWindowSubclass. Várias subclasses podem partilhar o mesmo procedimento de subclassificação e o ID pode identificar cada chamamento. Para alterar os dados de referência, você pode fazer chamadas subsequentes para SetWindowSubclass. A vantagem importante é que cada instância de subclasse tem seus próprios dados de referência.

A declaração de um procedimento de subclasse é ligeiramente diferente de um procedimento de janela regular porque tem duas partes adicionais de dados: o ID da subclasse e os dados de referência. Os dois últimos parâmetros da seguinte declaração de função mostram isso.

LRESULT CALLBACK MyWndProc (HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass,
DWORD_PTR dwRefData);

Sempre que uma mensagem é recebida pelo procedimento da nova janela, um ID de subclasse e dados de referência são incluídos.

Observação

Todas as cadeias de caracteres passadas para o procedimento são cadeias de caracteres Unicode, mesmo que Unicode não seja especificado como uma definição de pré-processador.

 

O exemplo a seguir mostra uma implementação de esqueleto de um procedimento de janela para um controle subclassificado.

LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
                               LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
    case WM_PAINT:
        .
        .
        .
        return TRUE;
    // Other cases...
    } 
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

O procedimento de janela pode ser associado ao controlo no manipulador de WM_INITDIALOG do procedimento de diálogo, conforme mostrado no exemplo a seguir.

case WM_INITDIALOG:
{
    HWND button = GetDlgItem(hDlg, IDC_OWNERDRAWBUTTON);
    SetWindowSubclass(button, OwnerDrawButtonProc, 0, 0);
    return TRUE;
}

GetWindowSubclass

Esta função recupera informações sobre uma subclasse. Por exemplo, você pode usar GetWindowSubclass para acessar os dados de referência.

RemoveWindowSubclass

Esta função remove subclasses. RemoveWindowSubclass em combinação com SetWindowSubclass permite adicionar e remover subclasses dinamicamente.

DefSubclassProc

A função DefSubclassProc chama o próximo manipulador na cadeia de subclasses. A função também recupera o ID adequado e os dados de referência e passa a informação para o procedimento da janela seguinte.