- designerUserGuid

本文档由未注册的 Word-2-CHM 软件自动从 Word 文件生成。
有关注册信息请浏览 Macrobject Software 主页：http://www.macrobject.cn


摘要 - designerUserGuid

摘要

本文的目的是说明如何使用TSL桌面开发工具开发桌面程序,阅读完本文后您可以使用TSL语言开发桌面应用程序.本文将讨论如下内容:

l 使用界面开发工具构建桌面工程

l TSL桌面开发库的基本架构

l 常用的控件简介


1. 使用桌面开发工具 - designerUserGuid

1. 使用桌面开发工具


1.1 安装 - designerUserGuid

1.1 安装

TSL桌面开发工具采用免安装方式,下载程序包,执行程序入口即可.


1.2 开发工具操作界面介绍 - designerUserGuid

1.2 开发工具操作界面介绍

运行开发工具,可以看到如下图所示.操作界面分为6个主要部分,下面将对各个部分进行介绍.

图1. 界面设计器

tsl桌面设计器如(图1)所示,可以大致分为6个部分

1. 菜单栏

2. 控件工具栏

3. 工程浏览器

4. 正在被编辑的窗口

5. 当前窗口控件树

6. 当前选中节点属性\事件编辑器


1.2.1 菜单 - designerUserGuid

1.2.1 菜单

表1. 菜单项说明

菜单项 | 菜单子项 | 说明
文件 | 保存 | 保存正在编辑的文件
 | 代码编辑 | 打开tsl代码编辑器
视图 | 管理工程文件 | 打开文件管理窗口可以添加或者删除文件/目录
 | 对象浏览 | 显示对象查看器。
工程 | 新建工程/打开工程 | 对工程执行相应的操作。
 | 打开历史 | 显示设计器打开工程的历史。
运行 | 运行/停止 | 运行当前工程以测试以及停止运行。
工具 | 打开图片 | 可以打开图片并将其转换为16进制字符串形式。
帮助 | 使用手册/详细接口/范例 | tsl桌面开发的各种帮助


1.3 构建一个TSL桌面程序 - designerUserGuid

1.3 构建一个TSL桌面程序

开发tsl桌面程序,包括的步骤如下

l 新建工程

l 新建窗口(新建窗口会默认构建一个主窗口)

l 给窗口添加控件

l 根据需求给窗口添加控件(菜单)

l 编写各个控件的消息处理函数


1.3.1 新建工程 - designerUserGuid

1.3.1 新建工程

Ø 第一步 菜单栏—工程—新建工程

Ø 第二步 在打开的文件选择对话框中,给工程新建一个文件夹(范例为newprojecta),并选中该文件夹

Ø 第三步 输入工程名(和tsl变量命名规则一样,范例中取名为newprojecta), 点击打开.

此时会在工程目录中出现三个文件以及一个资源文件目录

resource.tfm 目录为该工程的窗体资源文件夹

newprojecta.tpj文件为工程信息文件(打开工程时选择该文件)

newprojecta.tsl 文件为工程执行入口文件

newprojectamain.tsf 文件为工程主窗口文件(默认添加窗口)

图2.  工程目录

对于一个程序,往往会包含多个窗口,或者一下执行函数,可以通过工程文件管理器在工程中添加,窗体文件,tsl文件,tsf文件

图3. 工程文件管理器


1.3.2 给窗口添加/删除控件 - designerUserGuid

1.3.2 给窗口添加/删除控件

点选工具栏中的按钮,选择需要添加的控件,然后点击窗口,就会在窗口点击位置放置相应的控件,之后就可以用鼠标拖拽改变其位置和大小.

如果要删除控件,可以右键待删除控件(或者控件树节点),选择相应的右键菜单:

图4. 删除控件


1.3.3 操作控件 - designerUserGuid

1.3.3 操作控件

可以通过对象浏览器设置控件的属性.对于控件有很多共有属性如下:

name 名字属性,在窗口中唯一,作为成员变量,引用控件,可以在代码编辑器中使用

left 控件在父窗口中的水平位置

top 控件在父窗口中的垂直位置

width 控件的宽度

height 控件的高度

visible 可见

enabled 是否响应鼠标消息

图5. 修改控件属性

图6. 控件浏览器

右键控件\对象浏览器(树节点)可以删除控件.也可以修改控件在父节点中的次序

图7. 删除控件


1.3.4 编辑窗口代码 - designerUserGuid

1.3.4 编辑窗口代码

双击控件,便会打开窗口对应的TSL代码,可以在窗口类中看到添加的成员变量.可以根据业务需求添加成员变量到代码窗口类中,但是请不要改变控件成员的public属性

图8. 编辑窗口代码


1.3.5 添加消息响处理 - designerUserGuid

1.3.5 添加消息响处理

双击控件打开代码编辑器.如下图所示,如果控件存在默认的消息处理函数.就会自动在代码中添加处理函数.如按钮,双击打开编辑器的同时会添加一个默认的处理函数。在代码编辑器中,也可以自己添加函数,然后在控件events属性中选择其作为事件回调。

图9. 给按钮添加事件响应


1.3.6 给主窗口添加主菜单 - designerUserGuid

1.3.6 给主窗口添加主菜单

菜单在一个应用程序中占用重要地位,能提升使用者的体验,添加主菜单需要以下几个几步:

1. 窗体中添加主菜单控件

2. 给菜单控件添加菜单项

3. 设置各个菜单项的caption,以及设置onclick消息处理函数

4. 将菜单设置到窗口的mainmenu属性

在工具栏点选mainmenu控件添加到窗体,然后右键刚刚添加的mainmenu控件给菜单添加子菜单项.

图10. 添加菜单控件以及菜单项

将菜单mianmenu1 设置到主窗口的mainmenu属性

图11. 设置主菜单


1.3.7 窗口添加右键菜单 - designerUserGuid

1.3.7 窗口添加右键菜单

右键菜单可以添加给任意控件,只要控件有popupmenu属性,添加右键菜单的步骤:

1. 窗体中添加菜单控件

2. 给菜单控件添加菜单项

3. 设置各个菜单项的caption,以及设置onclick消息处理函数

4. 将菜单设置到窗口的popupmenu属性

在工具栏选择popupmenu控件添加到窗体,然后右键控件给菜单添加子菜单项.

图12. 添加弹出菜单

将菜单popupmenu1 设置到主窗口的popupmenu属性

图13. 设置弹出菜单


1.3.8 执行 - designerUserGuid

1.3.8 执行

菜单—运行--运行

图14. 运行效果


1.3.9 移植 - designerUserGuid

1.3.9 移植

移植需要将工程目录放入tsl解析器能够查找到的目录如funcext 或者 -libpath 所指定的目录,如果只移植部分窗口,只需要将工程中,对应的窗口tsf文件以及resource.tfm 文件夹拷贝到tsl解析器能够查找的目录及可.


2. 界面库简介 - designerUserGuid

2. 界面库简介


2.1 库文件 - designerUserGuid

2.1 库文件

库 | 说明
tslvcl | 界面库及其常用组件


2.2 类层次结构 - designerUserGuid

2.2 类层次结构

TSL界面开发常用类及其的继承关系

图15. tslvcl库主要类层次结构（在继承链省略了一些不重要的类）


2.2.1 公共基类TSLUIBASE和组件基类TComponent - designerUserGuid

