Comment programmer des composants en Gambas

Introduction

Toutes les informations suivantes concernent Gambas 3.

Les composants Gambas sont des bibliothèques partagées, écrites en C, C++ ou directement en gambas, qui ajoutent de nouvelles classes à l'interpréteur gambas.

Un composant écrit en gambas est un projet gambas normal ayant les caractéristiques distinctives suivantes :

  1. Dans l'onglet "Général" du dialogue des propriétés du projet, le combo-box "type de projet" est mis sur "Composant".

  2. Puis un nouvel onglet nommé "Information" est disponible.

    Il doit être rempli avec les points suivants :
    • L'évolution du composant (càd s'il est stable ou non).

    • Les fonctionnalités requises.

    • Les composants requis.

    • Les composants exclus.

  3. Certaines des classes du projet sont exportées.

  4. Les classes exportées qui sont des contrôles doivent déclarer certaines constantes publiques spéciales fournissant à l'IDE toute l'information nécessaire pour gérer le contrôle.

De nombreux composants officiels sont déjà écrits en gambas, et vous pouvez les utiliser comme exemples. Le code source de ces composants se trouve dans le répertoire /comp/src de l'archive des sources de gambas.

Voici la liste de ces composants : Notez que certains composants écrits en C/C++ possèdent également une partie écrite en gambas : Le code source de la partie gambas se trouve à l'intérieur du répertoire des sources de ces composants. Par exemple, la partie gambas de gb.qt4 est située dans /gb.qt4/src.

Classes exportées

Ainsi donc, le but d'un composant est de mettre de nouvelles classes à la disposition de l'interpréteur Gambas.

Les classes que vous voulez mettre à disposition doivent être exportées depuis votre projet, sinon l'utilisateur de votre composant ne les verra pas.

Pour marquer une classe comme exportée, il vous suffit d'ajouter le mot-clé gambas EXPORT au début du code source de la classe.

Si une méthode ou une propriété d'une classe exportée renvoie un objet d'une autre classe déclarée dans votre composant, alors cette autre classe doit être également exportée. Sinon, l'utilisateur ne sera pas capable d'en enregistrer une référence, à moins d'utiliser un type de donnée Object.

Si une classe exportée hérite d'une autre classe déclarée dans votre composant, alors cette autre classe doit être également exportée. Sinon, vous obtiendrez une erreur au moment où l'interpréteur chargera le composant.

Pour un bon exemple de composant simple comportant uniquement des classes exportées, examinez le code source de gb.settings et sa classe Settings.

Classes exportées cachées

Si vous devez exporter certaines classes que vous ne voulez pas rendre visibles à l'utilisateur, vous pouvez les cacher en plaçant simplement un caractère de soulignement au début de leur nom.

Par exemple, regardez dans le code source de gb.desktop; vous y verrez de nombreuses classes exportées qui sont explicitement rendues invisibles.

Cette méthode vous permet de remplacer le concept de "classes virtuelles" qui existe uniquement dans les composants écrits en C/C++.

Contrôles

Les contrôles sont des classes exportées spéciales qui vont apparaître dans la boîte à outils des contrôles dans l'IDE.

Les contrôles sont habituellement des contrôles graphiques qui affichent quelque-chose et interagissent avec l'utilisateur. Mais il peut s'agir aussi de classes normales, qui n'affichent rien, comme le contrôle Timer. Dans ce cas, ils sont appelés contrôles virtuel.

Les composants de l'Interface Utilisateur Graphique (gb.qt4 ou gb.gtk) fournissent deux classes que vous devriez utiliser comme classes parentes pour créer vos propres contrôles : UserControl et UserContainer sont en réalité des classes, dérivées de la classe Container. De cette facon, vous pouvez créer de nouveaux contrôles ou de nouveaux conteneurs en combinant des contrôles ou conteneurs préexistants.

Un bon exemple de l'utilisation de UserControl est fourni par le code source du contrôle FileView. Ce contrôle intègre un TreeView et un IconView au sein d'un UserControl, affichant l'un ou l'autre en fonction du type de vue demandée par l'utilisateur.

Vous trouverez un bon exemple de l'utilisation de UserContainer dans le code source du contrôle ListContainer. Ce contrôle est un conteneur permettant de créer une ListBox dont les éléments sont d'autres contrôles.

