Compartir a través de


Controles de subclases

Si un control hace casi todo lo que desea, pero necesita algunas características más, puede cambiar o agregar características al control original subclasándola. Una subclase puede tener todas las características de una clase existente, así como las características adicionales que quiera proporcionar.

En este documento se describe cómo se crean las subclases e incluye los temas siguientes.

Controles de subclases anteriores a ComCtl32.dll versión 6

Puede colocar un control en una subclase y almacenar datos de usuario dentro de un control . Para ello, use versiones de ComCtl32.dll anteriores a la versión 6. Hay algunas desventajas en la creación de subclases con versiones anteriores de ComCtl32.dll.

Para crear un nuevo control, es mejor empezar con uno de los controles comunes de Windows y ampliarlo para ajustarse a una necesidad determinada. Para ampliar un control, cree un control y reemplace su procedimiento de ventana existente por uno nuevo. El nuevo procedimiento intercepta los mensajes del control y actúa sobre ellos o los pasa al procedimiento original para el procesamiento predeterminado. Use la función SetWindowLong o SetWindowLongPtr para reemplazar el WNDPROC del control. En el ejemplo de código siguiente se muestra cómo reemplazar un WNDPROC.

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

Almacenar datos de usuario

Es posible que quiera almacenar datos de usuario con una ventana individual. El nuevo procedimiento de ventana puede usar estos datos para determinar cómo dibujar el control o dónde enviar determinados mensajes. Por ejemplo, puede usar datos para almacenar un puntero de clase de C++ a la clase que representa el control. En el ejemplo de código siguiente se muestra cómo usar SetProp para almacenar datos con una ventana.

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

Desventajas del enfoque de subclase antiguo

En la lista siguiente se indican algunas de las desventajas de usar el enfoque descrito anteriormente para subclasar un control.

  • El procedimiento de ventana solo se puede reemplazar una vez.
  • Es difícil quitar una subclase después de crearla.
  • La asociación de datos privados con una ventana es ineficaz.
  • Para llamar al siguiente procedimiento de una cadena de subclases, no puede convertir el procedimiento de ventana anterior y llamarlo, debe llamarlo mediante la función CallWindowProc .

Controles de subclases mediante ComCtl32.dll versión 6

Nota:

ComCtl32.dll versión 6 solo es Unicode. Los controles comunes admitidos por ComCtl32.dll versión 6 no deben estar subclasados (o superclase) con procedimientos de ventana ANSI.

 

ComCtl32.dll versión 6 contiene cuatro funciones que facilitan la creación de subclases y eliminan las desventajas descritas anteriormente. Las nuevas funciones encapsulan la administración implicada con varios conjuntos de datos de referencia, por lo que el desarrollador puede centrarse en las características de programación y no en la administración de subclases. Las funciones de subclases son:

SetWindowSubclass

Esta función se usa inicialmente para subclase de una ventana. Cada subclase se identifica de forma única mediante la dirección de la pfnSubclass y su uIdSubclass. Ambos son parámetros de la función SetWindowSubclass . Varias subclases pueden compartir el mismo procedimiento de subclase y el identificador puede identificar cada llamada. Para cambiar los datos de referencia, puede realizar llamadas posteriores a SetWindowSubclass. La ventaja importante es que cada instancia de subclase tiene sus propios datos de referencia.

La declaración de un procedimiento de subclase es ligeramente diferente de un procedimiento de ventana normal porque tiene dos fragmentos de datos adicionales: el identificador de subclase y los datos de referencia. Los dos últimos parámetros de la siguiente declaración de función muestran esto.

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

Cada vez que el nuevo procedimiento de ventana recibe un mensaje, se incluyen un identificador de subclase y datos de referencia.

Nota

Todas las cadenas que se pasan al procedimiento son cadenas Unicode, incluso si Unicode no se especifica como definición de preprocesador.

 

En el ejemplo siguiente se muestra una implementación de esqueleto de un procedimiento de ventana para un control con subclases.

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);
}

El procedimiento de ventana se puede adjuntar al control en el controlador WM_INITDIALOG del procedimiento de diálogo, como se muestra en el ejemplo siguiente.

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

GetWindowSubclass

Esta función recupera información sobre una subclase. Por ejemplo, puede usar GetWindowSubclass para acceder a los datos de referencia.

RemoveWindowSubclass

Esta función quita las subclases. RemoveWindowSubclass en combinación con SetWindowSubclass permite agregar y quitar subclases dinámicamente.

DefSubclassProc

La función DefSubclassProc llama al siguiente controlador de la cadena de subclases. La función también recupera el identificador y los datos de referencia adecuados y pasa la información al siguiente procedimiento de ventana.