其他语言

位置:IT落伍者 >> 其他语言 >> 浏览文章

如何用Delphi编写自己的可视化控件


发布日期:2021年06月15日
 
如何用Delphi编写自己的可视化控件
可视化控件(Visual Component)实际上就是一个类(class)要编写一个类可以直接在*pas文件中编写但是要编写控件则必须使用包(package)从File菜单中选择New新建一个Package这就是存放和安装控件用的包然后单击Package窗口中的Add按钮添加一个元件(Unit)

在弹出的对话框最上方选择New Component因为一个控件的所有属性方法事件不可能都由自己编所以就需要选择祖先类(或者叫做父类基类然后再在其上面添加自己的属性方法事件在Ancestor type后的下拉框中选择所需的祖先类由于编写可视化控件必须要画图所以选择TGraphicControl作为祖先类再在Class Name框中输入新控件(类)的名称一般以T开头Palette Page是用来选择新控件在Delphi的窗口中的控件页面名称例如Standard 这个可以自己取在Unit File Name中添好新控件文件的路径及文件名单击OK按钮新的控件便加入了现在可以为该控件编写代码了

下面以编写一个可以自定义图片的滚动条为例说明编写可视化控件的方法

按照上面的方法选择TGraphicControl为祖先类新控件的名称是TPigHorizontalScroller (小猪水平滚动条)选择好文件路径和文件名后单击OK按钮开始编写代码

每一个控件都会被创建(Create)和删除(Destroy)所以必须首先编写这两个过程对于控件中的每一个过程都必须在前面先定义然后再在后面编写

定义的过程或属性有三种

(1)在private后定义的是属于控件内部使用的使用该控件的人无法看到

(2)在protected后定义的一般是看不到的只在别人使用该控件作为祖先类编写其它控件时才可见

(3)在public后定义的只允许别人在程序中调用

(4)在published后定义的可以在属性窗口(Object Inspector)中看到由于创建和删除过程除了在编程过程中建立控件时自动执行外还可能在程序运行过程中动态创建控件时被调用所以把它定义在public后⑴(该序号表示次步骤在所附源程序中的代码的位置下同)现在也许还不知到应该在这两个过程中编写什么如何去编我们在下面将会讲到

我们首先为这个控件添加一些属性我们定义一个Max属性用于设置或读取滚动条的最大值因为在程序中一般不直接使用属性所以要定义一个变量和该属性对应起来一边修改或读取其值因为它只在控件内部使用所以我们把它定义在private后⑵(一般与属性相关联的变量都以F开头例如FMax)定义好变量后再定义属性这个属性需要再Object Inspector窗口中可见所以把它定义再published后⑶定义的语法是

property <属性名>:<类型> read <读取该属性时对应的变量> write <写入该属性时对应的变量或过程>

其它的变量和属性也类似的定义(例如Min最小值Value当前值等)下面我们定义几个属性和变量用于设置滚动条的图片(因为图片变量比较特殊所以单独讲一下)我们把LeftButtonUpPicture(向左按钮图片)LeftButtonDownPicture(向左按钮按下图片)等定义为TBitmap类型(一定要定义相对应的变量)

大家一定注意到了在所附的源程序中定义这几个属性时read后所指定的读取属性时对应的变量是F…而write后指定的写入该属性时对应的不是一个变量而是一个Set…之类的东西这是一个自定义的过程作为该功能的过程的定义为

procedure <过程名>(Value: <被设置的属性的值的类型>)

因为执行写入该类属性的时候需要做其它的事情所以不能光用一个变量来处理应该用一个过程来处理这中过程一般定义在protected后在该类过程中使用一个在⑷处这样一个语句来给TBitmap类型的变量来赋值这是由于该类型的变量不能直接赋值而采用的

定义完这些TBitmap类型的变量的属性后上面讲的create过程和destroy过程中就需要编写代码了因为TBitmap也是一个类所以在create过程中必须创建⑸在destroy过程中必须释放掉(free)⑹这里⑺所指的inherited语句是用于指明该过程是从祖先类类中继承来的(这个一定不能掉)

因为我们编写的是可视化控件所以必须在控件上画图我们这个控件的祖先类TGraphicControl中封装有一个Canvas(画布)对象我们可以直接使用它来画图如果你对画布的使用还不太熟悉最好去找一本书来看一看

下面要做的工作就是画图了如何在控件上画图呢?祖先类TGraphicControl中有一个Paint事件当控件需要重画时便会自动触发我们现在要做的就是要为这个事件编写一段程序首先在protected后定义一个Canvas对象由于它是祖先类中已有的所以不需要加任何说明⑻我们将使用这个对象来画图接着就要定义一个Paint过程编写绘制控件的代码先在public后定义Paint过程由于它是由祖先类触发的而不是由用户调用的所以后面必须加上override否则该控件将会由于Paint过程永远不会被调用而不成为可视化控件⑼下面我们就来编写Paint过程的代码⑽

该文章所附的源程序的Paint过程中的T_Height等变量是用来保存滚动条中按钮滑块等的大小的这部分程序和普通的Application中的程序差别不大大部分都是对画布进行操作相信大家一看就明白值得注意的是下面对FAutoSize变量的判断⑾FAutoSize是和该控件的属性AutoSize相关联的布尔型变量是用来设置这个控件的大小是否随图片的大小而变化的注意在控件的代码中一般都不直接调用属性而是使用与其相对应的的变量

程序编到这里就算是终于给自己的新控件做了一个外型了不过它还不能滚动现在我们来编写鼠标事件让我们能够操纵它鼠标事件的过程的定义和Paint过程很相似只是后面要加上参数说明⑿鼠标事件分为MouseDownMouseMove和MouseUp三个在定义后面都要加上override接下来在后面编写它的代码注意这里的鼠标事件是Mouse…而不是通常的OnMouse…可是在⒀处的定义是干什么用的呢?这里的事件定义都是给用户使用的也就是说当使用该控件时会在Object Inspector中的Event页面中显示出来

这些鼠标事件的代码也非常简单判断鼠标的坐标在画布上画出相应的图片等并同时触发相应的事件值得注意的是在调用自定义事件时都要先用⒁处的这样一个语句来判断用户是否已经为该事件编写代码这一点非常重要否则会调用出错

大家注意到了刚才所调用的事件都是自定义的定义的方法也很简单和定义属性差不多只是类型时TNotifyEvent罢了

TNotifyEvent是默认事件其定义为

TNotifyEvent = procedure(Sender: TObject)

如果你要定义另外形式的事件就必须这样先在type后编写

<事件类型名称> = procedure(<参?gt;:<类型>)

例如

TCustomEvent = procedure(a: Integer; b:String);

然后在public后定义

<事件名称>:<事件类型名称>

例如

AnEvent: TCustomEvent;

看完这些这整个程序你应该理解了吧如果编译或运行出错注意检查以下几点

(1)create和destroy过程中是否有inherited语句

(2)TBitmap类型的变量create和free了没有

(3)过程前有没有控件名例如TPigHorizontalScrollerMoseMove

判断鼠标是否进入或离开控件的方法

定义如下的过程

procedure MouseEnter(var Msg: TMessage); message CM_MOUSEENTER;

procedure MouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;

再在下面编写代码就行了这个方法用于编写三态按钮很有用

上一篇:Delphi数据库控件使用入门(三)

下一篇:Delphi中使用纯正的面向对象方法