2.2.1 公共基类TSLUIBASE和组件基类TComponent

TSLUIBASE是界面库组件的公共基类，定义了一些常用的成员函数以及各种常量。

TComponent是组件基类，定义了组件的基本操作；记录了组件间的拥有和被拥有的关系，定义了当组件创建、析构时将会执行的操作。

TComponent的派生类分为两类，其中一类是TControl，这个是可视控件基类，所有的可视控件都是继承自该类；另一类是不可视控件，Tcontrol以外的所有类都属于这一类别，其中的所有控件在最终完成的界面程序上是看不到的。


2.2.2 可视控件基类TControl - designerUserGuid

2.2.2 可视控件基类TControl

TControl是可视控件基类，该类定义了控件的可视属性，如位置、大小等，并且还定义了如菜单、鼠标操作等控件的通用行为。

表2. TControl类常用属性

属性 | 类型 | 说明
left | int | 控件的左侧位置，以像素为单位，从其parent的窗口区域左边开始。
top | int | 控件的顶部位置，以像素为单位，从其parent的窗口区域顶部开始。
width | int | 控件的宽度，以像素为单位。
height | int | 控件的高度，以像素为单位。
caption | string | 控件的标题。
visible | bool | 是否隐藏控件，默认为1（显示）。
border | bool | 使用隐藏边框，默认为1（显示）。
parent | twincontrol | 父窗口，设置某个控件的父窗口后，该控件将会显示在其父窗口上。
popupmenu | tpopupmenu | 弹出菜单，当鼠标在控件中单击右键时，将会显示该菜单。

除了可以设置对象的属性外，控件还定义了一系列可以设置回调函数的属性，这些属性都是函数指针类型，将指定的函数的函数指针赋值给它后，当控件发生相应的操作后，就会调用该函数。有两种方法设置回调函数：

1. 匿名函数：

可以直接定义一个匿名函数赋值给相应属性。

2. 绑定非匿名函数的函数指针

该方法需要定义一个对象可以访问到的函数，然后可以通过thisfunction或findfunction关键字绑定其函数指针。

注意函数的参数需要同属性提供的一致。调用函数时，编译器会将函数调用端提供的参数按照顺序传递到函数的参数列表中。

下表是TControl类提供的可绑定回调函数的属性，tslvcl库中这样的属性大多都是提供两个参数。一般来说，其中一个是控件自身对象，另一个是包含发生的操作的信息的对象。

表3. TControl类常用回调函数属性

函数名 | 参数o | 参数e | 说明
onsize | tcontrol自身 | tmmouse | 鼠标调整控件大小时回调。
onmove | tcontrol自身 | tmmouse | 鼠标拖动控件移动时回调。
onmousemove | tcontrol自身 | tmmouse | 鼠标在控件中移动时回调。
onmouseup | tcontrol自身 | tmmouse | 鼠标按键按下时回调。
onmousedown | tcontrol自身 | tmmouse | 鼠标按键松开时回调。

TControl类的回调函数属性大多是鼠标操作事件引发的，他们的第二个参数类型是tmmouse，这个类包含了该事件的信息，该类拥有属性xpos和ypos，分别是该操作发生时鼠标指针的x位置和y位置；类中有函数shiftstate()，其返回值是整数数组类型，该数组中的数字对应着操作发生时按下的键。其中常见常量如下表所示：

表4. 鼠标操作常用常量

常量名 | 说明
ssShift | shift键被按下
ssCtrl | ctrl键被按下
ssLeft | 鼠标左键被按下
ssRight | 鼠标右键被按下
ssMiddle | 鼠标滑轮被按下
ssDouble | 鼠标双击


2.2.3 窗口控件基类TWinControl - designerUserGuid

2.2.3 窗口控件基类TWinControl

TWinControl是窗口控件的基类，从图1中可以看出，除了TLabel等少数控件外，其他控件都是由TWinControl派生来的。该类有一些较为常用的属性：

l onKeyDown属性，函数指针类型，当用户按下一个按键时将会调用。

l onKeyUp属性，函数指针类型，当用户松开一个按键时将会调用。

l onKeyPress属性，函数指针类型，当用户输入一个字符时将会调用。

以上的函数调用都是按键引发的。这些函数的第二个参数是TMKEY类型，该参数中包含按下的按键的信息。注意只有可以拥有键盘输入焦点的窗口控件，例如能够输入字符的可编辑文本框或者容器和表格控件等等才能使用这些函数指针成员。


2.2.3.1.1 按键操作TMKEY - designerUserGuid

2.2.3.1.1 按键操作TMKEY

每一个TMKEY对象都表示一次按键操作，该对象中包含按下的按键的信息。TMKEY类拥有以下属性：

l char属性，字符类型，操作中按下的字符。

l charCode属性，整数类型，操作中按下的字符的ascii码。

注意keydown和keyup不同于keypress，前者只是按下的按键，后者才是输入的字符。例如当键盘的大小写锁未开启时，按一下“A”键将调用onkeyDown一次，其中char为“A”；调用onKeyPress一次，其中char为“a”；调用onKeyUp一次，其中char为“A”。当大小写锁开启时，这三次调用的char就都是“A”了。


3. 常用控件介绍 - designerUserGuid

3. 常用控件介绍


3.1 按钮控件 - designerUserGuid

3.1 按钮控件

按钮控件一组控件，如下所示：

表5. 各类型按钮

类 | 形态 | 说明
TBtn |  | 普通按钮
TCheckBtn |  | 复选按钮
TRadioBtn |  | 单选按钮

按钮的主要作用就是在用户按下的时候执行某种操作前面提过TControl拥有一些关于鼠标的操作的回调函数属性，而TBtn是它的间接派生类，这就意味着TBtn可以使用这些属性，也就是说设置后鼠标指针在按钮上执行点击等操作时，就会调用相应的函数。按钮类控件常用的属性有以下几种：

l onclick属性，函数指针类型，在鼠标单击左键时调用。

l onrclick属性，函数指针类型，在鼠标单击右键时调用。

l ondblclick属性，函数指针类型，在鼠标双击左键时调用。


3.1.1 普通按钮TBtn - designerUserGuid

3.1.1 普通按钮TBtn

TBtn是最基础的按钮，其他的按钮控件都是由TBtn的派生类，这些控件都可以用TBtn的属性：

l click()函数，功能是模拟点击一下该按钮。

l multiLine属性，布尔类型，用来设置是否多行显示按钮文字，默认为0.


3.1.2 单选按钮TRadioBtn - designerUserGuid

3.1.2 单选按钮TRadioBtn

TRadioBtn是单选按钮，单选意思是有多个这样的按钮时，只能选择其中的一个。当有多个TRadioBtn对象的parent相同时，选中其中某个按钮时，其他的按钮如果有被选中的，其选中状态会改成未选中状态。注意必须是直接在同一个窗口上的才有这种效果，举个例子，某窗口上有两个tpanel（可以放置其他控件的控件），这两个tpanel上各有几个单选按钮，则每个tpanel上的单选按钮是互斥的，跟另一个tpanel上的单选按钮是没有关系的。

TRadioBtn有以下常用成员：

l checked属性，整数类型，该属性显示该复选框是否被选中，未选中时为0，选中时为1.

l leftText属性，布尔类型，通过设置该属性可设置复选框外观为文字在坐，按钮在右。

l multiLine属性，布尔类型，用来设置是否多行显示按钮文字，默认为0.


