如何用Gambas开发组件

前言

以下所有信息均适用于 Gambas 3。

Gambas组件是用C、C++或者直接用Gambas写成的共享库,用于向Gambas解释器中加入新的类。

一个用Gambas编写的组件是一个具有下列特殊特征的普通Gambas工程:

  1. 在项目属性对话框的“常规”选项卡中,“项目类型”组合框设置为“组件”

  2. 然后会出现一个名为“信息”的新选项卡

    它必须填写以下详细信息:

    • 组件的进度(即是否稳定)。

    • 所需的功能。

    • 所需的组件。

    • 排除的组件

  3. 一些项目的类是 导出 的。

  4. 作为 控件 的导出类必须声明一些特殊的公共常量,这些常量将告诉 IDE 管理控件所需的所有信息。

很多gambas官方组件已经用gambas编写了,你可以使用它们作为示例。这些组件的源代码位于 /comp/src 源存档的目录中。

以下是这些组件的列表:

请注意,一些用 C/C++ 编写的组件也有一部分是用 gambas 编写的:

gambas 部分的源代码位于这些组件的源目录内。例如gb.qt4 的 gambas 部分位于:

/gb.qt4/src.

输出类

一个组件的目标是为Gambas解释器提供新的类。

你希望提供的类必须被从你的工程中 exported ,否则你的组件的用户将会看不到它们。

要标记一个类为 exported ,仅仅添加Gambas关键字EXPORT在类源代码文件的开始。

如果一个输出类的某个方法或者属性返回在你组件中声明的另一个类的一个对象,那么这另一个类也应该作为输出类。否则,用户将不能保存一个对它的引用,除非用户使用Object数据类型。

如果一个输出类继承自你的组件声明的另一个类,那么这另一个类也必须是输出类。 否则,在解释器加载组件时会发生错误。

仅有输出类的一个简单组件的优秀的实例,可以查看的gb.settings源代码和它的Settings类。

隐藏的输出类

如果有一些不想让用户看到的输出类,通过用下划线作为它们名字的首字符就可以来隐藏它们。

示例,可以在gb.desktop源代码中看到很多不会被明白看到的输出类。

这一点,可以取代仅仅存在于C/C++编写的组件中的“虚类”的概念。

控件

控件是会出现在IDE控件工具箱中的特殊的输出类。

控件通常是显示某些东西以及和用户实现交互的图形化控件。 但是也可以是正常的类,没有显示,就像Timer控件。在这种情况下,它们被称为 “虚拟” 控件。

GUI组件(gb.qt4gb.gtk)提供两个类,你应该将其作为你自己创建的控件的父类: UserControl和UserContainer事实上是Container 类的子类。 这样,可以通过混合已经存在的控件或容器来创建新控件或新容器。

UserControl用法的好实例请看FileView控件的源代码。 该控件在一个UserControl里面内嵌了一个TreeView和一个IconView, 根据用户要求的查看种类显示它们中的一个。

UserContainer用法的好实例请看ListContainer控件的源代码, 该控件是一个允许创建一个条目为其他控件的ListBox控件的容器

此外,控件需要声明一些特殊的隐含常数,它们被IDE用于管理控件:

Constant Type Default Description
_IsControl Boolean FALSE This property must be set to TRUE, so that an exported class becomes a control.
_IsContainer Boolean FALSE If a control is a container, i.e. if you can put other controls inside in the IDE form editor.
_IsMultiContainer Boolean FALSE If a control is a multiple container, like a TabStrip.
_IsVirtual Boolean FALSE If a control is virtual, i.e. just a normal class that you can put in the form editor, like the Timer or Printer class.
_IsForm Boolean FALSE If a control is actually a form, i.e. the top-level container of all controls of the same family.
_Family String "*" The family of the control, i.e. the kind of top-level object where you will be able to put the control. For example: "Form" for a form control, "Report" for a control report, and "*" for a control that can be put anywhere.
_Group String _Family The IDE toolbox tab name where the control will be put. By default, the family name will be used, or the "Special" group if the control has no family.
_Similar String "" A comma separated list of similarity groups. The IDE form editor will allow the control to be replaced by any other control sharing the same similarity groups. A similarity group is normally a control name.
_Properties String "" The list of control properties. See below.
_DefaultEvent String "" The control default event. See below.
_DefaultSize String "" The control default size. See below.
_DefaultArrangement String "" The automatic arrangement if the control is a container and if it arranges its children automatically. See below.
_DrawWith String "" The real GUI control used for drawing the control inside the form editor. See below

