Componentes externos (II)

En esta ocasión aprenderemos qué son los editores de propiedades, cómo usarlos en nuestros componentes y desarrollaremos un sencillo editor de propiedades paso a paso.

Un editor de propiedades es una extensión del IDE que permite manipular una propiedad publicada de un componente en tiempo de diseño y ofrece una manera sencilla de establecer y/o recuperar su valor, haciendo más cómoda la utilización y configuración de un componente.

Los editores de propiedades son una poderosa herramienta que puede marcar la diferencia entre un componente aceptable y uno realmente formidable. A través de ellos podremos dotarlos de nuevas características que van más allá de la simple validación del valor de las propiedades, pudiendo mostrar una lista de valores, acotar valores, mostrar formularios que permitan la asignación del valor de una o varias propiedades, etc.

Para introducir el valor de las propiedades en tiempo de diseño se utiliza el inspector de objetos, el cuál muestra una columna con el nombre de la propiedad y otra con el valor de dicha propiedad. Su uso es sencillo, se introduce un nuevo valor y listo. ¿Fácil, eh? Aunque externamente parece algo trivial, internamente, el inspector de objetos se comunica con los componentes usando sus editores de propiedades para obtener o fijar el valor, para informar de cómo se debe almacenar una propiedad, etc.

Editores estándar

Xailer incluye una serie de editores de propiedades por defecto que son suficiente para la mayoría de las propiedades con las que trabajamos habitualmente, pero también permite que creemos nuestros propios editores, derivemos de ellos y que incluso reemplacemos los que una determinada propiedad tiene por defecto.

PE_Color
PE_Icon
PE_Anchors
PE_Font
PE_Cursor
PE_Brush
PE_StringOrNil
PE_ExtendedString
PE_Picture
PE_StringList
PE_NumberList
PE_MultiList
PE_Control
PE_Component
PE_ImageList
PE_Menu
PE_Edit
PE_DataField
PE_BrowseFolder
PE_BrowseFile
PE_BrwRecSel
PE_ButtonBitmap
PE_Tooltip
PE_DbfField
PE_ADOConnect
PE_DataSourceTables
PE_DbfDataSetName
PE_WideString
PE_DbfDataSource
PE_SQLiteDataSource
PE_DataSourceCatalogs
PE_TreeView

El editor básico TPropertyEditor

Estos editores derivan de la clase básica TPropertyEditor que provee el interface para que cualquiera de ellos se comunique con el inspector de objetos y el IDE.

CLASS TPropertyEditor

   DATA oObj
   DATA cProperty
   DATA aProperty
   DATA nProperty
   DATA cType
   DATA cDataType
   DATA Value
   DATA cValue
   DATA Default
   DATA aValues
   DATA lRun      INIT .F.
   DATA lExpand   INIT .F.

   METHOD Get( oObj, nProperty )
   METHOD Set( Value, nIndex )
   METHOD Load( cValue )
   METHOD Save( cPrefix, cSufix )
   METHOD DblClick( Value ) VIRTUAL
   METHOD Run( Value )

ENDCLASS

* DATA cProperty
Contiene el nombre de la propiedad inspeccionada

* DATA cType
Es el tipo de dato del valor actual de la propiedad

* DATA cDataType
Es el tipo de dato indicado en la cláusula AS … de la declaración de la propiedad

* DATA Value
El valor actual de la propiedad

* DATA cValue
Es el valor actual de la propiedad en formato cadena para mostrar en el inspector

* DATA Default
Es el valor por defecto para la propiedad (cláusula INIT de la declaración)

* DATA aValues
Es el array de valores para mostrar en un combo en el inspector. Es un array de dos dimensiones (nºelementos x 2 columnas), donde la primera columna es el valor de cadena a mostrar en el combo del inspector, y la segunda columna es el valor real que hay que asignar a la propiedad.

* DATA oObj
Contiene una instancia del objeto al que pertenece la propiedad

* DATA lRun
Indica si se muestra el botón «…» cuando la propiedad tiene el foco.

* DATA lExpand
Muestra el pequeño triángulo naranja en el inspector que sirve para abrir un formulario con un memo con el valor de la propiedad.

* METHOD DblClick( @Value )
Se ejecuta al hacer doble click en el inspector y recibe el valor actual de la propiedad por referencia. Si no se define este método, por defecto, llama a Run().

* METHOD Run( @Value )
Se encarga de mostrar el interface de usuario si la propiedad lo requiere y se ejecuta al pulsar el botón «…». También recibe el valor actual de la propiedad por referencia. Debe devolver .T. para actualizar la propiedad y .F. para dejar su valor anterior.

* METHOD Get( oObj, nProperty )
Obtiene el valor asignado a la propiedad | del objeto y asigna el resto de las datas del editor de propiedades (cProperty, cType, Value, etc.). Siempre conviene llamar a Super:Get(…)