3.1.3 复选按钮TCheckBtn - designerUserGuid

3.1.3 复选按钮TCheckBtn

TCheckBtn是复选按钮，该按钮可以选中；跟TRadioBtn不同的是，该按钮跟不会因为其他同类按钮的状态改变而改变，可以同时有多个复选按钮维持选中状态。

TCheckBtn有以下常用成员：

l checked属性，整数类型，该属性显示该复选框是否被选中，未选中时为0，选中时为1.

leftText属性，布尔类型，通过设置该属性可设置复选框外观为文字在坐，按钮在右。

l click()函数，功能是模拟点击一下该按钮。

l multiLine属性，布尔类型，用来设置是否多行显示按钮文字，默认为0.

下面是按钮的简单范例：

代码1. 按钮范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

checkboxSample:=new TCheckbtn(self);

btn1:=new TBtn(self);

btn1.top:=40;

btn1.width:=200;

btn1.caption:="设置文字在左";

btn1.onclick:=thisfunction(proChanged);

btn2:=new TBtn(self);

btn2.top:=80;

btn2.width:=200;

btn2.caption:="设置外观为普通按钮";

btn2.onclick:=thisfunction(viewChanged);

end

function initializeWnd();override;begin

inherited;

checkboxSample.parent:=self;

btn1.parent:=self;

btn2.parent:=self;

end

private

function proChanged(o,e);begin

s:=checkboxSample.leftText;

checkboxSample.leftText:=not s;

o.caption:=s?"设置文字在左":"设置文字在右";

end

function viewChanged(o,e);begin

s:=checkboxSample.pushLike;

checkboxSample.pushLike:=not s;

o.caption:=s?"设置外观为普通按钮":"设置外观为默认外观";

end

checkboxSample;

btn1;

btn2;

end

----------------------------------------------------------------


3.2 可编辑文本框 - designerUserGuid

3.2 可编辑文本框


3.2.1 普通编辑框TEdit - designerUserGuid

3.2.1 普通编辑框TEdit

TEdit是编辑框，也就是可以设输入文本的控件，TEdit比较简单，其常用成员如下所示：

l text属性，字符串类型，用来设置或获取编辑框内的文本

l readOnly属性，布尔类型，用来设置或获取编辑框是否是只读的

l onChange属性，函数指针类型，每当编辑框内文本发生变化时（用户输入或删除文本），就调用该函数。

l onSetFocus属性，函数指针类型，每当编辑框获得输入焦点，例如用户点击编辑框准备输入文本时，就会调用该函数。

l onKillFocus属性，函数指针类型，每当编辑框失去输入焦点，例如用户输入完文本点击窗口的其他地方时，就会调用该函数。

onSetFocus和onKillFocus这两个属性看似不常用，但事实上相当有用。举个例子，在网站上注册账户，一般都可以自己设置用户名，然后系统会检查该账户名是否合法及可用。系统不会每输入一个字就检测一次，而是等用户输入完毕，点击其他地方，例如打算设置密码时检测，此时就可以设置编辑框的onKillFocus属性为检查账户名编辑框内的文本是否可用的操作。

图16. TEdit控件


3.2.2 密码框TPassword - designerUserGuid

3.2.2 密码框TPassword

密码框控件是用来输入密码的文本框，系统不会直接显示输入的字符，而是显示一个个‘*’符号。密码框常用的成员如下所示：

l text属性，字符串类型，用来设置或获取密码框内的文本

l readOnly属性，布尔类型，用来设置或获取密码框是否是只读的

l passwordChar属性，字符类型，用来设置密码框中用来代替真正密码而显示的字符。

l onChange属性，函数指针类型，每当密码框内文本发生变化时（用户输入或删除文本），就调用该函数。

l onSetFocus属性，函数指针类型，每当密码框获得输入焦点就会调用该函数。

l onKillFocus属性，函数指针类型，每当密码框失去输入焦点就会调用该函数。

图17. TPassword控件


3.2.3 多行文本框TMemo - designerUserGuid

3.2.3 多行文本框TMemo

TMemo是可以输入多行文本的编辑框，其常用的成员如下所示：

l getLineCount()函数，无参数、返回值为整数类型，就是编辑框内的函数。

l text属性，字符串类型，通过该属性可设置或获取密码框内的文本

l tabspace属性，整数类型，用来设置文本框内一个tab占多少个字符。

l readOnly属性，布尔类型，通过该属性可设置或获取密码框是否是只读的

l onChange属性，函数指针类型，每当密码框内文本发生变化时（用户输入或删除文本），就调用该函数。

l onSetFocus属性，函数指针类型，每当密码框获得输入焦点就会调用该函数。

l onKillFocus属性，函数指针类型，每当密码框失去输入焦点就会调用该函数。

图18. TMemo控件


3.3 不可编辑文本框TLabel - designerUserGuid

3.3 不可编辑文本框TLabel

上面介绍了可编辑的文本框，这些文本框都可以输入字符；而TLabel是不可编辑的文本框，只能通过其caption属性修改其显示的文本。

图19. TLabel控件


3.4 计时器TTimer - designerUserGuid

3.4 计时器TTimer

计时器是可以设置每隔一定时间就执行特定任务的控件，它是不可见控件，其常用成员如下所示：

l start()函数，参数返回值皆无，调用该函数将开启计时器；

l stop()函数，参数返回值皆无，调用该函数将暂停计时器；

l interval属性，正整数类型，通过该属性设置计时器间隔，单位是ms；

l enable属性，布尔类型，通过读取该属性值可获取计时器是否已启动的信息；

l ontimer属性，函数指针类型，每经过interval指定的时间，就执行一次该函数。

以下是ttimer的一个简单的范例：

代码2. ttimer范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

timer:=new ttimer(self);//创建定时器

timer.onTimer:=thisfunction(timerOnTimer);//设置定时操作

timer.interval:=1000;//设置间隔时间

timer.start();//启动定时器

end

private

function timerOnTimer(o,e);begin

echo datetimetostr(now()),"\n";

end

timer;

end

----------------------------------------------------------------

当代码执行的时候，会不断在终端中输出当前时间。我们在构造函数中创建ttimer并设置其间隔、执行的操作，并且令该计时器启动；当程序运行的时候，定时器可以随时打开、关闭。


3.5 树形控件TTreeView - designerUserGuid

3.5 树形控件TTreeView

TTreeView是树形控件，该控件可以显示一棵多叉树，能够直观地展示各结点间的关系。TTreeView拥有一个逻辑根节点，控件的显示的所有的树的根结点就是该控件根结点的子结点。

图20. TTreeView控件

TTreeView比较复杂，控件的每个结点都是一个TTreeNode对象（见3.5.1），要想使用好TTreeView控件，这两种类都需要了解。TTreeView类常用的成员如下所示：

l checkBox属性，布尔类型，用来设置控件的结点是否带有一个复选按钮，当该属性为1时，每个结点上都带有一个复选框可供选中，每个结点的复选框的选中状态跟其他复选框是无关的，可以同时有多个结点被选中。

l hasLine属性，布尔类型，用来设置控件的结点间是否有线相连

l rootNode属性，TTreeNode类型，该属性就是控件的根结点。

l currentNode属性，TTreeNode类型，用来获取控件当前选中的结点，这个当前选中的结点就是用户在控件内最后一次点击的结点，注意区分于结点复选框的选中状态。

l deleteNode(node:TTreeNode)函数，功能是当指定结点存在时就删除它，返回值为空。

由上可见TTreeView类上常用的成员数量不多；一般来说使用该控件是获取其根结点，然后在根结点上进行增加、删除、查找等操作。


3.5.1 树形控件结点TTreeNode - designerUserGuid

3.5.1 树形控件结点TTreeNode

TTreeNode是树形控件的结点，其类常用成员如下：

l itemCount属性，整数类型，作用是获取该结点当前子结点的数量。

l items属性，数组类型，作用是获取该结点当前的子结点。

l parent属性，TTreeNode类型，作用是获取该结点的父结点。

l checked属性，布尔类型，作用是设置或获取当前结点的复选框（如果有）是否被选中。

l caption属性，字符串类型，作用是设置或获取当前结点显示的名称。

l lastChild属性，TTreeNode类型，作用是获取该结点最后一个子结点。

l getNodeByIndex(idx:int)函数，参数是整数类型，作用是获取指定索引的子结点。

l indexOf(v:TTreeNode)函数，参数是TTreeNode，作用是根据给定子结点获取其索引。

l insertNodeStr(s:string,idx:int)函数，作用是根据给定字符串s构造一个新的结点并将其插入到子结点中索引为idx的位置，返回值是这个被插入的结点。

l insertNode(it:TTreeNode,idx:int)函数，类似insertNodeStr，不过插入的是给定的结点。

l deleteNode(nd:TTreeNode)函数，参数是TTreeNode类型，作用是当指定子结点存在时就删除它。deleteNodeByIndex(idx:int)函数，参数是整数类型，作用是当指定索引的子结点存在时就删除它。

l expand()函数，展开该结点。

l unExpand()函数，折叠该结点。

以下是一个TTreeView的简单范例：

代码3. TTreeView范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

tv:=new TTreeView();

tv.insertNode(

array("type":"treenode","caption":"start","checked":1));

b1:=new tbtn(self);

b1.top:=170;

b1.caption:="添加一个结点";

b1.onclick:=thisfunction(b1click);

b2:=new tbtn(self);

b2.top:=210;

b2.caption:="删除该结点";

b2.onclick:=thisfunction(b2click);

end

function initializeWnd();override;begin

inherited;

tv.parent:=self;

b1.parent:=self;

b2.parent:=self;

end

private

function b1click(o,e);begin

r:=tv.CurrentNode?tv.CurrentNode:tv.rootnode;

r.InsertNodeStr(tostn(int(rand()*100)),int(rand()*r.itemCount));

r.expand();

end

function b2click(o,e);begin

tv.deleteitem(tv.CurrentNode);

end

tv;

b1;

b2;

end

----------------------------------------------------------------

图21. TTreeView范例运行界面

上述范例中，点击“添加一个结点”按钮时，当控件中有结点被选中，则新的结点会插入到该结点的子结点中，否则结点会被插至控件根结点的子结点中。点击“删除一个结点”按钮时，当控件中有结点被选中，则会将该结点删除。


3.6 表格控件TListView - designerUserGuid

3.6 表格控件TListView

TListView是比较常用的控件，可以用来显示一个表格。TListView分为行和列，列相当于字段，每一行都是一个记录，也是一个数组，其中的元素按照索引的顺序显示在控件上。列的增加、删除、修改不会影响的数据，只会影响到数据的显示。例如某控件有5个列，其中的一行有5个元素，当删除其中某个列的时候，行的元素不会被删除一个，而是最后的元素不会被显示。同理，当列的数量高于行的元素数量时，行最后一个元素后面的格子就显示为空，如下图所示：

图22. 每一行的元素数都不同的表格

TListView常用成员如下：

l insertColumn(txt:string,wd:int,idx:int)函数，功能是插入一个列，其中txt是要插入列的列名，wd是要插入列的宽度，idx是要插到第几列前。

l deleteColumn(idx:int)函数，功能是删除指定的列，其中idx是要删除的列的索引。

l deleteAllColumns()函数，功能是删除所有的列。

l getColumnText(n:int)函数，功能是获取指定索引n的列的列名。

l setColumnText(n:int,t:string)函数，功能是设置指定索引n的列的列名为t

l appendItem(v:array)函数，功能是在所有行后面添加一个行。

l insertItemAfter(v:array,id:int)函数，功能是在指定索引id的行的后面插入一个行

l getItem(idx:int)函数，功能是获取指定索引的行的数据

l setItem(idx:int,v:array)函数，功能是设置指定索引的行的数据为数组v

l setSubItemByIndex(idx:int,subidx:int,v)函数，功能是设置指定索引idx的行的第subidx个元素值为v

l columns属性，数组类型，用来获取控件的列的数据。

l itemCount属性，整数类型，用来获取控件的行数。

l selectedId属性，整数类型，用来获取被选中项的行号。

l ListValues属性，数组类型，用来获取控件的行的数据。

以下是一个简单的TListView范例：

代码4. TListView范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

lv:=new TListView();

lv.width:=500;

b1:=new tbtn(self);

b1.top:=290;

b1.caption:="添加一列";

b1.onclick:=thisfunction(b1click);

b2:=new tbtn(self);

b2.top:=330;

b2.caption:="添加一行";

b2.onclick:=thisfunction(b2click);

cnt:=0;

end

function initializeWnd();override;begin

inherited;

lv.parent:=self;

b1.parent:=self;

b2.parent:=self;

end

private

function b1click(o,e);begin

lv.insertColumn(inttostr(cnt++),100,length(lv.columns));

end

function b2click(o,e);begin

i:=length(lv.columns);

arr:=array();

for x:=0 to i-1 do

arr[x]:=inttostr(rand()*100);

lv.appenditem(arr);

end

lv;

b1;

b2;

cnt;

end

----------------------------------------------------------------


3.7 菜单TMenu - designerUserGuid

3.7 菜单TMenu

菜单是一类特殊的控件，通常用来列出程序拥有的功能。分为主菜单和弹出菜单。主菜单是只有主窗口才能使用的菜单，而弹出菜单是所有控件都能使用的菜单。

图23. 菜单

主菜单是TMainMenu，在TVCForm类中有一个属性叫mainmenu，将指定的TMainMenu对象赋值给它就设置了窗口的菜单。同理，弹出菜单类是TPopupMenu，各个窗口都拥有popupmenu这一属性（见2.2.2），将指定的TPopupMenu对象赋值给它就设置了窗口的菜单。

主菜单和弹出菜单的编辑方法是相同的，菜单由菜单项TMenu组成，这些菜单项就是菜单直接的子菜单项。子菜单项本身也可以拥有子菜单项，这样就形成了菜单的嵌套。

TMenu常用成员如下：

l insertItem(item:TMenu,bef:int)函数，参数item是要插入的tmenu，bef是要插入的位置，bef非法时会插入到最后。插入成功时返回-1，否则返回-2。

l removeItemByIndex(idx:int)函数，参数是要删除的子菜单项的索引，当索引合法时删除其对应得菜单项。

l indexOf(item:TMenu)函数，参数是子菜单项，返回其在本TMenu中的索引。

l getItemByIndex(idx:int)函数，参数是子菜单项索引，返回本TMenu中对应该索引的子菜单项。

l caption属性，字符串类型，用来设置或获取该菜单项显示的文字。