Only the _IsControl and the _Properties constants are mandatory.

这些隐藏的常量和其他任何常量一样都是继承的。因此,只要它们之间存在一些继承关系,就不必在每个控件中实际声明它们。

_Properties 常数

该常数是最重要的,而且是必须的。描述所有将出现在IDE的控件属性表中的属性的类型、缺省值和其他依赖于属性类型的信息。

语法

该指定常数是一个符合下面格式的字符串:

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

每个属性符合下面的语法:

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

  • Name 是属性的名称。当然,属性必须在控件源代码中被声明和实现。

  • Kind 是属性的种类,是比属性数据类型更精确的描述。例如,"Color"意味着属性是一个整数,但是IDE属性表会打开一个颜色选择器来定义它的值。如果没有定义,属性的种类是它的数据类型。

  • Arguments 是依赖于_Kind_值的可选参数。

  • Default 是属性的缺省值。语法依赖于属性种类。

第一个属性可以是一个星号,意味着控件自动获得它的父类在 Property1 常数中所有的属性声明。 在这种情况下,一个属性名称可以用减号开头,这意味着该属性必须被从其父类继承来的列表中移除。

属性种类

这是目前支持的_Kind_的不同值:

属性种类 说明 参数
Color 描述颜色的一个整数。

IDE将弹出一个颜色选择器来编辑该属性的值。
Font 一个字体。

IDE将弹出一个字体选择器来编辑该属性的值。
Font [ :Fixed ]
用=Font:Fixed=可以仅仅允许固定字体。
Path 一个文件路径。

IDE将弹出一个文件选择器来编辑该属性的值。
Picture 一个位于工程目录的图片,或一个库存的图标。

IDE将弹出一个图片选择器来编辑该属性的值。
Range 一个有最大值和最小值限制的整数值。

IDE将使用一个SpinBox控件来编辑该属性的值。
Range:Minimum;Maximum

Default 值必须符合属性的数据类型。对于布尔属性,能指定"True"或"False"作为缺省值。

在定义(或不定义)一个属性的 Default 值时,必须小心。

  • 首先,如果不指定,缺省值是关联于属性数据类型的缺省值(Boolean属性是FALSE,数值属性是0...)。

  • 其次,缺省值必须是关联于属性实现。

因为当在IDE窗体编辑器中设置一个属性为它的缺省值,在运行时没有代码来初始化该属性。

常数列表

对于使属性值进入相同类的预定义常数列表的属性,可以指定一个类代替一个属性种类作为常数的一个可选列表。

下面是语法:

属性种类 说明 参数
Class name 一个常数的列表。

IDE将使用一个ComboBox控件来编辑
该属性的值, 并用指定的常数填充它。
Class . ( * | Constant1 ; Constant2 ; ... ) [ = Default ]

如果用星号代替常数列表,那么会使用指定类的所有常数。

如果指定, Default 的值必须是常量其中一个的名称,而非真值!

示例

示例, Control._Properties 的值是:
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

它被其他所有的控件和容器继承。

这是 ListBox._Properties 的值:
*,List,Mode{Select.*}=Single,Sorted

其他特殊常数

_DefaultEvent 常数

该常数是一个描述控件缺省事件的字符串。 该缺省事件用于在IDE窗体编辑器中双击控件。

示例:
PUBLIC CONST _DefaultEvent AS String = "Click"

该常数是可选的,但是总是应该声明。

_DefaultSize 常数

该常数是一个字符串,描述控件被从工具箱拖动到窗体编辑器时的缺省尺寸。 它是宽度和高度,是Desktop.Scale的倍数,用逗号分隔。

示例:
PUBLIC CONST _DefaultSize AS String = "36,36"

该常数是可选的。如果没有声明,IDE将尝试使其最佳。

_DrawWith 常数

该常数是一个字符串,用于告诉IDE哪一个控件应该被用来绘制在窗体编辑器上。

作为缺省,作为gb.qt4/wiki/comp/gb.qt.extgb.formgb.form.mdi成员的控件采用将Design属性设置为真来进行示例绘制。

如果控件不是上述组件的成员,那么IDE将绘制一个内有控件图标和控件名称的框架。

通过定义该常数,IDE将不使用DrawingArea,除了你指定的控件。

示例:
PUBLIC CONST _DrawWith AS String = "TextBox"

_Arrangement 常数