Les contrôles doivent déclarer certaines constantes cachées spéciales utilisées par l'IDE pour gérer le contrôle.

Constante Type Par défaut Description
_IsControl Booléen FALSE Pour qu’une classe exportée devienne un contrôle, cette propriété doit être positionnée à TRUE,
_IsContainer Booléen FALSE Si un contrôle est un conteneur, c.a.d. si vous placez, dans l’éditeur de formulaire de l’IDE, d’autres contrôles à l’intérieur.
_IsMultiContainer Booléen FALSE Si un contrôle est un conteneur multiple, comme un TabStrip.
_IsVirtual Booléen FALSE Si un contrôle est virtuel, c.a.d juste une classe normale que vous pouvez placer dans l’éditeur de formulaire, comme le Timer ou la classe Printer.
_IsForm Booléen FALSE Si un contrôle est en fait un formulaire, c.a.d. le conteneur de niveau supérieur de tous les contrôles de la même famille.
_Family Chaîne "*" La famille du contrôle, c.a.d. le type d’objet au premier plan où vous pourrez placer le contrôle. Par exemple : "Form" pour un contrôle formulaire, "Report" pour un contrôle rapport, et "*" pour un contrôle qui peut être mis n’importe où.
_Group Chaîne _Family Le nom de l’onglet de la boîte à outils de l’IDE où le contrôle sera placé. Par défaut, le nom de famille sera utilisé, ou le groupe "Spécial" si le contrôle n’appartient à aucune famille.
_Similar Chaîne "" Une liste de groupes de similarités, séparés par des virgules. L’éditeur de formulaire de l’IDE autorisera le remplacement du contrôle par tout contrôle du même groupe de similarité. Un groupe de similarité est normalement un nom de contrôle.
_Properties Chaîne "" La liste des propriétés du contrôle. Voir ci dessous.
_DefaultEvent Chaîne "" L’évènement par défaut du contrôle. Voir ci dessous.
_DefaultSize Chaîne "" La taille par défaut du contrôle. Voir ci dessous.
_DefaultArrangement Chaîne "" La disposition automatique si le contrôle est un conteneur et s’il dispose ses fils automatiquement. Voir ci-dessous.
_DrawWith Chaîne "" Le contrôle GUI réel utilisé pour dessiner le contrôle dans l’éditeur de formulaire. Voir ci-dessous.

Seules les constantes _IsControl et _Properties sont obligatoires.

Comme toute constante, ces constantes cachées sont héritées. Vous n’avez donc pas réellement besoin de les déclarer dans chaque contrôle, dès lors qu’elles ont une relation d’héritage entre elles.

La Constante _Properties

Cette constante est la plus importante, et elle est obligatoire. Elle décrit toutes les propriétés qui apparaîtront pour le contrôle dans la feuille de propriété de l'IDE, leur type, leur valeur par défaut et d'autres informations dépendantes du type de propriété.

Syntaxe

Cette constante spéciale est une chaîne de la forme suivante :

PUBLIC CONST _Properties AS String = " [ * , ] Property1 , Property2 , ... "

Chaque propriété obéit à la syntaxe suivante :

[-] Nom [ { Type [ Arguments ] } ] = Défaut

  • Nom est le nom de la propriété. Bien sûr, la propriété doit être déclarée et implémentée dans le code source du contrôle.

  • Type est le type de la propriété. Il peut être plus précis que le type de donnée de la propriété. Par exemple, "Color" signifiera que la propriété est un entier, mais la feuille de propriétés de l'IDE ouvrira un sélecteur de couleur pour définir sa valeur. S'il n'est pas défini, le type de la propriété est son type de donnée.

  • Arguments sont des arguments optionnels qui dépendent de la valeur de Type.

  • Défaut est la valeur par défaut de la propriété. Ici, la syntaxe dépend du type de la propriété.

La première propriété peut être une étoile, ce qui veut dire que le contrôle reçoit automatiquement toutes les propriétés déclarées dans la constante _Properties de sa classe parente. Dans ce cas, un nom de propriété peut débuter par le signe "moins", signifiant ainsi que cette propriété doit être enlevée de la liste héritée de la classe parente.

Types de propriétés