l enabled属性，布尔类型，用来设置或获取该菜单项是否可用。

l parent属性，TMenu类型，用来获取该菜单项上一级的菜单或菜单项。

l onclick属性，函数类型，每当鼠标左键单击该菜单项时就会调用。

类似于树形控件，菜单的编辑也往往是以菜单项为基础的：新创建一个主菜单或弹出菜单，在该菜单上创建并插入子菜单项，然后进入这些子菜单项，设置其标题、触发函数并且可以在该菜单项中创建并插入子菜单项并设置它们。

图24. 嵌套菜单


3.8 下拉框TCombobox - designerUserGuid

3.8 下拉框TCombobox

下拉框由一个编辑框和一个下拉按钮组成；当点击下拉按钮时，下拉框会显示一个列表框，点击该列表框中的某个列表项，该项就会显示在编辑框里。

图25. 下拉框

下拉框常用的成员如下所示：

l appendItem(str:strng)函数，参数类型是字符串，功能是将该字符串添加到控件的列表项的最后边。

l insertItem(str:string,idx:int)函数，第一个参数类型是字符串，第二个参数类型是整数，功能是将给定字符串插至列表项中指定位置。

l deleteItem(idx:int)函数，参数类型是整数，功能是删除指定索引的列表项。

l clean()函数，功能是清空列表项。

l getItemCount()函数，返回值是整类型，功能是获取列表项的数量。

l getItemText(idx:int)函数，参数是整数类型，返回值是字符串类型，功能是获取指定下标的列表项文字。

l showDropdown(b:bool)函数，参数是布尔类型，功能是设置是否显示下拉框的列表框。

l itemIndex属性，整数类型，用来设置和获取下拉框当前选中项的索引。

l items属性，数组类型，用来设置和获取下拉框的列表项。

l onDropdown属性，函数类型，每当列表框显示时调用。

l onCloseup属性，函数类型，每当列表框隐藏时调用。

l onEditChanged属性，函数类型，每当用户编辑完毕编辑框后调用。

l onEditUpdate属性，函数类型，每当用户开始编辑编辑框时调用。


3.9 列表框TListBox - designerUserGuid

3.9 列表框TListBox

列表框就是下拉框中展示列表项的控件，相比于下拉框中的列表框，列表框控件拥有的功能更多。

图26. 列表框

列表框常用成员如下所示：

l appendItem(item:string)函数，参数是字符串类型，功能是将该字符串添加至列表框的末尾。

l appendItems(arr:array of string)函数，参数是字符串数组，功能是将该数组中所有字符串添加至列表框的末尾。

l insertItem(item:string,idx:int)函数，第一个参数是字符串类型，第二个参数是整数类型，功能是将该字符串插入列表框内指定位置。

l insertItems(arr:array of string,idx:int)函数，第一个参数是字符串数组，第二个参数是整数类型，功能是将该数组内所有字符串插入列表框内指定位置。

l deleteItem(idx:int)函数，参数是整数类型，功能是删除指定索引的列表项。

l deleteItems(b:int,e:int)函数，两个参数都是整数类型，功能是删除指定两个索引位置上及其间的所有列表项。

l getItemCount()函数，返回值是整数类型，功能是获取列表框的项数。

l getItemText(idx:int)函数，参数是整数类型，返回值是字符串类型，功能是获取指定索引的项的文本。

l clean()函数，功能是清空列表框。

l getCurrentSelection()函数，返回值是整数类型，功能是获取当前选中项的索引。

l setCurrentSelection(idx:int)函数，参数是整数类型，功能是设置当前选中项的索引。

l getItemSelectedState(idx:int)函数，参数是整数类型，返回值是布尔类型，功能是获取指定项的选中状态。

l Items属性，字符串数组类型，用来设置和获取列表框的项的文本。

l onSelectionChange属性，函数类型，每当列表框选中项改变时，就调用该函数。


3.10 文件对话框 - designerUserGuid

3.10 文件对话框

文件对话框是用来选择文件或文件夹的控件，该控件是不可见控件，但不同于TTimer，它可以弹出一个对话框来供用户选择文件或文件夹。


3.10.1 文件保存对话框TSavefileADlg - designerUserGuid

3.10.1 文件保存对话框TSavefileADlg

文件保存对话框用来选择要保存文件的对话框，用来选择文件或文件夹的对话框都是相似的，但是文件保存对话框有自己独特的功能。例如文件和文件夹选择对话框只能选择已有的文件或文件夹，而文件保存对话框往往要创建并保存到一个新的文件，这样就需要允许文件保存对话框返回一个不存在的文件路径。并且，文件保存对话框选择了一个已有的文件时，为了数据安全，应该允许程序弹出一个警告对话框以询问用户是否确定覆盖该文件。

图27. 文件保存对话框

l chooseDlg()函数，返回值是布尔类型，打开对话框以选择文件，当选择有效的文件路径时，返回1，否则返回0.

l getSelectedItemName()函数，返回值是字符串类型，返回所选择的文件的文件名，当选择不止一个文件时，返回首文件名。

l getResults()函数，返回值是字符串数组类型，功能是获取所选择的所有文件的完整路径。

l filter属性，数组类型，用来设置对话框的过滤文件类型，格式举例：

array("所有文件":"*.*","文本文件":"*.txt")

l defaultFileExtension属性，用来设置默认扩展名，也就是当文件名输入框中未指定扩展名且未选择保存类型时将使用的扩展名。

l initialDir属性，字符串类型，用来设置初始目录。

l showHidden属性，布尔类型，用来设置是否显示隐藏的文件。

l multiSelected属性，布尔类型，用来设置对话框是否可多选。

l overwritePrompt属性，布尔类型，用来设置开启覆盖保存提示。


3.10.2 文件打开对话框TOpenfileADlg - designerUserGuid

3.10.2 文件打开对话框TOpenfileADlg

文件打开对话框是用来选择文件以打开的对话框，相比于文件保存对话框，其功能较为简单。其常用成员如下所示：

l chooseDlg()函数，返回值是布尔类型，打开对话框以选择文件，当选择有效的文件路径时，返回1，否则返回0.

l getSelectedItemName()函数，返回值是字符串类型，返回所选择的文件的文件名，当选择不止一个文件时，返回首文件名。

l getResults()函数，返回值是字符串数组类型，功能是获取所选择的所有文件的完整路径。

l filter属性，数组类型，用来设置对话框的过滤文件类型，格式示例：

array("所有文件":"*.*","文本文件":"*.txt")initialDir属性，字符串类型，用来设置初始目录。

l showHidden属性，布尔类型，用来设置是否显示隐藏的文件。

l multiSelected属性，布尔类型，用来设置对话框是否可多选。

以下是文件对话框的一个简单范例：

代码5. 列表框和文件对话框范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

b:=new tbtn(self);

listbox:=new TListBox(self);

listbox.left:=10;

listbox.top:=10;

listbox.height:=350;

listbox.width:=300;

addFileBtn:=new tbtn(self);

addFileBtn.left:=330;

addFileBtn.top:=10;

addFileBtn.caption:="添加文件";

addFileBtn.onclick:=thisfunction(addFileBtnClick);

deleteItemBtn:=new tbtn(self);

deleteItemBtn.left:=330;

deleteItemBtn.top:=50;

deleteItemBtn.caption:="删除选中项";

deleteItemBtn.onclick:=thisfunction(deleteItemBtnClick);