* METHOD Set( Value, nIndex )
Asigna el valor a la propiedad correspondiente del objeto inspeccionado. sólo tiene valor cuando en el inspector aparece un combo para cambiar el valor de la propiedad. Siempre conviene llamar a Super:Set(…)

* METHOD Load( cValue )
Asigna el valor de la propiedad a partir de la cadena leida desde el fichero .xfm

* METHOD Save( cPrefix, cSufix )
Devuelve la cadena que hay que guardar en el fichero .xfm a partir del valor de la propiedad

Escribir un editor de propiedades

Vamos a desarrollar nuestro primer editor de propiedades, que será editable sobre el propio inspector de objetos y también mostrará un formulario para cambiar el valod de la propiedad.

Los pasos necesarios para escribir un editor de propiedades son los siguientes:

* Crear una nueva clase que descienda de TPropertyEditor o de algún editor estándar.
* Desarrollar los métodos necesarios para dotar al editor de propiedades de la funcionalidad deseada.

Como norma general, se suele anteponer el prefijo PE_ a las clases que definen un editor de propiedades, por ejemplo: PE_MyColorEditor, aunque no es obligatorio.

Creando nuestro primer editor

Imaginemos que tenemos un componente con una propiedad que guarda una dirección de correo electrónico:

CLASS TMyComponent FROM TComponent

PUBLISHED:
   PROPERTY cEmail INIT ""

ENDCLASS

La opción más sencilla cuando definimos el componente sería dejarlo como está en el ejemplo pero deberíamos pensar en hacer la vida más fácil a quien vaya a usarlo, así que vamos a establecer un editor que haga una validación básica de la propiedad.

CLASS PE_EmailEditor FROM TPropertyEditor

PUBLIC:
   DATA lRun   INIT .T.

   METHOD Run( Value )
   METHOD DblClick( Value ) INLINE ::Run( @Value )

   METHOD MailValidate( oSender )

ENDCLASS

En la definición del editor establecemos lRun a .T. para indicar que la propiedad debe mostrar el botón de acción (los puntos «…») y hacemos que se lance la misma acción al hacer doble click que al pulsar el botón de acción.

METHOD Run( Value ) CLASS PE_EmailEditor

   LOCAL oForm
   LOCAL oEditMail
   LOCAL lReturn := .F.

   WITH OBJECT oForm := TMailEditForm():New( Application )
      :SetBounds( 235, 197, 302, 145 )
      :SetClientSize( 294, 118 )
      :cText := "Email PropertyEditor"
      :nBorderStyle := bsDIALOG
      :lHideOnClose := .T.
      :Create()
   END

   WITH OBJECT TLabel():New( oForm )
      :SetBounds( 12, 12, 27, 14 )
      :cText := "EMail"
      :Create()
   END

   WITH OBJECT oEditMail := TEdit():New( oForm )
      :SetBounds( 12, 28, 270, 20 )
      :Create()
   END

   WITH OBJECT TButton():New( oForm )
      :SetBounds( 12, 80, 80, 25 )
      :cText := "&Validate"
      :lDefault := .T.
      :OnClick := "MailValidate"
      :Create()
   END

   WITH OBJECT TButton():New( oForm )
      :SetBounds( 112, 80, 80, 25 )
      :cText := "Ok"
      :nModalResult := mrOK
      :Create()
   END

   WITH OBJECT TButton():New( oForm )
      :SetBounds( 204, 80, 80, 25 )
      :cText := "Cancel"
      :nModalResult := mrCANCEL
      :Create()
   END

     IF :ShowModal() == mrOK
        IF ::MailValidate( oEditMail:Value )
           Value := oEditMail:Value
           lReturn := .T.
        ENDIF
        :End()
     ENDIF
   END

RETURN lReturn

METHOD MailValidate( oSender ) CLASS PE_EmailEditor

   LOCAL lValid := .F.

   //Comprobamos que incluye la arroba y el punto
   IF Empty( oSender:Value ) .OR. At( "@", oSender:Value ) > 0 .OR. At( ".", oSender:Value ) > 0
      lValid := .T.
   ENDIF

RETURN lValid

Este sencillo editor muestra un formulario con un TEdit para introducir la dirección de email y tres botones para validar la dirección y para Aceptar o Cancelar el formulario.

Tras cerrar el formulario, volvemos a comprobar si la dirección es correcta llamando a ::MailValidate() y sólo actualizamos la propiedad y devolvemos .T. en caso de que la validación sea correcta.

Sólo nos queda enlazar a nuestra propiedad con su nuevo editor, así que la declaramos:

CLASS TMyComponent FROM TComponent

PUBLISHED:
   PROPERTY cEmail INIT "" EDITOR PE_EmailEditor

ENDCLASS

En el ZIP adjunto se encuentran todos los fuente del componente de ejemplo y una DLL ya compilada para probarla en el IDE (ver post)

2 comentarios en “Componentes externos (II)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *