无节操非程序猿

莫催稿,催稿也不交

自定义 CodeTyphon 的包和组件

CodeTyphon 提供了海量的组件包,它们对开发提供了极大的便利,也是 CodeTyphon 易于上手的一大原因。在实际开发中,也会经常遇到内置组件无法满足需求的情况,直接在代码中进行修改固然是一个办法,但是考虑到代码的复用性,很多时候我们都会试图建立一个自定义的包,把修改过的组件放置在内,以便让其他的开发者获得便利。CodeTyphon 之所以发展到现在会拥有如此多的组件,与开源社区的贡献密不可分,本章我们即来看一下如何建立一个自定义的包。

还是以之前的员工管理工具为例,我们已经拥有了一个原形程序:

图1 员工管理工具原形

左侧的列表显得非常单薄,需要将它修改成更美观的样式,比如说如图2的样子:

图2 修改ListBox样式

在 TListBox 的属性列表内翻了一遍,没有找到能如此修改的方法。事实上 TListBox 也没有提供这样的方法,所以即需要手动进行修改了。从图2以可以看到,由于界面的绘制方法发生了变化,因此也引起了界面效果的不同,这一过程称为『自绘』。系统内置的组件毕竟绘制效果单一,无法适用于所有的需求,自绘的存在即是解决这一问题的利器。


『使用自绘』

在 LCL 内,可视化组件都拥有一个同样的内置对象 Canvas,即画布,可以通过在画布上绘画,从而达到自己想要的效果。Canvas 提供了一系列的绘制方案,在代码任意地方输入 TCanvas 并选中后按 F1,可以看到 TCanvas 的文档,文档内详细描述了 TCanvas 的属性、方法及其作用。

图3 TCanvas的帮助文档

简单的了解一下 TCanvas 后,我们先来想办法实现图2的效果。将 TListBox 的 Style 属性改为 lbOwnerDrawFixed,表示允许自绘,再将 ItemHeight 属性改为50。对于 TListBox 来说,由 Style 属性决定是否可以自绘,其他的组件会有不同名称的属性来决定自绘许可,又或是直接可以自绘。

然后双击 TListBox 的 OnDrawItem 事件,IDE 会自动生成事件的代码框架。不得不说,LCL 已经为开发者考虑了相当多的可能性,包括自绘的可能性,OnDrawItem 恰到好处的给出了自绘的时机,为开发者提供了巨大的方便。

添加一段代码来完成自绘,这段代码看上去比较复杂,但是很容易理解:

图4 自绘TListBox

这段代码包含了四次绘制,先将字体设为黑色,背景设为白色,进行一次背景色的填充。第二步再次设置背景色,设置画笔色,绘制圆角矩形,这里要注意的是,为了画出立体效果,用不同的坐标又画了一次。第三步判断是否为当前选中的项,如果是的话,把背景改为深色,字体改为蓝色,再画一次。第四步是绘制文字,在自绘模式下,文字也需要画上去,否则将不会显示文字。

可能你已经发现了,在自绘的过程中,需要指出明确的颜色、坐标等UI元素,这些估计会对很多开发者造成麻烦,这个时候就需要设计师的帮忙,让设计师来告诉你具体该怎么画吧,或者干脆让他们给出一份 UI 设计图。

随后我们需要改一下 GetEmpList 方法,因为显示的方法已经被改了,因此返回的数据也需要改一下,按照自绘时对字符串的要求来:

图5 修改GetEmpList

改完后编译运行程序,即可看到如图2所示的效果,试着点击一下列表,选中项的效果会发生变化,同时也不会影响 OnClick 的执行。


『制作自定义包』

上面的修改已经达到了目标,但是却不具备可复用性,如果下次还需要实现同样效果,就只能复制一遍代码,而复制代码会造成各种问题,使程序结构不清晰,影响维护,特别是当一个程序内有多处复制的代码时,就几乎没法看下去了。因此有必要将这个改动封装成组件。

CodeTyphon 同样提供了制作组件的解决方案,而且非常的简单易用。当然在此之前,我们有必要将对 TListBox 的改动剥离出来,使它成为一个独立的单元,而不是与 TForm 纠缠在一起。

通过选择主菜单内 Package | New Package 可以新建一个包,此处将包命名为 demo_list。

图6 新建包

可以看到,IDE 生成了一个空的包,接下去向其中添加一个新的 Pascal unit,并命名为 cmpdemolist.pas。单元文件的命名可以随意,需要注意的是不要与现有单元重名,也不要与现有组件重名,不然在引用时会出现问题。同时也要添加对 LCL 的依赖,TListBox 即定义在 LCL 包内。完成后的包结构如图7所示:

图7 包结构

在 cmpdemolist 单元内,完成对 TListBox 的继承,并且加入自绘的特性:

图8 继承TListBox

在此处同样有一个小技巧,通常情况我们无法记住一个回调所具有的参数,例如此处的 OnDrawItem 事件,要记住参数是非常累人的一件事情。此时可以定义好具体方法名,然后将光标移到 InnerDrawItem 处,按 Ctrl+Shift+C,让 IDE 自动生成方法定义与实现框架。随后将之前的自绘代码填入其中:

图9 填入自绘代码

此处需要注意的是,不再需要写 lstEmp,因为当前是在内的内部实现,所有的属性均可以直接调用到,如果觉得这么写不安心,可以把原 lstEmp 改为 Self,表示调用自己的属性与方法。

在编译的过程中,还会遇到找不到 clBkack,找不到 odSelected 等问题,需要补全引用:

图10 补全引用

补全后,即可顺利编译包了。注意编译包的按钮在包视图左上角,位于保存按钮的旁边。现在即可以点击编译按钮右侧的,并选择 Add to Project,从而将这个包加入到现有项目中。此时即可以用非可视化的方法来使用 TDemoListBox 组件,并获得自绘的列表效果。

到目前为止,我们还无法得到与系统组件相同的效果,因为我们的组件还未出现在组件面板中,无法直接通过拖放来使用。要使得组件出现在组件面板上,必须注册组件到 IDE,同时必须重新编译 IDE 以加入组件。


『注册组件到IDE』

要将组件注册到组件面板内,必须添加 bs_ideintf 的依赖,它提供了与 IDE 的交互接口,使组件可以被 IDE 识别。现在新增一个 pascal unit,并勾选 Register Unit 选项,标识出该单元拥有注册的功能。

图11 新增注册单元

随后为注册单元编写相关代码,需要注意的是,注册方法的名称必须为 Register,而不能便用其他名称。IDE 会寻找 Register 方法并执行,从而将组件注册至 IDE。

图12 完成注册单元

现在包的开发已经完成了,终于要走到最后一步,编译包并安装到 IDE,点选 Install 按钮来完成安装:

图13 Install按钮

IDE 会弹出确认窗口,询问是否要重新构建 IDE,此处我们选择 Yes 来继续:

图14 重新构建IDE的提示

重新构建 IDE 是一个比较漫长的过程,可以看到 Message 窗口处不断的打印出编译进度,需要耐心的等待5分钟(取决于磁盘速度)甚至更久,IDE 才会重新编译好。

图15 重新构建IDE

构建完成后,IDE 会自动关闭,此时需要手动再次启动 IDE,到组件面板中找一下,就可以看到 TDemoListBox 了。

图16 在组件面板找到 TDemoListBox


『使用自定义组件』

新建一个 Application 项目,尝试将 TDemoListBox 拖放到界面上,然后在 TForm 的 OnCreate 事件里写上代码:

图17 用于测试TDemoListBox的代码

编译程序并运行它,即可看到我们要的效果:

图18 TDemoListBox运行效果

通过这个实例可以发现, 制作一个自定义的包是较为简便的,而 IDE 提供的相关功能,也可以让我们将包集成到 IDE 内。而唯一不足的,是 CodeTyphon 为了每个自定义包的安装,都必须重新编译 IDE,这对于开发者来说,是一个非常巨大的负担,谁也不想写几行代码就重新编译 IDE。因此就要求开发者有能力来把握组件的品质,在不编译 IDE 的情况下,即明确组件的运行情况,查出其 bug 并予以修正。

在更多的情况下,我们也会封装非可视组件,即一段代码,非可视组件继承自 TComponent,而拖放非可视组件也就相当于拖放了一段代码,其封装作用也不言而喻。




样例代码下载:

发表评论:

Powered By Z-BlogPHP 1.5.1 Zero

Copyright Rarnu 2017. All Rights Reserved.