clearBtn:=new tbtn(self);

clearBtn.left:=330;

clearBtn.top:=90;

clearBtn.caption:="清空列表";

clearBtn.onclick:=thisfunction(clearBtnClick);

printBtn:=new tbtn(self);

printBtn.left:=330;

printBtn.top:=130;

printBtn.caption:="打印路径";

printBtn.onclick:=thisfunction(printBtnClick);

file:=new TOpenFileADlg(self);

file.multiSelected:=1;

file.caption:="添加文件";

save:=new TSavefileADlg(self);

save.filter:=array("文本文件":"*.txt","所有类型":"*.*");

save.defaultFileExtension:="txt";

save.caption:="保存文件";

end

function initializeWnd();override;begin

inherited;

listbox.parent:=self;

addFileBtn.parent:=self;

deleteItemBtn.parent:=self;

clearBtn.parent:=self;

printBtn.parent:=self;

file.parent:=self;

save.parent:=self;

end

private

function addFileBtnClick(o,e);begin

if (not file.chooseDlg()) then

return;

for i,v in file.getResults() do

if listbox.findStrExact(v)=-1 then

listbox.appendItem(v);

end

function deleteItemBtnClick(o,e);begin

i:=listbox.getCurrentSelection();

if i>=0 then

listbox.deleteItem(i);

end

function clearBtnClick(o,e);begin

listbox.clean();

end

function printBtnClick(o,e);begin

if (not save.chooseDlg()) then

return;

dir:=save.getResults()[0];

if(fileExists("",dir))then

fileDelete("",dir);

str:=array2str(listbox.stringItems,"\n");

r:=writeFile(rwraw(),"",dir,0,length(str),str);

if r=1 then

MessageBoxA(self.Handle,"保存成功","保存成功",0);

else

MessageBoxA(self.Handle,r,"保存失败",0);

end

listbox;

file;

save;

addFileBtn;

deleteItemBtn;

clearBtn;

printBtn;

end

----------------------------------------------------------------

该范例可以选择一些文件，并将它们的路径保存到指定目录下。

图28. 列表框和文件对话框范例

上述对话框支持多选，此时选择的文件的完整路径将作为字符串数组被保存，可以通过getResults()函数获取该数组，当对话框未开启多选模式或开启多选模式但只选择一个文件的情况下，该数组就只有一个元素了。


3.10.3 文件夹选择对话框TFolderChooseADlg - designerUserGuid

3.10.3 文件夹选择对话框TFolderChooseADlg

文件夹选择对话框只能用来选择文件夹，不能选择文件。跟其他的文件对话框不同的是，文件夹选择对话框不能够多选，外观也完全不同。

图29. 文件夹选择对话框

文件夹选择对话框常用成员如下所示：

l chooseDlg()函数，返回值是布尔类型，打开对话框以选择文件夹，当选择有效的文件路径时，返回1，否则返回0.

l defaultDir属性，字符串类型，用来设置对话框所显示的初始目录。

l rootFolder属性，字符串类型，用来设置对话框选择范围：指定该属性为某路径时，则只能在该路径下选择文件夹。

l editBox属性，布尔类型，用来设置是否显示一个编辑框以供用户指定文件夹。

l folder属性，字符串类型，用来获取对话框选择的路径，在使用该函数前应检查最近一次chooseDlg函数调用的返回值是否为1。


3.11 图像列表TControlImageList - designerUserGuid

3.11 图像列表TControlImageList

图像列表是不可视控件，但从功能上来看，它更像是一种数据结构，用来组织程序中用到的图像，以便于其他控件检索、使用。

l addBmp(bmp:TBitmap)函数，参数是TBitmap类型（见3.11.1），功能是向图像列表中添加图像。

l imgheigt 图标高度,修改后会清空图标,在addbmp前设置

l imgwidth 图标宽度,修改后会清空图标,在addbmp前设置

l removeImge(idx:int)函数，参数是整数类型，功能是移除指定索引的图像。

l imageCount属性，整数类型，用来获取图像列表中的图像数量。


3.11.1 位图类TBitmap - designerUserGuid

3.11.1 位图类TBitmap

位图对象，用来存储位图信息以供程序中使用。

l id属性，表示图像的资源id，将该属性设置为硬盘中图像的路径即可读取并保存。图像应该是bmp或png格式的小图，其路径可以是绝对路径；也可以是相对路径（见代码6），此时相对路径起始地址从执行该程序所用的解释器所在的路径开始计算。

位图对象创建并设置后，即可将其添加至图像列表中以备使用。


3.12 工具栏TToolbar - designerUserGuid

3.12 工具栏TToolbar

工具栏是一个可以放置工具按钮的长条面板，位于窗口的顶部。往往将程序中最常用的功能添加到上面。工具栏常用成员如下所示：

l addButton(btn:TToolButton)函数，参数是TToolButton类型，功能是将该工具栏按钮添加到上面

l insertButton(btn:TToolButton,bef:int)函数，第一个参数是TToolButton类型，是要添加的工具栏按钮，第二个参数是要添加的位置。

l deleteButton(btn:TToolButton)函数，参数是TToolButton类型，功能是当该工具栏控件已经被添加到工具栏上时，就把它移除。

工具栏高度依赖工具栏按钮，控件机制的设计是将工具栏上的每一个按钮抽象出来，成为一个单独的类，在这些按钮对象中定义它们各自的属性，要想使用工具栏，不但需要创建工具栏控件，还需要创建并设置要用到的工具栏按钮对象，并将它们添加的工具栏上。


3.12.1 工具栏按钮TToolButton - designerUserGuid

3.12.1 工具栏按钮TToolButton

工具栏按钮是工具栏上用到的按钮，每个按钮需要设置自己的属性，如下所示：

l onclick属性，函数指针类型，当鼠标点击了该按钮时将会调用。

l caption属性，字符串类型，用来设置当鼠标指针悬停在该按钮上将会显示的说明文字。

l imageId属性，整数类型，用来设置该按钮的图标。

l enabled属性，布尔类型，用来设置该按钮是否有效。

l visible属性，布尔类型，用来设置该按钮是否可见。

代码6. 工具栏范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

//创建图像列表

aImageList:=new TControlImageList(self);

//创建位图对象并设置图像

bmpo:=new TBitmap(self);

//设置位图对象所用图像的硬盘位置，此处使用的是相对路径。

bmpo.id:=".\\a.bmp";

//将位图对象添加到图像列表中，此时图像列表中只有一个图像，其索引值为0.

aImageList.addbmp(bmpo);

//创建工具栏控件

toolBar:=new TToolBar(self);

//创建工具按钮，并设置其属性

button:=new TToolButton(self);

button.caption:="exit";

button.imageid:=0;//将imageid属性设置为0，则

button.onclick:=thisfunction(doexit);

//设置工具栏的使用的图像列表

toolBar.imagelist:=aImageList;

//将按钮添加到工具条中

toolBar.addbutton(button);

end

function initializeWnd();override;begin

inherited;

toolBar.parent:=self;

end

private

function doexit(o,e);begin

if MessageBoxA(self.Handle,"是否退出","退出",1)=1 then

ExitMessageLoop();

end

toolBar;

aImageList;

end

----------------------------------------------------------------

代码中使用了如下所示的图标：

图30. 图标

则在程序运行时，工具栏的显示如下所示：

图31. 工具栏


