Home / dev / gambas 
Previous  Next  Edit  Rename  Undo  Refresh  Search  Administration   
fr  de  es  it  nl  pl  pt  pt_BR  mk  sq  ca  ar  fa  vi  ja  ru  zh  zh_TW  eo 
Documentation
History
 
How To Program Components In Gambas

Introduction

Gambas components are shared libraries written in C, C++ or directly in gambas that add new classes to the gambas interpreter.

A component written in gambas is a normal gambas project with the following distinctive features:

Many gambas official components are already written in gambas, and you can use them as examples. The source code of these components is located in the /comp/src directory of the gambas source archive.

Here is the list of these components:

Note that some components written in C/C++ have a part written in gambas too: The source code of the gambas part is located inside the source directory of these components. For example, the gambas part of gb.qt is located in /gb.qt/src.

Exported classes

So the goal of a component is to provide new classes to the Gambas interpreter.

The classes you want to provide must be exported from your project, otherwise the user of your component won't see them.

To mark a class as exported, you just have to add the gambas keyword EXPORT to the beginning of the class file source code.

If a method or a property of an exported class returns an object of another class declared in your component, then this other class should be exported too. Otherwise, the user won't be able to store a reference on it, unless he uses the Object datatype.

If an exported class inherits another class declared in your component, then this other class must be exported too. Otherwise, you will get an error when the interpreter will load the component.

For a good example of a simple component with only exported classes, look at the source code of gb.settings and its Settings class.

Hidden exported classes

If you have to export some classes that you don't want the user to see them, you can hide them by just starting their name with an underscore character.

For example, look in the gb.desktop source code to see many exported classes that are not to be seen explicitely.

With that, you can replace the concept of "virtual classes" that exist only in components written in C/C++.

Controls

Controls are special exported classes that will appear in the IDE control toolbox.

Controls are usually graphical controls that display something and interact with the user. But they can be normal classes too, and display nothing, like the Timer control. In that case, they are called virtual controls.

The GUI components (gb.qt or gb.gtk) provide two classes that you should use as parent classes for creating your own controls:

UserControl and UserContainer are actually children classes of the Container class. This way, you can create new controls or new containers by mixing already existing controls or containers.

For a good example of the use of UserControl, look at the source code of the FileView control. This control embeds one TreeView and one IconView inside a UserControl, displaying one of them according to the kind of view requested by the user.

For a good example of the use of UserContainer, look at the source code of the ListContainer control. This control is a container that allows to create a ListBox whose items are other controls.

Moreover, controls need to declare some special hidden constants that are used by the IDE to manage the control.

There are five constants that should be declared. The _Properties constant is mandatory, the others are optional:

The _Properties Constant

This constant is the most important, and is mandatory. It describes all properties that will appear in the IDE property sheet for the control, their type, their default value, and other information depending on the property type.

Syntax

This special constant is a string having the following form:

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

Each property has the following syntax:

Syntax
[-] Name [ { Kind [ Arguments ] } ] = Default

The first property can be a star, meaning that the control automatically gets all properties declared in the _Properties constant of its parent class. In that case, a property name can start with a minus sign. It means that this property must be removed from the list inherited from the parent class.

Property kinds

Here are the different values of Kind that are supported at the moment:

Property kind Description Arguments
Color An integer that represents a color.

The IDE will popup a color chooser to edit the value of this property.

Font A font.

The IDE will popup a font chooser to edit the value of this property.

Syntax
Font [ :Fixed ]

Use Font:Fixed to allow fixed fonts only.

Path A file path.

The IDE will popup a file chooser to edit the value of this property.

Picture A picture located in the project directory, or a stock icon.

The IDE will popup a picture chooser to edit the value of this property.

Range An integer value with a minimum and a maximum.

The IDE will use a SpinBox control to edit the value of this property.

Syntax
Range:Minimum;Maximum

The Default value must follow the datatype of the property. For boolean properties, you can specify "True" or "False" as default value.

You must be careful when defining (or not) the Default value of a property.

  • First, if not specified, the taken default value is the default value associated with the property data type (FALSE for a Boolean property, 0 for a numerical one...).

  • Last, the default value must be accurate with the property implementation. Because when a property is set to its default value in the IDE form editor, no code is emitted to initialize the property at run time.

Constant lists

For properties that take their value into a list of predefined constants of the same class, you can specify a class instead of a property kind, with an optional list of constants.

Here is the syntax:

Property kind Description Arguments
Class name A list of constants.

The IDE will will use a ComboBox control to edit the value of the property, and will fill it with the specified constants.

Syntax
Class . ( * | Constant1 ; Constant2 ; ... ) [ = Default ]

If a star is used instead of a constant list, then all constants of the specified class will be used.