该常数是一个整数值,描述IDE在将窗体保存到磁盘之前在容器中排列子控件的强制排列类型。

值是Arrange 类常数的整数值之一。

Constant Arrangement
"H" Arrange.Horizontal
"V" Arrange.Vertical
"R" Arrange.Row
"C" Arrange.Column
"F" Use the actual value of the Arrange property.

示例:
PUBLIC CONST _DefaultArrangement AS Integer = "V" ' Arrange.Vertical

该常数仅仅被用于容器控件,而且是可选的。如果不定义,强制不排列。

控件图标

每个控件必须有一个用于在IDE控件工具箱中显示的图标。

要提供你的组件控件的图标,必须在你的工程的根目录下创建一个 /control 目录,并在里面为每一个控件图标放置一个PNG文件。

In Gambas 3, the control directory must be created inside the .hidden directory. This is the "Project" section in the development environment project treeview.

控件图标的名称必须是*小写*的控件类名称和=.png=扩展名。

示例:

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

关于组件的公用信息

关于组件的更多信息在工程的属性对话框的“提供”和“需要”标签页中。
注意,当工程不是一个组件时这些标签页不可见。

“提供”信息

在这个标签页里,有一个所有输出类的列表。

对每一个类,必须指定:
  • 在“类型”列中,是否为控件,以及什么种类的控件。

  • 在“组”列中,IDE工具箱中控件图标将要被插入的标签页的名字。

这是不同类类型的列表:

类型 说明
Class 一个不是控件的普通类。
Control 一个不是容器的控件。
Virtual 一个“虚拟”控件,也就是说,一个普通的类,但是在窗体编辑器中可以被放置于窗体。 例如,Timer控件。
Container 一个容器控件。这样,IDE窗体编辑器可以把其他控件放置其中。
MultiContainer 一个行为像TabStrip的容器。这意味着它分配它的子控件在不同的子容器中, 在某一时刻仅有这些子控件组中的一组可见。
Form 目前没有使用。在Gambas 3中,它用来说明一个事实上实现一些可用IDE编辑的窗体种类的容器。

“需要”信息

在这个标签页中,列出你的组件所依赖的所有其他组件。

在“特征”部分有4个选择框,每个对应一个由一个或多个组件提供的特征。 当你的组件需要指定的不依赖于特定组件的特征时,使用该部分。

如果确实需要一些特定的组件,可以在标签页的“组件”部分中选择它们。

在属性对话框的“组件”标签页选择的组件与在“需要”标签页中指定的组件毫无关系。

它们仅仅用于为了调试目的而从IDE运行组件工程。

调试、安装和打包组件

调试

为了调试你的组件,你可以直接照原样使用和运行它的工程!

工程的启动类和在工程属性对话框的“组件”标签页中选中的组件,在你的组件安装和被其他工程使用时将根本不会干扰你的组件的行为。

安装

可以通过在“生成可执行文件”对话框中勾选相应的选项,在你的用户主目录安装组件。

一旦安装完成,组件将出现在工程属性对话框的“组件”标签页中,就像其他全局安装的组件一样。

从用户主目录卸载组件,仅仅不勾选“生成可执行文件”对话框中的选项,并重新生成可执行文件。

打包

IDE可以生成你的组件的二进制包,操作和任何其他普通的工程一样。

仅仅需要规定较少的选项:例如,组件没有菜单条目。

二进制包将全局安装组件,并且可以像由Gambas提供的其他官方组件一样使用。

如果想发布你的组件,必须严格按下面的规则命名它,那样组件包才不会发生冲突。

你的组件的名称必须是:=gambas2-/vendor/-/name/=

  • gambas2=是所有Gambas 2组件的前缀。

  • vendor=是供应商名称。对于官方Gmabas组件,供应商名称是简单的=gb=。

  • name=是组件的名称。

即使打包向导程序允许插入包供应商字符串到包名称中,请避免这样做。

将你的供应商名称放置在组件工程名称中,那样它将出现在最终的组件名称里,而且用户就会看到它。

目前,打包程序中有一个缺陷,没有考虑组件工程版本对生成包依赖关系的影响。 所以,你必须设置你的组件工程的版本为当前Gambas的版本!

结束语

我试图找到最简单的方法来用IDE开发组件。它还不够完美,但是如果你对这个问题有什么看法和疑问,请用给我发邮件!

注意,这些内容在Gambas 3中将必然发生改变。

当然,如果想修改或扩充这篇文章,非常欢迎。