3.13 状态栏TStatusBar - designerUserGuid

3.13 状态栏TStatusBar

状态栏,通常位于窗口的底部,显示程序的运行状态。状态栏常用成员如下所示：

items :属性,设置或者获取所有的item项目,二维数组包括,text 和 width 两个字段

  items := array(("width":0.8,"text":"a"),("width":100,"text":"b"));

setitemtext(caption:string,idx:integer) 设置指定下标项的文本

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.CreateForm(class(tvcform),fm);

status := new TStatusBar(fm);

status.items := array(("width":0.8,"text":"a"),("width":100,"text":"b"));

status.parent := fm;

fm.show();

app.run();

----------------------------------------------------------------

图32. 状态栏效果图


3.14 进度条tprogressbar - designerUserGuid

3.14 进度条tprogressbar

进度条,显示程序的运行状态。进度条常用成员如下所示：

range:属性,设置进度条的上下界

  range:=array(1,100);

Position:属性, 设置当前位置

smooth : 属性 bool类型 设置进度条平滑

barColor: 属性rgb颜色值,设置进度颜色

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.CreateForm(class(tvcform),fm);

progress := new tprogressbar(fm);

progress.range := array(0,100);

progress.Position := 30;

progress.parent := fm;

fm.show();

app.run();

----------------------------------------------------------------

图33. 进度条效果图


3.15 日期选择控件 - designerUserGuid

3.15 日期选择控件

日期选控件

setDate(y:integer;m:integer;d:integer):成员函数,设置时间

GetDate():成员函数,获得控件时间 返回数组: array(y,m,d);

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.CreateForm(class(tvcform),fm);

dtpk := new tdatetimepicker(fm);

dtpk.setDate(2020,1,7);

dtpk.parent := fm;

fm.show();

app.run();

----------------------------------------------------------------

图34. 日期控件效果图


3.16 容器控件 - designerUserGuid

3.16 容器控件

前面介绍了常用的控件，这些控件都是拥有特定功能的窗口，接下来要介绍的是没有自己的功能，专门用来放置其他控件的窗口，叫做容器。

容器有以下的常用成员：

l minWidth属性，整数类型，用来设置窗口的最小宽度，当窗口的宽度等于该值时，将不能调整的更小。

l minHeight属性，整数类型，用来设置窗口的最小高度，当窗口的高度等于该值时，将不能调整的更小。

l wsDlgModalFrame属性，布尔类型，用来设置窗口显示具备凹凸感的边。


3.16.1 程序主窗口TVCForm - designerUserGuid

3.16.1 程序主窗口TVCForm

TVCForm是程序的主窗口，所有的控件最终都要被放置在主窗口上，一个程序可能拥有多个主窗口。运行以下代码即可创建一个空的、原始的主窗口。

代码7. 创建一个主窗口

----------------------------------------------------------------

uses tslvcl;//使用库文件

app := InitializeApplication();//初始化UI程序

app.createform(class(tvcform),form);//创建程序窗口

app.run();//启动程序窗口

----------------------------------------------------------------

图35. 主窗口tvcform

tvcform只是一个空的窗口，为了能够开发出可用的程序，可以使该类派生出一个新类，然后在新类中设置控件及功能，然后令程序创建这个新的类作为窗口。

代码8. 自定义窗口

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tvcform),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

//在此实现所需的功能

end

function initializeWnd();override;begin

inherited;

//在此实现所需的功能

end

//在此实现所需的功能

end

----------------------------------------------------------------

在上述类中，有一个create函数，这个是类的构造函数，通常在此处为该类中定义的新的数据成员初始化；而initializewnd函数是初始化窗口函数，程序在这个函数中创建并显示窗口，通常在这个函数中定义窗口中控件等窗口的parent，以令它们显示。在tvcform及其基类中的这两个函数都有自己的职责，故在自定义派生类的时候应在函数开始处使用inherited关键字以令对象在构造的时候调用其基类中被覆盖的函数以完成相应职责。

TVCForm有一个常用的属性：onClose函数指针，当用户点击了窗口的关闭按钮时将会调用该函数。可以在该函数中执行一些有必要的操作；程序调用函数的第二个参数拥有一个skip属性，将该属性设置为1就能够跳过该操作：关闭窗口的操作。利用这个特性可以实现当关闭窗口时询问是否确定关闭的操作，如下所示：

在主窗口的构造函数中加入以上代码，就能够实现这个效果。

图36. 窗口关闭提示


3.16.2 面板TPanel - designerUserGuid

3.16.2 面板TPanel

TPanel和TVCForm一样都是容器，可以放置其他的控件或容器，而不同的是，TPanel不是一个主窗口，也就意味着它需要被放置在其他的容器中。

图37. TPanel

TPanel拥有具有凹凸效果的边，可以令它们隐藏，只需把对象的wsDlgModalFrame属性设置为0即可。当隐藏边后，因为TPanel和TVCForm的颜色一样，会导致看不到TPanel，为解决这个问题，可以将其border属性（见2.2.2）设置为1，这样TPanel的轮廓就明显了。

图38. 具有边界的TPanel

每个窗口控件都拥有一个parent成员（见2.2.2），将指定的容器赋值给该成员就能令该窗口控件显示在其上。可以在程序运行期间改变这一属性，此时窗口控件就会立刻显示在新的容器上。


3.16.3 选项卡控件TPageControl - designerUserGuid

3.16.3 选项卡控件TPageControl

选项卡控件是可以像笔记本一样，将各个容器分页显示的控件。控件上方是页名，下侧是显示的具体的页。当点击上方的某个页名时，控件下侧即切换至该页名对应的页。

图39. 选项卡控件

其常用成员如下所示：

l appendPage(page:TTabSheet)函数，参数是TTabSheet类型（见4.3.1），功能是将指定的选项卡页添加到控件中。

l setTabIndex(oidx:int,newidx:int)函数，参数是整数类型，功能是调整选项卡页的顺序：将索引为oidx的页调整至newidx的位置。

l removePage(idx:int)函数，参数是整数类型，功能是移除指定索引的选项卡页。

l cursel属性，整数类型，用来设置默认展示的页。

l onSelChange属性，函数指针类型，当用户切换显示的选项卡页时，将会调用该函数。

l tabCount属性，整数类型，用来获取控件中选项卡页的数量。

类似工具栏控件，选项卡控件也是同选项卡页高度关联的，同样是通过修改选项卡页对象来修改控件


3.16.4 选项卡页TTabSheet - designerUserGuid

3.16.4 选项卡页TTabSheet

选项卡页可以当做普通的容器使用；通过修改其caption属性可以改变该页在控件上显示的名称，选项卡控件范例如下：

代码9. 选项卡控件范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

pageControl:=new TPageControl(self);

label1:=new tlabel(self);

label1.caption:="PAGE1";

tabsheet1:=new TTabSheet(self);

tabsheet1.caption:="1";

tabsheet2:=new TTabSheet(self);

tabsheet2.caption:="2";

pageControl.appendPage(tabsheet1);

pageControl.appendPage(tabsheet2);

end

function initializeWnd();override;begin

inherited;

tabsheet1.parent:=pageControl;

label1.parent:=tabsheet1;

tabsheet2.parent:=pageControl;

pageControl.parent:=self;

end

private

pageControl;

tabsheet1;

tabsheet2;

label1;

end

----------------------------------------------------------------


