Red de conocimiento informático - Conocimiento informático - Cómo bloquear el ancho del encabezado de columna de ListView

Cómo bloquear el ancho del encabezado de columna de ListView

Descarga del código fuente

ListView y sus encabezados de columna son en realidad parte de un control común de Windows (Comctl32.dll). Por lo tanto, no nos resulta difícil encontrar información de control relacionada con el "Control de encabezados" en MSDN y descubrir que el bloqueo de los encabezados de columna está estrechamente relacionado con varios mensajes de notificación de Windows, que son HDN_TRACK, HDN_BEGINTRACK y HDN_ENDTRACKA. FINALTRACKA. De particular interés en este artículo es HDN_BEGINTRACK. Cuando el usuario arrastra el mouse sobre el encabezado de la columna, si la posición es exactamente en la barra divisoria que cambia el ancho, el control del encabezado de la columna enviará un mensaje de notificación HDN_BEGINTRACK a su ventana principal. Para lograr el bloqueo del ancho del encabezado de la columna, se debe fijar el mensaje de notificación. Este mensaje no se puede pasar a la ventana principal, pero como todos los demás mensajes de notificación en Windows, hay dos versiones de este mensaje: una versión es HDN_BEGINTRACKW, que se usa específicamente para caracteres anchos y conjuntos de caracteres Unicode, la otra versión es HDN_BEGINTRACKA; que se utiliza específicamente para el juego de caracteres ANSI. El uso de estas dos versiones se puede obtener del archivo de encabezado commctrl.h del control público ***:

// De commctrl.h

#ifdef UNICODE

#define HDN_BEGINTRACK HDN_BEGINTRACKW

#else

#define HDN_BEGINTRACK HDN_BEGINTRACKA

#endif

Por lo tanto, al implementar HDN_BEGINTRACK para mensajes Al procesar, de hecho, dependiendo del valor de UNICODE, se puede implementar el procesamiento HDN_BEGINTRACKA o HDN_BEGINTRACKW. HDN_BEGINTRACKA o HDN_BEGINTRACKW dependiendo del valor de UNICODE. Entonces, ¿qué mensaje envía el control de encabezado? Es importante comprender que el control de encabezado es parte de los controles comunes de Windows, implementados en la biblioteca de vínculos dinámicos comctl32.dll. Dado que la biblioteca de vínculos dinámicos está compilada en código ejecutable, cambiar la configuración UNICODE en el proyecto no ayudará. ¿Cómo saber qué versión del mensaje de notificación envía el control de encabezado de columna? ¿Es la versión A o la versión W?

Para encontrar la respuesta, debemos recurrir al mensaje muchas veces olvidado WM_NOTIFYFORMAT. Normalmente, cuando se crea un control por primera vez, envía un mensaje a la ventana principal preguntándole qué versión del mensaje de notificación desea. La ventana principal devuelve NFR_ANSI o NFR_UNICODE. Si la ventana principal no maneja WM_NOTIFYFORMAT, este mensaje se pasa a la rutina de manejo de mensajes DefWindowProc de Windows para el procesamiento predeterminado según las preferencias de la ventana principal o el propio cuadro de diálogo. El valor predeterminado es UNICODE, por lo que para conocer la versión del mensaje de notificación, debe manejar WM_NOTIFYFORMAT de ListCtrl. Para confirmar el valor de retorno de la ventana principal, puede realizar un experimento.

Si no desea lidiar con los mensajes WM_NOTIFYFORMAT, puede simplificar la solución al problema implementando los mensajes de notificación HDN_BEGINTRACKA y HDN_BEGINTRACKW, que es un enfoque más confiable y general. El programa de muestra que acompaña a este artículo demuestra este enfoque porque el código admite tanto ANSI como Unicode.

Como se muestra en la Figura 1:

El código de implementación es muy simple. El control de encabezado envía HDN_XXX a la ventana principal (ListCtrl) y la reflexión del mensaje se puede usar en MFC para procesar el mensaje de notificación del control de encabezado. . Esto se debe a que la característica "Encabezado bloqueable" en sí no es tanto una propiedad de ListCtrl sino del control Encabezado. Si no estuviera usando MFC, tendría que manejar los mensajes de notificación en ListCtrl. El programa de muestra utiliza el mecanismo de reflexión de mensajes y utiliza ON_NOTIFY_REFLECT en el control de encabezado para el mapeo de mensajes, es decir, escribir la función miembro virtual OnChildNotify: BOOL CLockableHeader:: OnChildNotify(UINT msg, WPARAM wp, LRARAM lp, LRARAM lp) LPARAM lp, LRESULT* pRes )

{

NMHDRamp; nmh = *(NMHDR*)lp;

if (nmh.code==HDN_BEGINTRACKW nmg.code== HDN_BEGINTRACKA)

return *pRes=TRUE;

......

}

Debido a que OnChildNotify es una función virtual, no es necesaria la entrada del mapa de mensajes. Simplemente implemente la función. En cualquier aplicación, el mensaje enviado por el encabezado es uno u otro, no ambos. En cualquier caso, el mensaje de notificación enviado se consumirá antes de llegar a la ventana principal. Es decir, el manejo de mensajes siempre devuelve VERDADERO, y si el ancho de un encabezado de columna está bloqueado o no se controla mediante un indicador: la aplicación modifica el valor del indicador bloqueándolo.

Si el ancho del encabezado de la columna está bloqueado, el cursor que cambia el ancho también debe estar deshabilitado para que la interfaz de usuario permanezca consistente, y no es difícil hacer esto: BOOL CLockableHeader::OnSetCursor(CWnd* pWnd, UINT nHit, UINT msg)

{

return m_bLocked ?TRUE: CHeaderCtrl::OnSetCursor(pWnd, nHit, msg);

}

si el encabezado de la columna está bloqueado, OnSetCursor devuelve VERDADERO y el cursor no se restablecerá en este momento; de lo contrario, será manejado por el control del encabezado de la columna de forma predeterminada. Cuando el ancho está bloqueado, Windows muestra un cursor de flecha estándar en lugar de un cursor con flechas izquierda y derecha cuando el mouse se mueve sobre el encabezado de una columna.

Las clases derivadas de CHeaderCtrl se pueden usar de la misma manera que los controles de diálogo, subclasificándolas en la rutina del controlador OnCreate de la ventana principal. Consulte el código fuente de muestra para obtener detalles de implementación:

// CMyView deriva de CListView

int CMyView::OnCreate(LPCREATESTRUCT lpcs)

{

VERIFY(CListView.:OnCreate(lpcs)==0);

return m_header.SubclassDlgItem(0, this) ?0: -1;

}

Dado que el ID de recurso del control Encabezado = 0, el código anterior funciona bien. Para tener una interfaz fácil de usar, el programa de muestra crea un menú de comandos y rutinas de procesamiento de actualización de la interfaz.