If specified, the value of Default must be the name of one of the constants. Not its real value!

Examples

For example, the value of Control._Properties is:

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

It is inherited by all other controls and containers.

Here is the value of ListBox._Properties:

*,List,Mode{Select.*}=Single,Sorted

The Other Special Constants

The _DefaultEvent constant

This constant is a string that represents the default event of the control. This default event is used when you click twice on a control in the IDE form editor.

For example:

PUBLIC CONST _DefaultEvent AS String = "Click"

This constant is optional, but you should declare it anyway.

The _DefaultSize constant

This constant is a string that represents the default size of the control when it is dropped from the toolbox on the form editor. It is the width and height as multiple of Desktop.Scale, separated by commas.

For example:

PUBLIC CONST _DefaultSize AS String = "36,36"

This constant is optional. If not declared, the IDE will try to do its best.

The _DrawWith constant

This constant is a string that tells the IDE which control should be used for drawing it on the form editor.

By default, controls that are member of gb.qt, gb.qt.ext, gb.form and gb.form.mdi are drawn by being instanciated with the Design property set.

If a control is not a member of the components above, then the IDE will draw a frame with the control icon and the control name inside.

By defining this constant, the IDE will not use a DrawingArea, but the control you specified.

For example:

PUBLIC CONST _DrawWith AS String = "TextBox"

The _Arrangement constant

This constant is an integer value that represents the arrangement style forced by the IDE to order children controls inside a container before saving them to disk.

The value is one of the integer value of the Arrange class constants.

For example:

PUBLIC CONST _Arrangement AS Integer = 2 ' Arrange.Vertical

You cannot use directly the Arrange constants in the declaration because you are in a constant declaration. This is a limitation of the Gambas language.

That constant is only used if the control is a container, and is optional. If not defined, no arrangement is forced.

Control Icons

Each control must have an icon that will be displayed in the IDE control tool box.

To provide the icons of your component controls, you must create a /control directory at the root of your project, and put one PNG file for each control icon in it.

The name of a control icon must be the class name of the control in lower case with the .png extension.

For example:

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

Global information about the component

More information about the component is given in the project property dialog, in the "Provides" and "Requires" tabs. Note that these tabs are not visible when a project is not a component.

The "Provides" information

In this tab, you have a list of all exported classes.

For each class, you must specify:

Here is the list of the different class types:

Type Description
Class A normal class that is not a control.
Control A control that is not a container.
Virtual A "virtual" control, i.e. a normal class but that can be put on a form in the form editor. For example, the Timer control.
Container A control that is a container. This way, the IDE form editor knows that it can put other controls inside.
MultiContainer A container that acts like a TabStrip. It means that it divides its children between different sub-containers, and that only one group of children is visible at the same time.
Form Not used at the moment. In Gambas 3, it will indicate a container that actually implements some sort of form that can be edited by the IDE.

The "Requires" information

In this tab, you will list all the dependencies of your component on other components.

The "Features" section has four check-boxes, each one being a feature provided by one or many components. You use this section when your component needs a specific feature, that does not rely on a specific component.

If you really need some specific components, you can select them in the "Components" section of the tab.

The components that you select in the "Components" tab of the property dialog have nothing to do with the components you specify in the "Requires" tab.

They are only used when you run the component project from the IDE for debugging purpose.

Debugging, installing and packaging the component

Debugging

To debug your component, you can directly use and run its project as is!

The startup class of the project, and the components checked in the "Components" tab of the project property dialog will not interfer at all with the behaviour of the component when it will be installed and used by other projects.

Installing

You can install the component in your home directory by checking the corresponding option in the "Make executable" dialog.

Once installed there, the component will be visible in the "Components" tab of the project property dialog as any other globally installed components.

To uninstall the component from your home directory, just uncheck the option in the "Make executable" dialog, and make the executable again.

Packaging

The IDE can make binary packages of your component, as it does for any other normal projects.

You just will have to define less options: a component has no menu entry, for example.

The binary package will install the component globally, and will be usable as any other official component provided by Gambas.

If you want to distribute your component, you will have to name it by following a precise scheme, so that components packages do not conflict.

The name of your component will have to be: gambas2-vendor-name

Even if the packager wizard allows to insert the package vendor string into the package name, please avoid it.

Put your vendor name inside the component project name, so that it appears in the final component name, and the user sees it.

At the moment, there is a flaw in the packager that does not take into account the component project version to generate the package dependencies. Consequently, you have to set the version of your component project to the current Gambas version!

Conclusion

I try to find the easiest way of making components with the IDE. It is not perfect yet, but if you have any comment or question about that, please use the mailing-list!

Note that things will change for sure in Gambas 3.

And, of course, if you want to fix or enhance that article, you are welcome.