Voici les différentes valeurs admises actuellement pour Type :

Propriété ; Type Description Arguments
Color Un entier représentant une couleur.

L'IDE affichera un sélecteur de couleur pour éditer la valeur de cette propriété.
Font Une police de caractères.

L'IDE affichera un sélecteur de police pour éditer la valeur de cette propriété.
Font [ :Fixed ]
Utilisez Font:Fixed pour n'autoriser que les polices à chasse fixe.
Path Le chemin d'un fichier.

L'IDE affichera un sélecteur de fichier pour éditer la valeur de cette propriété.
Picture Une image située dans le répertoire du projet, ou une icône prédéfinie.

L'IDE affichera un sélecteur d'image pour éditer la valeur de cette propriété.
Range Une valeur entière avec un minimum et un maximum.

L'IDE utilisera un contrôle SpinBox pour éditer la valeur de cette propriété.
Range:Minimum;Maximum

La valeur par Défaut doit obéir au type de donnée de la propriété. Pour les propriétés booléennes, vous pouvez spécifier "True" ou "False", par défaut.

Vous devez être prudent lorsque vous définissez (ou non) la valeur par Défaut d'une propriété.

  • D'abord, si elle n'est pas spécifiée, la valeur par défaut prise en compte est la valeur par défaut associée au type de donnée de la propriété (FALSE pour une propriété Boolean, 0 pour une propriété numérique...).

  • Enfin, la valeur par défaut doit correspondre précisément à l'implémentation de la propriété. En effet, lorsqu'une propriété est mise à sa valeur par défaut dans l'éditeur de formulaire de l'IDE, aucun code n'est produit pour initialiser la propriété au moment de l'exécution.

Listes de constantes

Pour les propriétés qui prennent leur valeur dans une liste de constantes de la même classe, vous pouvez spécifier une classe au lieu d'un type de propriété, avec une liste facultative de constantes.

Voici la syntaxe :

Propriété ; Type Description Arguments
Class name Une liste de constantes.

L'IDE utilisera un contrôle ComboBox pour éditer la valeur de la propriété, et la remplira avec les constantes indiquées.
Classe . ( * | Constante1 ; Constante2 ; ... ) [ = Défaut ]

Si une étoile est utilisée au lieu d'une liste de constantes, alors toutes les constantes de la classe spécifiée seront utilisées.

Si elle est spécifiée, la valeur par Défaut doit être le nom d'une des constantes, et non sa valeur réelle !

Exemples

Par exemple, la valeur de Control._Properties est :
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

Elle est héritée par tous les autres contrôles et conteneurs.

Voici la valeur de ListBox._Properties :
*,List,Mode{Select.*}=Single,Sorted

Les autres constantes spéciales

La constante _DefaultEvent

Cette constante est une chaîne représentant l'évènement par défaut du contrôle. Cet événement par défaut est utilisé lorsque vous double-cliquez sur un contrôle dans l'éditeur de formulaire de l'IDE.

Par exemple:
PUBLIC CONST _DefaultEvent AS String = "Click"

Cette constante est facultative mais vous devriez la déclarer d'office.

La constante _DefaultSize

Cette constante est une chaîne représentant la taille par défaut du contrôle lorsqu'il est déposé depuis la boîte à outils sur l'éditeur de formulaire. Il s'agit de la largeur et de la hauteur exprimées comme multiples de Desktop.Scale, séparées par une virgule.

Par exemple:
PUBLIC CONST _DefaultSize AS String = "36,36"

Cette constante est facultative. Si elle n'est pas déclarée, l'IDE tâchera de faire de son mieux.

La constante _DrawWith

Cette constante est une chaîne indiquant à l'IDE quel contrôle utiliser pour le dessiner sur l'éditeur de formulaire.

Par défaut, les contrôle qui sont membres de gb.qt4, /wiki/comp/gb.qt.ext, gb.form et gb.form.mdi sont tracés en étant instanciés avec la propriété Design activée.

Si un contrôle n'est pas un membre des composants ci-dessus, alors l'IDE dessinera un cadre contenant l'icône du contrôle ainsi que son nom.

En définissant cette constante, l'IDE n'utilisera pas un DrawingArea, mais bien le contrôle que vous aurez indiqué.

Par exemple:
PUBLIC CONST _DrawWith AS String = "TextBox"

