在使用Delphi可视化设计时,有时觉得某个元件缺少点自己需要的功能或者属性,或者需要的功能或者属性是protected,没法直接得到。比如TPanel,是个容器类组件,其功能是用来放置其它窗口组件和图形组件,但是,如果想在它的界面上画点什么就不那么方便了,既没有OnPaint事件,也不能直接获取其Canvas(该属性是protected)。
碰到这类问题,我们采用的策略一般有2个:
- 重新写一个该组件的派生类,注册到IDE的组件面板中,或者动态建立这个类,插入到窗口中,对于类似TPanel的组件,由于可能要在其上放置其它组件,只能选择注册,但是由于我们需要的新增功能不多,或者只是想得到组件的protected方法或属性,注册一个新组件似乎很“冤”,对较大项目的维护也很不利。
- 采用替换法,如TPanel,写成TMyPanel = class(TPanle),然后通过强制转换后取得其protected方法和属性,或者使用新增的属性和方法。不过这样也很麻烦,有时也会有些问题,比如上面所说的要在TPanle上画点什么,只能在TForm.OnPaint事件进行,下面是替换法的例子,在Panel1的界面上画一个红色矩形:
unitUnit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,ExtCtrls,StdCtrls;
type
TMyPanel=class(TPanel);
TForm1=class(TForm)
Panel1:TPanel;
Button1:TButton;
procedureFormPaint(Sender:TObject);
procedureButton1Click(Sender:TObject);
private
{Privatedeclarations}
public
{Publicdeclarations}
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
procedureTForm1.FormPaint(Sender:TObject);
//var
//Canvas:TControlCanvas;
begin
{
Canvas:=TControlCanvas.Create;
Canvas.Control:=Panel1;
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(10,10,100,100);
Canvas.Free;
}
withTMyPanel(Panel1)do
begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(10,10,100,100);
end;
end;
procedureTForm1.Button1Click(Sender:TObject);
begin
Invalidate;
end;
end.
运行上面例子,由于Form在开始显示时,其OnPaint在TPanel.Paint方法前被调用,所以窗口开始显示时,我们得不到应有的效果,必须借助一次刷新才行,而且这个刷新还不知道在哪个事件中进行才合适,笔者在Form的OnCreate、OnShow、OnActive以及OnResize事件中都试过,都不起作用(使用FormOnPaint中被注释的代码也是一样),笔者愚钝,只好借助按钮Click事件刷新一次。
采用本文介绍的组件“偷梁换柱”法,可以方便的解决这类问题。请看和上面例子同样功能的代码:
unitUnit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,ExtCtrls;
type
TPanel=class(ExtCtrls.TPanel)
public
procedurePaint;override;
end;
TForm1=class(TForm)
Panel1:TPanel;
private
{Privatedeclarations}
public
{Publicdeclarations}
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
{TPanel}
procedureTPanel.Paint;
begin
inherited;
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(10,10,100,100);
end;
end.
其实,该例子也是一种替换法,和前面所说的替换法是一样的原理,只不过前面介绍的替换法是间接的,要借助外部事件进行强制转换;而该例子是借助编译器自动完成的。在设计期,使用的是原组件,但是编译的时候,使用的却是同名新组件。编译器遇到同样名称的类型,总是“就近”选取,而本例子中新的TPanel就在本单元,所以编译器选择了它,成了名副其实的“偷梁换柱”。如果新的TPanel在另外的单元,只要在uses中该单元排列在原TPanel所在单元的后面就行了,假如新TPanle所在单元名为MyPanel.pas,写成uses ExtCtrls, MyPanel;就行了。下面举一个复杂点的例子。
去年在论坛上,有人要求实现TEdit只能接受汉字和“,”,并且屏蔽粘贴功能,我当时给的方案如下:
unitUnit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls;
type
TForm1=class(TForm)
Edit1:TEdit;
procedureFormCreate(Sender:TObject);
private
{Privatedeclarations}
LowCh:Boolean;
C:Word;
OldWndProc:TWndMethod;
procedureWndProc(varMessage:TMessage);
public
{Publicdeclarations}
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
procedureTForm1.WndProc(varMessage:TMessage);
var
ch:Word;
begin
ifMessage.Msg=WM_PASTEthenExit;
ifMessage.Msg=WM_CHARthen
begin
ifMessage.LParam=-1then
Message.LParam:=0
elseif(Message.WParamand$80)<>0then
begin
ifnotLowChthen
begin
if((Message.WParamand$7f)xor$20)<$10then
begin
C:=Message.WParam;
LowCh:=True;
Exit;
end;
endelse
begin
LowCh:=False;
ch:=(Message.WParamshl8)orC;
if((chand$7f7f)xor$2020)=$0c03then
PostMessage(Edit1.Handle,WM_CHAR,ch,-1);
Exit;
end;
endelseifMessage.WParam>=32thenexit;
end;
OldWndProc(Message);
end;
procedureTForm1.FormCreate(Sender:TObject);
begin
OldWndProc:=Edit1.WindowProc;
Edit1.WindowProc:=WndProc;
end;
end.
该方案确实能达到了提问者的要求,但是如果有多个TEdit,就很麻烦了:必须在FormCreate反复赋值,还得要用多个变量或者数组保存每个Edit原先的WindowProc,在新的WinProc过程中还得判断是哪个Edit被激活,以便调用它原先的WindowProc等。这给以后的修改和维护带来了极大的隐患。
按照本文介绍的方法,就不存在这个问题,可以写一个新的TEdit放在另一个单元:
unitUnit2;
interface
uses
Windows,Messages,SysUtils,StdCtrls;
type
TEdit=class(StdCtrls.TEdit)
private
LowCh:Boolean;
C:Word;
procedureWMChar(varMessage:TWMChar);messageWM_CHAR;
procedureWMPASTE(varMessage:TMessage);messageWM_PASTE;
end;
implementation
{TEdit}
procedureTEdit.WMChar(varMessage:TWMChar);
var
ch:Word;
begin
ifMessage.KeyData=-1then
Message.KeyData:=0
elseif(Message.CharCodeand$80)<>0then
begin
ifnotLowChthen
begin
if((Message.CharCodeand$7f)xor$20)<$10then
begin
C:=Message.CharCode;
LowCh:=True;
Exit;
end;
endelse
begin
LowCh:=False;
ch:=(Message.CharCodeshl8)orC;
if((chand$7f7f)xor$2020)=$0c03then
PostMessage(Handle,WM_CHAR,ch,-1);
Exit;
end;
endelseifMessage.CharCode>=32thenexit;
inherited;
end;
procedureTEdit.WMPASTE(varMessage:TMessage);
begin
end;
end.
只要正确引用该单元,任何窗口的任何TEdit 对象都有同样的功能,而且利于维护,测试例子就不写了,读者可以自己测试,只要保证uses列表中Unit2在StdCtrls后面就行了。
当然,该方法也有局限,如本例,如果窗口上有多个Edit,只有其中几个需要屏蔽功能,使用该方法就不适合了,不过,也还是有解决办法,如本例,可使用TEdit.Tag进行分组判断,以实现各组不同的需求。如果需要的功能太多,太复杂,还是应该写成新的组件或者使用第三方组件。
如有错误请指正,我的邮件地址:maozefa@hotmail.com
分享到:
相关推荐
《Delphi 组件参考大全》全面、系统地介绍了Delphi组件以及它们的应用,是一本全面、系统的组件参考大全。《Delphi 组件参考大全》通过大量的示例、典型实例帮助读者透彻理解Delphi组件及其应用。全书共分19章。主要...
Delphi是一款强大的面向对象的集成开发环境(IDE),以其高效的代码生成、丰富的组件库和直观的可视化设计闻名。对于想要入门Delphi组件开发的初学者来说,了解并掌握相关知识至关重要。组件是Delphi编程的核心元素...
Delphi组件大全、原书名称[软件工程师的典藏—Delphi组件大全]、作者:明日科技,扫描高清版带书签。 此资源共三个压缩文件,每卷资源分:1分 1、资源名称:Delphi组件大全[扫描高清版带书签_共三卷第一卷],文件:...
### Delphi组件开发教程指南 #### 一、组件开发概述 在Delphi编程环境中,组件是一种高度封装的对象,用于提供特定的功能或行为。通过使用组件,开发者能够快速地构建复杂的应用程序,而无需深入理解底层实现细节...
《Delphi组件参考大全》是一本专为Delphi开发者量身打造的专业参考资料,它涵盖了Delphi编程中的各种组件使用和开发技巧。这本书的配套光盘包含了一系列文档和可能的示例代码,旨在帮助用户深入理解和应用Delphi的...
Delphi是一款强大的Windows应用程序开发工具,它以其直观的可视化组件编程模式和高效的VCL(Visual Component Library)框架闻名。在Delphi中,组件是预先编写好的可重用代码单元,可以方便地通过拖放方式添加到用户...
《Delphi组件开发指南中文版》是一本专为Delphi开发者设计的详尽教程,旨在帮助读者深入理解和掌握在Delphi环境下进行组件开发的核心技术。Delphi是一款强大的面向对象的集成开发环境(IDE),以其高效的编译器和...
本书全面、系统地介绍了Delphi组件以及它们的应用,是一本全面、系统的组件参考大全。 本书通过大量的示例、典型实例帮助读者透彻理解Delphi组件及其应用。全书共分19章。主要包括组件的基础知识和共用的属性、...
Delphi 组件编写指南是 Delphi 编程语言中编写控件的详细指南,对于编写 Delphi 组件的方法进行了详细的阐述,涵盖了组件创建、类库、控件修改、窗口控件、图形控件、子类化 Windows 控件、非可视组件等方面的内容。...
本实例将聚焦于Delphi组件的应用,帮助开发者更好地理解和利用这些组件进行软件开发。 Delphi的组件库,也称为Visual Component Library (VCL),提供了大量的预先编写好的UI控件和非UI功能部件,使得开发者可以快速...
《Delphi组件参考大全》是Delphi开发者们的重要参考资料,其中包含了丰富的组件源码和实践示例,旨在帮助程序员深入理解和应用Delphi的各种组件。这个压缩包中的资源是从03开始编号的,遗憾的是缺少了01和02两部分,...
这个组件安装包的提供,旨在帮助Delphi程序员将Python的强大功能引入到他们的项目中,实现两者之间的无缝交互。 首先,让我们深入了解Python4Delphi的核心功能。它为Delphi提供了Python引擎接口,使得Delphi程序...
书中每一个组件都有相应的实例介绍,通俗易懂,希望对你有所帮助,这是一个htm文件
Delphi是一种强大的面向对象的 Pascal 编程语言,它以其集成开发环境(IDE)和丰富的组件库而闻名。本指南将深入探讨如何在Delphi中编写自己的组件,这对于提升应用程序的功能性和可重用性至关重要。 1. 组件基础 ...
Delphi组件大全涵盖Delphi几乎所有控件组件,值得分享!高清PDF想用什么控件就从目录找,属性,事件解析一应俱全,不可多得的Delphi组件大全,Delphi控件大全!
Delphi组件包安装工具——汉化版DelphiPI是一款专为Delphi开发者设计的实用工具,主要用于简化Delphi组件的安装过程。这个版本基于DelphiPI 0.57进行了优化,增加了仅编译和仅安装的功能,使得用户可以根据实际需求...
Delphi 组件安装有五种情况,分别是只有一个 DCU 文件的组件、只有 PAS 文件或既有 PAS 又有 DCU 文件的组件、有 dpk 文件的组件包、带有 Bpl 文件的组件包、ActiveX 控件的安装。下面将详细介绍每种情况的安装方法...