delphidelphidelphidelphi组件开发详解DelphiDelphiDelphiDelphi除了支持使用可视化部件所见即所得地建立应用程序外,还支持为开发应用而设计自己的部件。在本章中将阐述如何为DelphiDelphiDelphiDelphi应用程序编写部件。这一章将达到两个目的:●●●●教你如何自定义部件●●●●使你的部件成为DelphiDelphiDelphiDelphi环境的有机组合部分19.119.119.119.1DelphiDelphiDelphiDelphi部件原理19.1.119.1.119.1.119.1.1什么是部件部件是DelphiDelphiDelphiDelphi应用程序的程序构件。尽管大多数部件代表用户界面的可见元素,但部件也可以是程序中的不可见元素,如数据库部件。为弄清什么是部件可以从三个方面来考察它:功能定义、技术定义和经验定义。1.1.1.1.部件的功能定义从最终用户角度,部件是在ComponentComponentComponentComponentPalettePalettePalettePalette上选择的,并在窗体设计窗口和代码窗口中操作的元素。从部件编写者角度,部件是代码中的对象。在编写部件之前,你应用相当熟悉已有的DelphiDelphiDelphiDelphi部件,这样才能使你的部件适合用户的需要。编写部件的目标之一是使部件尽可能的类似其它部件。2.2.2.2.部件的技术定义从最简单的角度看,部件是任何从TComponentTComponentTComponentTComponent继承的对象。TComponentTComponentTComponentTComponent定义了所有部件必须要的、最基本的行为。例如,出现在ComponentComponentComponentComponentPalettePalettePalettePalette上和在窗体设计窗口中编辑的功能。但是TComponentTComponentTComponentTComponent并不知如何处理你的部件的具体功能,因此,你必须自己描述它。3.3.3.3.部件编写者自己的定义。在实际编程中,部件是能插入DelphiDelphiDelphiDelphi开发环境的任何元素。它可能具有程序的各种复杂性。简而言之,只要能融入部件框架,部件就是你用代码编写的一切。部件定义只是接口描述,本章将详细阐述部件框架,说明部件的有限性,正如说明编程的有限性。本章不准备教你用所给语言编写每一种部件,只能告诉编定代码的方法和怎样使部件融入DelphDelphDelphDelphiiii环境。19.1.219.1.219.1.219.1.2编写部件的不同之处在DelphiDelphiDelphiDelphi环境中建立部件和在应用程序中使用部件有三个重要差别:●●●●编写部件的过程是非可视化的●●●●编写部件需要更深入的关于对象的知识●●●●编写部件需要遵循更多的规则1.1.1.1.编写部件是非可视化的编写部件与建立DelphiDelphiDelphiDelphi应用最明显的区别是部件编写完全以代码的形式进行,即非可视化的。因为DelphiDelphiDelphiDelphi应用的可视化设计需要已完成的部件,而建立这些部件就需要用ObjectObjectObjectObjectPascalPascalPascalPascal代码编写。虽然你无法使用可视化工具来建立部件,但你能运用DelphiDelphiDelphiDelphi开发环境的所有编程特性如代码编辑器、集成化调试和对象浏览。2.2.2.2.编写部件需要更深的有关对象的知识除了非可视化编程之外,建立部件和使用它们的最大区别是:当建立新部件时,需要从已存部件中继承产生一个新对象类型,并增加新的属性和方法。另一方面,部件使用者,在建立DelphiDelphiDelphiDelphi应用时,只是使用已有部件。在设计阶段通过改变部件属性和描述响应事件的方法来定制它们的行为。当继承产生一个新对象时,你有权访问祖先对象中对最终用户不可见的部分。这些部分被称为protectedprotectedprotectedprotected界面的。在很大部分的实现上,后代对象也需要调用他们的祖先对象的方法,因此,编写部件者应相当熟悉面向对象编程特性。3.3.3.3.编写部件要遵循更多的规则编写部件过程比可视化应用生成采用更传统的编程方法,与使用已有部件相比,有更多的规则要遵循。在开始编写自己的部件之前,最重要的事莫过于熟练应用DelphiDelphiDelphiDelphi自带的部件,以得到对命名规则以及部件用户所期望功能等的直观认识。部件用户期望部件做到的最重要的事情莫过于他们在任何时候能对部件做任何事。编写满足这些期望的部件并不难,只要预先想到和遵循规则。19.1.319.1.319.1.319.1.3建立部件过程概略简而言之,建立自定义部件的过程包含下列几步:●●●●建立包含新部件的库单元●●●●从已有部件类型中继承得到新的部件类型●●●●增加属性、方法和事件●●●●用DelphiDelphiDelphiDelphi注册部件●●●●为部件的属性方法和事件建立HelpHelpHelpHelp文件如果完成这些工作,完整的部件包含下列4444个文件●●●●编译的库单元((((.DCU.DCU.DCU.DCU文件))))●●●●选择板位图(.DCR(.DCR(.DCR(.DCR文件))))●●●●HelpHelpHelpHelp文件(.HLP(.HLP(.HLP(.HLP文件))))●●●●Help-keywordHelp-keywordHelp-keywordHelp-keyword文件(.KWF(.KWF(.KWF(.KWF文件))))19.219.219.219.2DelphiDelphiDelphiDelphi部件编程方法19.2.119.2.119.2.119.2.1DelphiDelphiDelphiDelphi部件编程概述19.2.1.119.2.1.119.2.1.119.2.1.1DelphiDelphiDelphiDelphi可视部件类库DelphiDelphiDelphiDelphi的部件都是可视部件类库(VCLVCLVCLVCL)的对象继承树的一部分,下面列出组成VCVCVCVCLLLL的对象的关系。TComponenTComponenTComponenTComponentttt是VCVCVCVCLLLL中每一个部件的共同祖先。TComponenTComponenTComponenTComponentttt提供了DelphDelphDelphDelphiiii部件正常工作的最基本的属性和事件。库中的各条分支提供了其它的更专一的功能。当建立部件时,通过从对象树中已有的对象继承获得新对象,并将其加入VCLVCLVCLVCL中。19.2.1.219.2.1.219.2.1.219.2.1.2建立部件的起点部件是你在设计时想操作的任意程序元素。建立新部件意味着从已有类型中继承得到新的部件对象类。建立新部件的主要途径如下:●●●●修改已有的控制●●●●建立原始控制●●●●建立图形控制●●●●建立WindowsWindowsWindowsWindows控制的子类●●●●建立非可视部件下表列出了不同建立途径的起始类表19.119.119.119.1定义部件的起始点━━━━━━━━━━━━━━━━━━━━━━━━━━━━━途径起始类────────────────────────────────────────────────────────────────────────────────────────────────────────────────────修改已有部件任何已有部件,如TButtonTButtonTButtonTButton、TListBoxTListBoxTListBoxTListBox或抽象部件对象如TCustomListBoxTCustomListBoxTCustomListBoxTCustomListBox建立原始控制TCustomControlTCustomControlTCustomControlTCustomControl建立图形控制TGraphicControlTGraphicControlTGraphicControlTGraphicControl建立窗口控制的子类TWinControlTWinControlTWinControlTWinControl建立非可视部件TComponentTComponentTComponentTComponent━━━━━━━━━━━━━━━━━━━━━━━━━━━━━也可以继承非部件的其它对象,但无法在窗体设计窗口中操作它们。DelphiDelphiDelphiDelphi包括许多这种对象,如TINIFileTINIFileTINIFileTINIFile、TFontTFontTFontTFont等。1.1.1.1.修改已有控制建立部件的最简单的方法是继承一个已有的、可用的部件并定制它。可以从DelphiDelphiDelphiDelphi提供的任何部件中继承。例如,可以改变标准控制的缺省属性值,如TButtonTButtonTButtonTButton。有些控制,如ListboxListboxListboxListbox和GridGridGridGrid等有许多相同变量,在这种情况下,DelphiDelphiDelphiDelphi提供了抽象控制类型,从该类型出发可定制出许多的类型。例如,你也许想建立TListBoxTListBoxTListBoxTListBox的特殊类型,这种部件没有标准TListBoxTListBoxTListBoxTListBox的某些属性,你不能将属性从一个祖先类型中移去,因此你需要从比TListBoxTListBoxTListBoxTListBox更高层次的部件继承。例如TCustomListBoxTCustomListBoxTCustomListBoxTCustomListBox,该部件实现了TCustomListBoxTCustomListBoxTCustomListBoxTCustomListBox的所有属性但没有公布(Publishing)(Publishing)(Publishing)(Publishing)它们。当从一个诸如TCustomListBoTCustomListBoTCustomListBoTCustomListBoxxxx的抽象类中继承时,你公布那些你想使之可获得的属性而让其它的保护起来(protected)(protected)(protected)(protected)。2.2.2.2.建立原始控制标准控制是在运行时可见的。这些标准控制都从TWinControlTWinControlTWinControlTWinControl,继承来的,当你建立原始控制时,你使用TCustomControlTCustomControlTCustomControlTCustomControl作为起始点。标准控制的关键特征是它具有窗口句柄,句柄保存在属性HandleHandleHandleHandle中,这种控制:●●●●能接受输入焦点●●●●能将句柄传送给WindowsWindowsWindowsWindowsAPIAPIAPIAPI函数如果控制不需要接受输入焦点,你可把它做成图形控制,这可能节省系统资源。3.3.3.3.建立图形控制图形控制非常类似定制的控制,但它们没有窗口句柄,因此不占有系统资源。对图形控制最大的限制是它们不能接收输入焦点。你需要从TGraphicControlTGraphicControlTGraphicControlTGraphicControl继承,它提供了作图的CanvasCanvasCanvasCanvas和能处理