La constante _DefaultArrangement

Cette constante est une valeur chaîne représentant le style d'arrangement que l'IDE imposera pour ordonner les contrôles enfants à l'intérieur d'un conteneur avant de les sauvegarder sur disque.

La valeur peut être une des chaînes suivantes :

Constant Arrangement
"H" Arrange.Horizontal
"V" Arrange.Vertical
"R" Arrange.Row
"C" Arrange.Column
"F" Utilise la valeur véritable de la propriété Arrange.

Par exemple :
PUBLIC CONST _DefaultArrangement AS Integer = "V" ' Arrange.Vertical

Cette constante est optionnelle et utilisée uniquement lorsque le contrôle est un conteneur. Si elle n'est pas définie, aucun arrangement n'est imposé.

Icônes des contrôles

Chaque contrôle doit posséder une icône qui sera affichée dans la boîte à outils des contrôles de l'IDE.

Pour mettre à disposition les icônes de vos composants contrôles, vous devez créer un répertoire /control à la racine de votre projet et y placer un fichier PNG pour chaque contrôle.

En Gambas 3, le répertoire contrôle doit être créé dans le répertoire .hidden (caché). C’est la section "Project" dans l’arborescence d’environnement de développement du projet.

Le nom d'une icône de contrôle doit être le nom de la classe du contrôle en minuscules avec l'extension .png.

Par exemple :

$ cd gb.db.form
$ cd control
$ ls
databrowser.png  datacombo.png  datacontrol.png  datasource.png  datatree.png  dataview.png

Exigences des Composants

Vous pouvez spécifier les exigences du composant dans l’onglet "Information" du dialogue de propriétés du composant de l’IDE.

Dans cet onglet, vous inscrirez toutes les dépendances de votre composant à d'autres composants.

La section "Fonctionnalités" possède cinq cases à cocher, chacune d'elles correspondant à une fonctionnalité fournie par un ou plusieurs composants. Utilisez cette section lorsque votre composant a besoin d'une fonctionnalité spécifique qui ne repose pas sur un composant particulier.

Si vous avez vraiment besoin de certains composants spécifiques, vous pouvez les sélectionner dans la section "Composants requis et exclus" de l'onglet.

Les composants que vous sélectionnez dans l'onglet "Composants" du dialogue de propriétés n'ont rien à voir avec les composants que vous indiquez dans la section "Composants requis et exclus".

Ils sont seulement utilisés lorsque vous exécutez le projet du composant depuis l'IDE à des fins de débogage.

Débogage, installation et empaquetage du composant

Débogage

Pour débugger votre composant, vous pouvez simplement utiliser et exécuter son projet tel quel !

La classe de démarrage du projet, ainsi que les composants cochés dans l'onglet "Composants" du dialogue de propriété du projet ne perturberont en aucune manière le comportement du composant lorsqu'il sera installé et utilisé par d'autres projets.

Empaquetage

L'IDE peut construire des paquets binaires de votre composant, tout comme il le fait avec n'importe quel autre projet normal.

Simplement, il y aura moins d'options à définir : un composant n'a pas d'entrée de menu, par exemple.

Le paquet binaire installera le composant de manière globale et celui-ci sera utilisable au même titre que n'importe quel autre composant officiel mis à disposition par Gambas.

Si vous voulez distribuer votre composant, vous devrez le nommer selon un schéma précis pour éviter que les paquets de composants n'entrent en conflit.

Le nom de votre composant sera gambas3-//, ainsi le nom de votre projet ne doit pas inclure le nom du fournisseur et le prefixe gambas3.

par exemple, pour créer le paquet pour le composant gambas3-maboite-truc, votre projet doit être nommé truc, et "maboite" doit être spécifié comme nom du fournisseur dans le packager wizard.

Pour l'instant, une faille de l'empaqueteur empêche de prendre en compte la version de projet du composant pour générer les dépendances du paquet. Par conséquent, vous devrez mettre vous-même la version de projet de votre composant à la version courante de Gambas !

Conclusion

J'essaie de trouver le moyen le plus facile pour fabriquer des composants avec l'IDE. Ce n'est pas encore parfait mais si vous avez un commentaire, une question ou un problème, veuillez utiliser la mailing-list!