Cómo programar componentes en Gambas
Introducción
Toda la información a continuación es para Gambas 3.
-
En la pestaña "General" del propieades de proyecto, debe cambiar el "project type" a "Component".
-
Entonces la pestaña "Information" se hace disponible.
Debe llenarse con los siguientes detalles:
-
El progreso del componente (es decir, si es estable o no).
-
Las características requeridas.
-
Los componentes requeridos.
-
Los componentes excluidos.
-
Algunas de las clases de proyectos se exportan.
-
Las clases exportadas que son controles deben declarar algunas constantes públicas especiales que le dirán al IDE toda la información necesaria para administrar el control.
Muchos componentes oficiales de gambas ya están escritos en gambas, y puedes usarlos como ejemplos.
El código fuente de estos componentes se encuentra en el
Esta es la lista de dichos componentes:
Algunos componentes escritos en C/C++ tienen también partes escritas en gambas:
El código fuente de la parte de gambas está dentro del directorio fuente de ese componente. Por ejemplo, la parte de gambas de
gb.qt4 está en
/gb.qt4/src
.
Clases Exportadas
El propósito de un componente es proporcionar nuevas clases al intérprete de Gambas.
Las clases que queremos proveer deben ser
exportadas desde nuestro proyecto, de otro modo el usuario de tu proyecto no podrá verlas o usarlas.
Para marcar una clase como
exportada, sólo hay que añadir la palabra clave
EXPORT al principio del código de la clase.
Si un método o una propiedad de una clase exportada devuelve un objeto de otra clase declarada en tu componente, entonces esa otra clase debería de ser exportada igualmente.
De otro modo, el usuario no podrá guardar una referencia a ella, a menos que use el tipo de dato
Object.
Si una clase exportada hereda de otra clase declarada en tu componente, esta otra clase debería de ser exportada también.
De otro modo, se producirá un error cuando el intérprete intente cargar el componente.
Un buen ejemplo de un componente sencillo con clases exportadas es
gb.settings y su clase
Settings.
Clases Exportadas Ocultas
Si tienes que exportar algunas clases que no quieres que sean visibles al usuario, puedes ocultarlas simplemente comenzando su nombre con un guión bajo.
Por ejemplo, mira el código fuente de
gb.desktop y verás muchas clases exportadas que no son visibles explícitamente.
Con esto, podemos reemplazar el concepto de "clase " existente sólo en componentes escritos en C/C++.
Controles
Los controles son clases exportadas especiales que aparecen en la caja de herramientas de controles del IDE.
Los controles son generalmente elementos gráficos que muestran algo y que sirven para interactuar con el usuario.
Pero también pueden ser clases normales y no tener una parte gráfica, como el control
Timer. En estos casos los llamamos controles
es.
Los componentes gráficos (
gb.qt4 o
gb.gtk) proveen dos clases que deberías usar como "clases padre" para crear tus propio controles:
UserControl y UserContainer son realmente clases hijas de la clase
Container. De esta forma, puedes crear nuevos controles o nuevos contenedores mezclando controles o contenedores ya existentes.
Para un buen ejemplo de uso de UserControl, mira el código fuente del control
FileView.
Este control contiene un
TreeView y un
IconView dentro de un UserControl, mostrando uno de los dos, según el tipo de vista requerido por el usuario.
Para otro ejemplo de uso de UserContainer, mira el código fuente del control
ListContainer.
Este control es un contenedor que permite crear un
ListBox cuyos ítems son otros controles.
Los controles tienen que declarar algunos tipos de constantes ocultas que permiten al IDE gestionar el control:
Constante
|
Tipo
|
Por defecto
|
Descripción
|
_IsControl
|
Boolean
|
FALSE
|
Esta propiedad debe establecerse a TRUE, para que una clase exportada se convierta en un control.
|
_IsContainer
|
Boolean
|
FALSE
|
Si un control es un contenedor, es decir, si puedes poner otros controles dentro usando el editor de formularios del IDE.
|
_IsMultiContainer
|
Boolean
|
FALSE
|
si un control es un contenedor múltiple, como el TabStrip.
|
_IsVirtual
|
Boolean
|
FALSE
|
Si un control es virtual, es decir, una clase normal que puedes poner en el editor de formularios, como el control Timer o la clase Printer.
|
_IsForm
|
Boolean
|
FALSE
|
Si un control es realmente un formulario, por ejemplo el contenedor de nivel superior de todos los controles de la misma familia.
|
_Family
|
String
|
"*"
|
La familia del control, esto es, el tipo de objeto de nivel superior donde se ha de colocar el control.
Por ejemplo: "Form" para un control Form, "Report" para un control Report, and "*" para un control que se puede colocar en cualquier lugar.
|
_Group
|
String
|
_Family
|
El nombre de la pestaña de la caja de herramientas del IDE donde se mostrará el icono del control. Por defecto se usará el nombre de la familia, pero si no se ha establecido se usará el grupo "Special" .
|
_Similar
|
String
|
""
|
Una lista separada por comas de grupos similares. El editor de formularios del IDE permite reemplazar un control por cualquier otro que comparta los mismos grupos de similaridad.
Normalmente un grupo de similaridad es el nombre de un control.
|
_Properties
|
String
|
""
|
La lista de propiedades del control. Ver más abajo.
|
_DefaultEvent
|
String
|
""
|
El evento por defecto. Ver más abajo.
|
_DefaultSize
|
String
|
""
|
El tamaño por defecto del control. Ver más abajo.
|
_DrawWith
|
String
|
""
|
El control gráfico real empleado para dibujar el control dentro del editor de formularios. Ver más abajo.
|
_Arrangement
|
Integer
|
0
|
La disposición automática del control cuando éste es un contenedor y si éste dispone la posición de sus elementos hijos automáticamente.
Ver más abajo.
|
Sólo las constantes
_IsControl
y
_Properties
son obligatorias.
Estas constantes ocultas se heredan como cualquier otra constante. Así que no necesitas declararlas en cada control, ya que hay una relación hereditaria entre ellas.
La constante _Properties
Esta constante es la más importante y además es obligatoria. Describe todas las propiedades que aparecerán en la hoja de propiedades del IDE para ese control,
su tipo, sus valores por defecto y otra información dependiente del tipo de propiedad.
Sintaxis
Esta constante especial es una cadena con la siguiente sintaxis:
PUBLIC CONST _Properties AS String = " [ * , ] Propiedad1 , Propiedad2 , ... "
Cada propiedad tiene la siguiente sintaxis:
[-] Nombre [ { Tipo [ Argumentos ] } ] = Default
-
Nombre es el nombre de la propiedad. Por supuesto, la propiedad debe ser declarada e implementada en el código del control.
-
Tipo es el tipo de propiedad (N. del T.: Tipo como sinónimo de "especie", no como tipo de dato o datatype). Puede ser más exacto que el tipo de dato de la propiedad. Por ejemplo, "Color" significará que la propiedad es un entero, pero la hoja de propiedades del control en el IDE abrirá un selector de colores para definir su valor. Si no se define, el tipo de propiedad es su tipo de dato (datatype).
-
Argumentos son argumentos opcionales que dependen del valor de Tipo.
-
Default es el valor por defecto de la propiedad. La sintaxis aquí depende del tipo de propiedad.
La primera propiedad puede ser un asterisco, de forma que el control adquiere automáticamente todas las propiedades declaradas en la constante
_Properties
de su clase ascendiente.
En ese caso, un nombre de propiedad puede comenzar con un guión medio (-) para que no aparezca en la lista de propiedades heredada de la clase padre.
Tipos de Propiedades
Aquí están los diferentes valores de
Tipo soportados hasta el momento:
Tipo Propiedad
|
Descripción
|
Argumentos
|
Color
|
Un entero que representa un color.
El IDE mostrará un selector de color emergente para editar el valor de esta propiedad.
|
|
Font
|
Una fuente de caracteres.
El IDE mostrará un selector de fuentes emergente para editar el valor de esta propiedad.
|
Font [ :Fixed ]
Usar Font:Fixed para permitir fuentes fijas solamente.
|
Path
|
Una ruta a un fichero.
El IDE mostrará un selector de ficheror emergente para editar el valor de esta propiedad.
|
|
Picture
|
Una imagen localizada en el el directorio del proyecto o un icono de stock.
El IDE mostrará un selector de imágenes para editar el valor de esta propiedad.
|
|
Range
|
Un rango de números enteros con un mínimo y un máximo.
El IDE usará un control SpinBox para editar el valor de esta propiedad.
|
Range:Mínimo;Máximo
|
El valor
Default value debe coincidir con el tipo de dato de la propiedad. Para propiedades booleanas, se puede especificar "True" o "False" como valor por defecto.
Hay que ser muy prudente cuando definamos (o no) el valor
Default de una propiedad.
-
Si no se especifica, el valor por defecto que toma es el valor por defecto asociado con el tipo de dato de la propiedad, (FALSE para una propiedad Boolean, 0 para una numérica, etc.).
-
El valor por defecto debe coincidir con la implementación de la propiedad, porque cuando una propiedad se establece a su valor por defecto en el editor de formularios del IDE, no se genera ningún código para inicializar la propiedad en tiempo de ejecución.
Listas de Constantes
Para propiedades que toman su valor de una lista de constantes predefinidas de la misma clase,
puedes especificar una clase en lugar de un tipo de propiedad, con una lista opcional de constantes.
Esta es la sintaxis:
Tipo de Propiedad
|
Descripción
|
Argumentos
|
Nombre de clase
|
Una lista de constantes.
El IDE usará un control ComboBox para editar el valor de la propiedad, y lo llenará con las constantes especificadas.
|
Class . ( * | Constante1 ; Constante2 ; ... ) [ = Default ]
Si usamos un asterisco en vez de una lista de propiedades, se usarán todas las constantes de la clase especificada.
|
Si se especifica, el valor de Default debe ser el nombre de una de las constantes, no su valor real.If specified, the value of _Default must be the name of one of the constants. Not its real value!
Ejemplos
Por ejemplo, el valor de
Control._Properties
es:
X{Position},Y{Position},Width{Dimension},Height{Dimension},Visible=True,Enabled=True,Font{Font},
Background{Color}=-1,Foreground{Color}=-1,Tag,
Mouse{Mouse.Default;Blank;Arrow;Cross;Wait;Text;SizeAll;SizeH;SizeV;SizeN;SizeS;SizeW;SizeE;SizeNWSE;SizeNESW;SplitH;SplitV;Pointing}=Default,
ToolTip,Drop,Expand,Ignore
Es heredado por todos los otros controles y contenedores.
Este es el valor de
ListBox._Properties
:
*,List,Mode{Select.*}=Single,Sorted
Las otras Constantes Especiales
La constante _DefaultEvent
Esta constante es una cadena que representa el evento por defecto del control. Este evento por defecto es el que se usa cuando de hace doble clic en un
control en el editor de formularios del IDE.
Por ejemplo:
PUBLIC CONST _DefaultEvent AS String = "Click"
Esta constante es opcional, pero es muy conveniente declararla.
La constante _DefaultSize
Esta constante es una cadena que representa el tamaño por defecto del control cuando se suelta encima del editor de formularios al arrastrarlo desde la caja de herramientas de controles.
Es su anchura y su altura como un múltiplo de
Desktop.Scale, separado por comas.
Un ejemplo:
PUBLIC CONST _DefaultSize AS String = "36,36"
Esta constante es opcional. Si no se declara, el IDE tratará de hacer lo mejor posible.
La constante _DrawWith
Esta constante es una cadena que indica al IDE el control que se va a usar para dibujarlo en el editor de formularios.
Por defecto, los controles que son miembros de
gb.qt4,
/edit/comp/gb.qt.ext,
gb.form y
gb.form.mdi se dibujan siendo instanciados con el juego de propiedades Design.
Si un control no es miembro de dichos componentes, entonces el IDE dibujará un marco con el icono del control y su nombre dentro.
Al definir esta constante, el IDE no usará un
DrawingArea, sino el control que se especifique.
Por ejemplo:
PUBLIC CONST _DrawWith AS String = "TextBox"
La constante _Arrangement
Esta constante es un valor de tipo cadena que representa el estilo de disposición que usa el IDE para ordenar los controles hijos dentro de un contenedor, antes de salvarlos en el disco duro.
El valor puede ser una de las siguientes cadenas:
Por ejemplo:
PUBLIC CONST _DefaultArrangement AS Integer = "V" ' Arrange.Vertical
Esa constante se usa solamente si el control es un contenedor y es opcional. Si no se define, no se fuerza su disposición.
Iconos de control
Cada control debe tener un icono para mostrarse en la caja de herramientas del IDE.
Para proporcionar los iconos de los controles de tu componente, debes crear un directorio
/control
en la raíz de tu proyecto,
y colocar un fichero PNG para cada control.
En Gambas 3, el directorio del control
se debe crear dentro del directorio .hidden
. Esa es la sección "Proyecto" en la vista de árbol del IDE.
El nombre del icono de un control debe ser el nombre de clase del control en
minúsculas con la extensión
.png
.
Por ejemplo:
$ cd gb.db.form
$ cd control
$ ls
databrowser.png datacombo.png datacontrol.png datasource.png datatree.png dataview.png
Requerimientos del componente
Se pueden especificar los requerimientos del componente en la pestaña "Requiere" del diálogo de propiedades del proyecto.
Observa que esta pestaña no es visible cuando un proyecto no es un componente.
En esta pestaña se listarán todas las dependencias de tu componente sobre otros componentes.
La sección "Características" tiene cuatro check-boxes, cada una con una característica proporcionada por uno o varios componentes.
Esta sección se usa cuando tu componente necesita una característica específica que no depende de un un componente en especial.
Si realmente se necesita algún componente específico, se pueden seleccionar en la sección "_Componentes_" de esta pestaña.
Los componentes seleccionados en la pestaña "Componentes" del diálogo de propiedades del proyecto, no tienen nada que ver con los componentes especificados en la pestaña "Requiere" de las propiedades del componente.
Éstos sólo se usan para correr el proyecto del componente desde el IDE con fines de depuración.
Depuración, instalación y empaquetado del componente
Depuración
Para depurar tu componente, directamente se puede usar y correr el proyecto tal cual.
La clase de inicio del proyecto y los componentes chequeados en la pestaña "Componentes" del diálogo de propiedades de proyecto no interfiere en absoluto con el comportamiento del componente una vez instalado y en uso por otros proyectos.
Empaquetado
El IDE puede crear paquetes binarios de tu componente, igual que haría para cualquier otro proyecto normal.
Sólo hay que definir menos opciones: un componente no tiene entrada de menú, por ejemplo.
El paquete binario instalará el componente a nivel global y se podrá usar igual que cualquier otro componente proporcionado por Gambas.
Si quieres distribuir tu componente, es muy importante nombrarlo siguiendo un esquema muy preciso, para que no haya conflictos entre paquetes.
El nombre de tu componente tiene que ser:
gambas3-/vendedor/-/nombre/
-
gambas3
es el prefijo para todos los componentes.
-
vendedor
es el nombre de vendedor. Para componentes oficiales de gambas, el nombre de vendedor es simplemente gb
.
-
nombre
es el nombre del componente.
En caso de que el asistente de empaquetado permita insertar la cadena de vendedor en el nombre del paquete, por favor evita hacerlo.
Coloca el nombre de vendedor dentro del nombre de proyecto del componente, de forma que aparezca en el nombre del componente final y sea visible para el usuario.
Por el momento, hay un fallo en el empaquetador que no tiene en cuenta la versión del proyecto del componente al generar las dependencias del paquete.
En consecuencia, hay que establecer la versión de tu componente a la versión de Gambas actual!
Conclusión
He intentado encontrar la forma más fácil de crear componentes usando el IDE. Aún no es perfecta, pero si tienes alguna pregunta o comentario,
por favor usa la lista de correo.
Ten en cuenta que algunas cosas cambiarán seguramente antes de la versión final de Gambas 3.
Y por supuesto, si quieres corregir o mejorar este artículo, bienvenido seas!