el Guille, la Web del Visual Basic, C#, .NET y más...

Cambiando el comportamiento predefinido de un control (III)

 Sobreescribir métodos virtuales

 

Autor: RFOG (MVP de Visual C++)
Publicado: 20/Sep/2010
Actualizado: 20/Sep/2010

Tras haber visto cómo heredar y sustituir un control dentro de un cuadro de diálogo, ahora vamos a ver cómo aprovechar la infraestructura del propio control mediante la sobreescritura de métodos virtuales.


elGuille.hosting: OFERTA Multi Dominio por 40.95 Eur al mes



 

Introducción:

Tras haber visto cómo heredar y sustituir un control dentro de un cuadro de diálogo, ahora vamos a ver cómo aprovechar la infraestructura del propio control mediante la sobreescritura de métodos virtuales.

En la primera entrada de esta serie vimos cómo se podía sustituir un control existente por uno nuestro heredado del sustituido y cómo MFC soporta esta práctica sin problemas y sin florituras.

Ahora es el momento de ver qué tan buenos son los programadores de Microsoft y cómo nos han dado soporte extendido para este control ya que, como vimos, no hay nada de forma inmediata.

Si os dais cuenta, tampoco hay documentación sobre el control, apenas unas líneas describiendo qué hace… No os extrañéis, pero esto es bastante habitual no sólo con Microsoft, sino con la mayora de implementadores de extensiones para MFC, y la verdad es que cabrea mucho, pero es lo que hay.

La solución, algo bastante habitual en C++, es navegar a través del código fuente de MFC hasta encontrar el del componente. Podríamos buscar la carpeta con los fuentes de MFC, y luego con alguna utilidad de búsqueda dentro de ficheros, encontrar la definición de la clase, pero hay otra forma más rápida, y es a través de la depuración.

Nos vamos a MyVSListbox.cpp y ponemos un punto de interrupción en el constructor de la clase. Ejecutamos y el código se nos parará en dicho lugar. Luego le damos a “step into” y ¡tachán!, el IDE ha hecho nuestro trabajo:

Él solo ha encontrado no solo el fichero fuente, sino la propia definición de la clase. Únicamente nos falta apuntar con el ratón a algún elemento de la clase y elegir “Go To declaration”. En este caso se nos abre una ventana de “Find Symbols” porque Visual Sutdio no tiene del todo claro dónde está la clase. Pero si miramos en la ventana lo que está haciendo es apuntarnos a dos lugares de la misma clase y del mismo fichero. Elegimos uno de ellos y se nos abre el fichero “faxvslistbox.h”, y ahí está la declaración de nuestra clase.

[Nota: esto también podríamos haberlo hecho desde el principio sin necesidad de lanzar el depurador, pero así os damos otra forma más para hacerlo y para navegar dentro del código fuente de MFC].

¿Qué soporte nos han dado? Pues si vemos la clase, observamos que lo único que se ha hecho es redefinir algunos métodos ya existentes en un cuadro de lista normal y corriente y capturar algunos mensajes (y ese es el motivo por el que nosotros no vemos los mensajes: los métodos de captura ni son virtuales ni permiten que se siga llamando a la cadena de mensajes).

Debemos, pues, seguir mirando en la clase padre, que si nos fijamos es CVSListBoxBase. Repitiendo el “Go To Declaration” se nos abrirá la clase en cuestión, que resulta está en el mismo fichero.

Y ahora sí, ahora sí que hemos encontrado algo interesante:

       virtual void OnSelectionChanged() {}

 

       // "Standard" action overrides

       virtual BOOL OnBeforeRemoveItem(int /*iItem*/) { return TRUE; }

       virtual void OnAfterAddItem(int /*iItem*/) {}

       virtual void OnAfterRenameItem(int /*iItem*/) {}

       virtual void OnAfterMoveItemUp(int /*iItem*/) {}

       virtual void OnAfterMoveItemDown(int /*iItem*/) {}

 

Eso es lo que queríamos encontrar: cómo reaccionar ante los eventos más comunes que pueden ocurrir en un cuadro de lista: El cambio de elemento seleccionado, el acto de añadir, renombrar o cambiar de sitio un elemento. Y una especial que si devolvemos FALSE el elemento no será eliminado.

Vemos, por ejemplo, que los métodos son virtuales, por lo que cualquier hijo que los implemente será llamado independientemente de si ha sido instanciado desde el padre o desde el propio hijo, por lo que nos viene como anillo al dedo para nuestros propósitos: nuestra CMyVSListbox implementa cualquiera de dichos métodos, y debería funcionar.

¿Cómo sabemos que dichos métodos funcionan tal y como os he contado?: pues o bien ponemos puntos de interrupción en ellos y comprobamos cómo funcionan o bien nos vamos leyendo el código. Y desde luego hacer ambas cosas no es excluyente.

En el caso que nos ocupa, el programador ha capturado los mensajes pertinentes de cada control y nos ha integrado un interfaz común, cosa que, en este caso, es de agradecer a primera vista, pero nos impide capturar los mensajes en las clases propietarias (el cuadro de diálogo en nuestro caso).

El primer paso, para evitarnos errores, es copiar tal cual el código de las funciones de ese fichero cabecera en nuestra propia clase, y compilar a ver qué pasa:

class CMyVSListbox : public CVSListBox

{

       DECLARE_DYNAMIC(CMyVSListbox)

 

public:

       CMyVSListbox();

       virtual ~CMyVSListbox();

      

       virtual void OnSelectionChanged() {}

 

       // "Standard" action overrides

       virtual BOOL OnBeforeRemoveItem(int /*iItem*/) { return TRUE; }

       virtual void OnAfterAddItem(int /*iItem*/) {}

       virtual void OnAfterRenameItem(int /*iItem*/) {}

       virtual void OnAfterMoveItemUp(int /*iItem*/) {}

       virtual void OnAfterMoveItemDown(int /*iItem*/) {}

protected:

       DECLARE_MESSAGE_MAP()

};

 

Vemos que todo funciona perfecto, y que ahora se está llamando a nuestros nuevos métodos en lugar de a los de la clase CVSListBoxBase.

Ya sólo nos queda rellenar el cuerpo de dichos métodos con nuestro código.

Este comportamiento es muy similar al de los mensajes por reflexión: es el propio control el que trastea con sus propios mensajes en lugar de ser el contenedor o el propietario, como se hace en los cuadros de diálogo. En la entrega siguiente veremos cómo solventar esto.

 

Código fuente:

El lector tiene el código fuente de esta entrada disponible en el fichero:
MFC_09_cambiar_control_02.zip


(MD5 checksum: 9AFFE98689098277CCC32985CD0E0655)

 

 


Ir al índice de los artículos de RFOG en el sitio del Guille




La fecha/hora en el servidor es: 23/12/2024 20:26:06

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024