Las clases X y las clases T

Muchos de vosotros ya conocéis que la jerarquía de clases de Xailer es bastante extensa y que, además, tiene la mayoría de estas clases duplicadas entre clases X y clases T. Concretamente, la jerarquía es algo así:

XComponent -> TComponent -> XWinObject -> TWinObject -> XControl -> TControl -> etc.

En la jerarquía que aparece en la ayuda no se muestra esta dualidad de clases, sino que aparecen sólo las clases T. Pero realmente existen también las clases X, y son precisamente estas las que contienen todo el código, permaneciendo las clases T completamente vacías. P.ej., la clase TControl está declarada así:

CLASS TControl FROM XControl
ENDCLASS

Y ahora bien, ¿para qué queremos tener las clases duplicadas? ¿qué conseguimos con esto?


Si no se conoce cómo aprovechar esta característica, pues sirve más bien de poco. Pero como vamos a ver a continuación, el beneficio es enorme.

Yo utilizaba anteriormente cierta librería xbase para programar en windows que no voy a nombrar, y que muchos de vosotros conocéis. Y también sabéis que si queríamos corregir algún bug de un control, o modificar un comportamiento o hacer cualquier otra modificación, no nos quedaba más remedio que coger el fuente de la clase correspondiente, hacer las modificaciones oportunas y añadirlo a nuestro programa. O meter el obj corregido en la librería original o en alguna librería destinada a tal fin. Todo un engorro. Al final llegué a tener una librería de parches que ocupaba casi tanto como la librería original, y cuando tenía que actualizarla me echaba a temblar.

Pues bien, con la técnica de las clases X y las clases T ya no hace falta. Vamos a suponer que hubiera un bug en el método SetSel() de TEdit. Pues para corregirlo sólo tenemos que añadir el siguiente código en algún módulo de nuestro programa (o en alguna librería propia):

CLASS TEdit FROM XEdit
   METHOD SetSel( nStart, nEnd ) INLINE ;
          ::SendMsg( EM_SETSEL, nStart, nEnd )
ENDCLASS

Eso es todo. Si os fijáis bien, lo que hemos hecho ha sido declarar una nueva clase TEdit derivada de XEdit. Y en esta nueva clase hemos sobrescrito el método SetSel() con una versión corregida. Y no hemos necesitado para nada el código fuente original de la clase, ni tendremos problemas con cada nueva actualización, ni vamos a tener un sinfín de módulos por ahí perdidos con código parcheado del GUI.

Y esto es en caso de algún bug, pero las posibilidades llegan aún más lejos. Supongamos que queremos que los controles edit de nuestro programa se muestren en color amarillo claro cuando tienen el foco. Lógicamente podemos modificar el valor de la propiedad nClrPaneFocus de todos y cada uno de los edit (uf! qué cantidad de trabajo, ¿no?). Pero es mucho más sencillo aplicar la técnica que estamos comentando de esta forma:

CLASS TEdit FROM XEdit
   PROPERTY nClrPaneFocus  INIT RGB( 255, 255, 192 )
ENDCLASS

Además, como TMaskEdit, TEditBtn, TDateEdit, TDBEdit, TDBMaskEdit, etc. derivan directa o indirectamente de TEdit, todos estos controles mostrarán este comportamiento.

Imaginad también que queremos publicar una demo de nuestra aplicación, de forma que no se puedan introducir fechas más allá del 31-12-05. Podemos incluir este código:

CLASS TMaskEdit FROM XMaskEdit
   METHOD Valid( oNextCtl )
ENDCLASS

METHOD Valid( oNextCtl ) CLASS TMaskEdit
   LOCAL uRet := Super:Valid( oNextCtl )
   IF ::cType == "D" .AND. Day( ::Value ) > 0
      IF DTOS( ::Value ) > "20052131"
         MsgStop( "La fecha no es válida para esta demo." )
         RETURN .F.
      ENDIF
   ENDIF
RETURN uRet

Bueno, estos son sólo unos ejemplos de uso de esta técnica, pero las posibilidades son enormes, y sólo están limitadas por la imaginación.