3.16.5 分页控件TPairSplitter - designerUserGuid

3.16.5 分页控件TPairSplitter

图40. 分页控件

分页控件也是容器，可以分栏显示（默认是并排显示）两个容器，它们之间互不影响。分页控件常用成员如下所示：

l addSide(aSide: TPairSplitterSide)函数，参数是TPairSplitterSide类型，功能是将指定的页添加到控件中。

l removeSide(aSide: TPairSplitterSide)函数，参数是TPairSplitterSide类型，功能是从控件中移除指定的页。

l position属性，整数类型，用来获取和设置控件中间分隔位置，以像素为单位。

l splitterType属性，整数类型，用来设置控件视图，可以是以下值：

pstHorizontal横向 pstVertical纵向

类似选项卡控件的页，分页控件的页可以当做普通容器使用，但是其不能显示名称。显式创建TPairSplitterSide对象，然后通过addSide函数将其添加到分页控件中，接下来只需在相应的TPairSplitterSide对象上放置并设置控件，就会显示在分页控件上。分页控件范例如下所示：

代码10. 分页控件范例

----------------------------------------------------------------

uses tslvcl;

app := InitializeApplication();

app.createform(class(tforma),form);

app.run();

type tforma=class(tvcform)

function create(AOwner);override;begin

inherited;

pairSplitter:=new TPairSplitter(self);

pairSplitter.width:=300;

pairSplitter.height:=300;

label1:=new tlabel(self);

label1.caption:="SIDE1";

pairSplitterSide1:=new TPairSplitterSide(self);

pairSplitterSide2:=new TPairSplitterSide(self);

pairSplitter.AddSide(pairSplitterSide1);

pairSplitter.AddSide(pairSplitterSide2);

end

function initializeWnd();override;begin

inherited;

pairSplitterSide1.parent:=pairSplitter;

label1.parent:=pairSplitterSide1;

pairSplitterSide2.parent:=pairSplitter;

pairSplitter.parent:=self;

pairSplitter.position:=100;

end

private

pairSplitter;

pairSplitterSide1;

pairSplitterSide2;

label1;

end

----------------------------------------------------------------


4. 其他工具 - designerUserGuid

4. 其他工具


4.1 多线程工具TThreadWorker - designerUserGuid

4.1 多线程工具TThreadWorker


4.1.1 工作线程TThreadWorker和子线程TThreadWorkerClient - designerUserGuid

4.1.1 工作线程TThreadWorker和子线程TThreadWorkerClient

工作线程TThreadWorker类用来创建一个新的线程，并对其进行管理；而子线程TThreadWorkerClient则是这个新的线程中真正执行的对象，也就是说要想令某段代码在一个独立的线程中运行，就需要将其添加到TThreadWorkerClient对象中。

当TThreadWorker对象成功创建后，就会开启一个子线程，该线程里运行着TThreadWorkerClient对象。而TThreadWorker所在的线程就是TThreadWorkerClient所在线程的父线程。当子线程工作结束后，父线程就可以结束它。

父子线程对象间通过onMessage属性和postMessage函数进行通信，两种类都有这样的成员。onMessage属性是函数指针类型，用来相应接收到的信息。postMessage函数有一个参数，其功能就是把这个参数传递给对应的父/子线程对象。然后接收消息的对象就会调用其onMessage属性绑定的函数进行处理。该函数拥有两个参数，第一个参数是发送消息的对象，第二个参数就是传递过来的消息。函数根据这些参数执行相应的操作。


4.1.2 TThreadrWorker的使用 - designerUserGuid

4.1.2 TThreadrWorker的使用

TThreadWorker构造函数：

create(s:string,libs:string,declaration:string)

其中s是对被创建的TThreadWorkerClient对象执行的脚本，字符串形式。程序根据这个脚本对子线程TThreadWorkerClient进行相应的处理，可以在字符串中对TThreadWorkerClient对象的成员进行操作（主要是修改它的onMessage属性（参见5.1.1）以向子线程分配特定工作），字符串中可以用变量“this”代指要修改的TThreaderWorkerClient对象。

libs是子线程对象运行要使用的库名，字符串形式，以逗号开始且库名间用逗号隔开。该参数可以为nil。

declaration是子线程对象额外定义的局部函数或类，字符串形式。可以在这里定义函数或类，然后在s中使用它们。

TThreadWorker常用成员：

l terminate函数，参数为空，功能是结束子线程。

l onMessage属性，函数指针类型。当子线程使用postMessage发送消息时，就会调用该属性绑定的函数。有两个参数，第一个是子线程对象，第二个是发送的消息。

l onError属性，函数指针类型。当子线程执行出错时，会调用该属性绑定的函数。有两个参数，第一个是子线程对象，第二个参数是错误信息数组。

l postMessage函数，参数为tsl基本类型以及数组，该函数功能是向子线程对象发送消息。


4.1.3 TThreadWorkerClient的使用 - designerUserGuid

4.1.3 TThreadWorkerClient的使用

前面介绍过，TThreadWorkerClient是真正在子线程中运行的对象，我们不能直接对其进行操作；需要通过TThreadWorker间接对其发出指令（参见5.1.1）。在构造TThreadWorker时，就需要提供这个对其操作的脚本（参见5.1.2），在这个脚本里， TThreadWorkerClient有以下成员可以使用：

l close函数，参数为空，功能是主动关闭该线程。

l onMessage属性，函数指针类型。当父线程使用postMessage发送消息时，就会调用该属性绑定的函数。有两个参数，第一个是父线程对象，第二个是发送的消息。

l postMessage函数，参数不限，该函数功能是向父线程对象发送消息。


4.1.4 TThreadWorker范例 - designerUserGuid

4.1.4 TThreadWorker范例

TThreadWorker的实现使用了操作系统的api，通过父线程的TThreadWorker对象的postMessage向其对应的子线程对象TThreadWorkerClient发送消息，除此之外它们的数据是不互通的。子线程对象根据构造父线程对象时提供的脚本中定义的函数对传递过来的消息进行处理。父线程传递完毕消息后就可以继续执行下面的操作，而子线程处理这个消息的操作是同时进行的；当子线程处理完毕后可以通过调用postMessage向父线程对象发送一个信号表示执行结束，或者把处理完的消息直接当做参数发送给父线程对象。当子线程对象不再被需要时，可以自行结束，也可以由父线程对象结束它。

代码11. TThreadWorker范例

----------------------------------------------------------------

uses tslvcl;

app := initializeapplication();

script:=%%

this.onmessage:=function(o,e)begin

if e=-1 then

this.close();

o.postmessage(e+1);

end

//在此处定义子线程的处理脚本。

%%;

declareF:=%%

//在此处定义子线程用到的其他函数或对象。

%%;

worker := new TThreadWorker(script,nil,declareF);

worker.onmessage:=thisfunction(workerMessage);

app.run();

function workerMessage(o,e);begin

echo e,"\n";

if e>=100 then

o.postmessage(-1);

else

o.postmessage(e);

end

----------------------------------------------------------------

执行以上代码，将会在控制台打印出0-100的数字，父线程将一个数发送给子线程，子线程将这个数加一再返回，父线程再将其打印出来然后重新发送给子线程。这种情况下父线程只负责显示数字，而子线程负责增加这个数字。

当数字超过100时，父线程向子线程发送一个数字-1，子线程收到-1时，就会调用close函数结束线程。