分享
 
 
 

Delphi程序设计之--惯用法

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Delphi --技巧探索:

{ No. 1 }

创建模式窗体的句子:

class procedure TMyForm.RunForm(AObj1, AObj2: TObject);

var

vForm: TMyForm;

begin

vForm := TMyForm.Create(Application);

with vForm do

Try

InitForm(AObj1, AObj2);

ShowModal;

Finally

Free;

end;

end;

//*说明:

通过class声明的函数,类似与VC中的静态函数;使用语句:TMyForm.RunForm(vObj1, vObj2);

其他具体的,参考:Delphi 帮助中的,class 类说明。

强调这个惯用法,就是为了:

1、如果此窗体在多处被使用,那么可以保证统一都调用此段代码;

2、如果功能上有所修改,比如:根据ShowModal的返回值不同进行处理,那么只修改此函数就行了。

3、程序封装性好,易于维护和工作交接。*//

{ No. 2 }//Tag 的使用

窗体工具栏按钮事件的响应

procedure TMyForm.RunOperate(ATag: Integer);

begin

Case ATag of

1: MyButton.Color := clRed;

2: MyButton.Color := clGreen;

3: MyButton.Color := clBlack;

end;

end;

procedure TMyForm.ToolBtnClick(Sender: TObject);

begin

RunOperate(TControl(Sender).Tag);

end;

如果你在某下拉菜单中,也需要执行类似功能则

procedure TMyForm.MenuItemClick(Sender: TObject);

begin

RunOperate(TMenuItem(Sender).Tag);

end;

//*说明:

1、结构清晰

2、相关的信息集中,比较容易查错、修改和维护

3、提高程序的适应、扩展能力;比如现在要求不在工具栏按钮中实现,而要求在不同按钮中实现,则修改容易。

建议:每个分类后面只跟一行或不多的几行代码,如果代码比较多,使用过程函数替代。

比较有意思的是,我经常如下写:

Case btnMyButton.Visible of

{ 显示 } True: ...

{不显示} False: ...

end; *//

{ No. 3 }//事件指针做参数

//对于列表等的读取使用事件指针的方式

type

TDataSetEvent = procedure (DataSet: TDataSet; AIndex, ACount: Integer) of Object;

//从 TADOQuery派生而来的类

procedure TMyADOQuery.EnumRecord(AWhereStr: String; APro: TDataSetEvent);

begin

Close;

SQL.Clear;

SQL.Add('Select * From Table1');

if AWhereStr <> '' then

SQL.Add('Where ' + AWhereStr);

Open;

While Not Eof do

begin

if Assigned(APro) then APro(Self, RecNo, RecordCount);

Next;

end;

Close;

end;

//*说明:

此方法来自与Window中,枚举当前所有子窗体的API函数,EnumChildWindow

1、原则:尽量将数据读取与数据显示、数据处理等分离;如:MVC等都是此目的。

2、程序扩展性增强,如果您原来希望在列表中显示或处理某列信息,后来改为用ComboBox,则在修改程序时,不在阅读数据读取部分,只需要修改信息显示等即可。又比如,现在要求您在读取记录时,用进度条显示读取进度等。

*//

{ No. 4 }//常量数组

{ 在 No.2 中,实现了如下的内容

procedure TMyForm.RunOperate(ATag: Integer);

begin

Case ATag of

1: MyButton.Color := clRed;

2: MyButton.Color := clGreen;

3: MyButton.Color := clBlack;

end;

end;

}

//那么用数组方式实现,则就比较理想了

procedure TMyForm.RunOperate(ATag: Integer);

const

MyButtonColorMax := 3;

MyButtonColor: array [1..MyButtonColorMax] of TColor = (clRed, clGreen, clBlack);

begin

Case ATag of

1..MyButtonColorMax: MyButton.Color := MyButtonColor[ATag];

101:....

end;

end;

//*说明:

对于数组方式使用,只要注意数组的上限或下限使用常量来实现,然后在以后使用中都尽量使用此常量进行数组循环读取就行了。

*//

{ No. 5 }消息机制 减少类公共函数

//如何让一个窗体中,尽量减少公共函数的定义;

{ 比如:要实现一个当前窗体控件的属性列表窗体,当需要刷新属性窗体;改变某属性值;添加新的属性等;会有很多需要交互的信息。如果我们使用类公共函数,则需要定义很多的公共函数。同时,如果需要进行窗体类型转换,转换为目标窗体类型才可以使用公共函数。所以,会遇到两个单元需要互相包含的情况 }

//解决方案:

TfrmMyForm = class(TForm)

FfrmProperty: TForm;

end;

...

FfrmProperty := TfrmProperty.MyCreate(Application, Self);

...

//当需要刷新属性窗体时

FfrmProperty.Perform(WD_REFRESHPROPERTYLIST, 0, 0);

TfrmProperty = class(TForm)

private

FMyForm: TForm;

procedure WDREFRESHPROPERTYLIST(var Message: TMessage); message WD_REFRESHPROPERTYLIST;

public

constructor MyCreate(Owner: TComponent; AForm: TForm);

end;

constructor TfrmProperty.MyCreate(Owner: TComponent; AForm: TForm);

begin

inherited Create(Owner);

FMyForm := AForm;

end;

//* 对于使用消息的方式,可以减少窗体公共函数的定义。同时,提高程序的可扩充性。如果,使用他的窗体替代时,则可以比较轻松的转换,因为如果最多也就是您的窗体,对当前的消息没有进行处理而已 *)//

{ No. 6 }使用注册列表管理可能扩充的模块

//项目:要求你对一个数据集支持多种输出显示方式

...例子,以后给出

//* 说明:

1、“多种输出方式”,说明输出方式在今后的应用中可能会经常扩充,因此要在程序设计时考虑到输出方式的易扩充性。

2、参考VCL中,控件注册(RegisterComponents)的机制,可以发现VCL中大量的使用到了注册机制;其中比较经典的就是控件属性编辑器的注册了。

*//

{ No. 7 }使用预定义控制程序版本

//如果您做的是一个二次开发平台的程序,则必须涉及到产品版本控制和项目版本控制问题

//通常使用预定义的方式控制

//语句比较简单了就是:

{$DEFINE JOYYUAN97}

{$IFDEF JOYYUAN97} {ELSE} {ENDIF}

{$UNDEF JOYYUAN97}

*说明:

1、将预定义划分在多个单独的文件中。

2、在每个单元的最前头但在Unit 后,使用{$I ...} 将文件包含(Include)进当前单元

3、根据预定义情况控制当前单元所能包含的单元文件

4、尽量单独划分一个针对项目的预定义文件在包含所有预定义文件后,包含此文件,则在此文件中,可以针对项目的需要,将取消部分预定义{$UNDEF JOYYUAN97}

*//

{ No. 8 } 使用函数指针,减少单元项目包含

//我经常的认为减少单元的包含,是做公共单元的第一步,所以在如何尽量减少单元包含

//也就是如何减少程序单元的耦合性上,应多下工夫。

{ 情景描述:

TMyFormManager: 窗体管理类

TMyForm:数据窗体基础类

TMyFormAccess:窗体信息保存和读取类。将窗体信息保存到数据库或其他什么类型的结构中

分析:

1、窗体基础类(TMyForm) 和 窗体管理类(TMyFormManager)需要在一个单元 uManagers中实现。

2、窗体具体实现类(TMyImageForm)单元 fMyImange 需要包含单元uManagers,进行窗体继承,和窗体管理。

3、窗体数据读取类(TMyFormAccess)单元 uMyAccess 需要包含单元uManagers和单元fMyImange

问题:

如果我希望实现窗体保存,那么应该在窗体的某个按钮事件中实现。则涉及到窗体单元需要包含窗体数据访问类单元,而如果放在窗体基础类中,则单元uManager又必须包含单元uMyAccess。

当数据访问,即数据存储格式会根据要求而改变并要求可扩充时,则单元包含必定是一个隐患。

解决办法:使用函数指针变量。

1、在单元uManagers中定义一个,保存数据信息的函数指针变量。

2、在应用程序初始化的时候给这个函数指针变量赋值。

3、在需要保存窗体信息时,判断如果指针不为空,则执行函数保存窗体信息。

{ No. 9 } 常量,认识常量,使用常量

有很多书都都介绍了常量定义的重要性,我也会经常想到,但是看看VCL源码才知道,自己忽略了,别人对常量的使用情况。

1、我们经常使用的消息的定义就是:声明一个常量,然后在适当的时候使用之。

通常定义和使用:

const

WD_MyMessage = WM_User + 101;

type

TMyForm = class(TForm)

...

procedure WDMyMessage(var message: TMessage); message WD_MyMessage; {响应消息位置}

end;

但是,如果您将{响应消息位置}语句改写为:

procedure WDMyMessage(var message: TMessage); message WM_User + 101;

同样,编译可以成功,使用也正常。所以,常量定义在Window系统处理和接口中应用非常普遍。

2、在Delphi中,我们定义了颜色变量,clRed, clGreen等,也都是定义的常量,便于以后的使用。通过这个观察我发现,常量的定义应该是在项目中,可部分复用的,所以,可以定义一个标准常量单元,以便在个项目中,复用定义的常量。

{ No. 10 }一个Delphi中,常用到的数组

对TIdentMapEntryd类型的数组定义和使用,Delphi中,有比较完善的实现。

TIdentMapEntry = record

Value: Integer;

Name: String;

end;

1、数组定义:array[0..ArrMax] of TIdentMapEntry

可参考:Controls单元中:

Cursors: array[0..21] of TIdentMapEntry = (

...

);

2、两个互相求值得函数: IntToIdent(由Value求Name)和 IdentToInt(由Name求Value);

具体应用可以参考:IdentToCursor 和 CursorToIdent。

3、应用:a、直接应用此树组定义方式和数组操纵函数;b、学习函数中,对数组访问和操纵的方式。c、学习标准的信息访问函数定义: function IntToIdent(Int: Longint; var Ident: string; const Map: array of TIdentMapEntry): Boolean; 具体返回的信息由参数方式返回回来,至于访问是否有效,则通过函数的布尔返回值加以判断。

{ No. 11 } 由特例到普通的发现

我通过对 Cursors 的定义和操作函数的跟踪发现:

1、如 { No. 10 }中介绍的,将Cursors的定义和一般操作通用化。

2、提供 Int 和 Ident互转化的函数。

3、提供数组列表信息循读取的函数: GetCursorValues;其中,使用了 { No. 3 } 中介绍的“事件指针 做参数”读取列表信息的方法。

{ No. 6 } 的补充:

例子:

procedure RegisterComponents(const Page: string;

ComponentClasses: array of TComponentClass);

begin

if Assigned(RegisterComponentsProc) then

RegisterComponentsProc(Page, ComponentClasses)

else

raise EComponentError.CreateRes(@SRegisterError);

end;

解读:

1、使用注册的方式,记录可使用的控件的类型等。

3、对于 RegisterComponentsProc 使用了{ No. 8 } 中“使用函数指针,减少单元项目包含”的方法,便于将来程序的扩充,版本的升级等。

{ No. 11 }只定义一个公共函数

//项目描述:现在要实现一个CAD画图或Visio系统,要求有好的扩展性和易维护性;

//并且要求耦合性低,便于,将来系统的部分或扩展后的系统封装后,直接在今后的项目中使用

设计:

1、设计一个图形对象抽象类,在此类中,定义一个抽象函数 CadPerform,函数的参数参照function TControl.Perform(Msg: Cardinal; WParam, LParam: Longint): Longint;

2、在图形管理类中,实现一个图形对象列表的管理,列表中保存的是抽象对象的指针。

3、对于要对具体类对象进行操纵控制时,只需通过条用CanPerform函数,然后根据当前操作的类别传入 Msg, 并传入相应的参数信息。

实现: TCad 为由抽象类继承下来的第一层控件类

function TCad.CadPerform(Msg: Cardinal; WParam, LParam: Longint): Longint;

begin

Case Msg of

My_Message1: Result := MyMessage1(WParam, LParam);

My_Message2: Result := MyMessage2(WParam, LParam);

end;

end;

对于,TPoint继承自 TCad, CadPerform函数实现如下。

function TPoint.CadPerform(Msg: Cardinal; WParam, LParam: Longint): Longint;

begin

Case Msg of

My_Message1: Result := MyMessage1(WParam, LParam); //屏蔽了TCad中此操作类型的处理

My_Message3: Result := MyMessage3(WParam, LParam);

else Result := inherited CadPerform(Msg, WParam, LParam);

end;

end;

*说明:

因为,我们对图形对象的操作会非常频繁,所以我们通过定义一个公共开放的接口函数来实现,类的高封装性和程序的易维护性、好扩展等性能。

*//

{ No. 12 }

以下是我编程时的要求:(部分信息没有语言限制)

//以下的解决方案,几乎都可以在上面的方法中,找到

1、减少程序的复杂度。a、减少函数个数,使用Case、Tag方式,学习实现Perform定义方式;b、减少单元嵌套关系,使用消息传递方式,减少窗体单元的互相包含。

2、减少

{ No. 13 }使用广播,实现管理类对管理列表对象的通知

//对于{ No. 12 } 项目描述中,当画图的窗体控件属性或状态改变时,经常会需要通知所有的图形对象,进行相应的改变。

//则如果只定义一个广播函数,就可以实现父子通知的话,也会提高程序的可重用性、扩展性、易维护性等,使类结构清晰。

//比如:1、在Visio和MapInfo中,如果当前窗体的比例尺(缩放比例)改变时,需要用新的比例尺重画当前所有的显示图形对象。2、当当前窗体默认窗体字体改变后,对于默认使用窗体字体显示文字信息的图形对象,他们的文字字体也应该相应的改变。

//解决方案,参考TWinControl中,属性或状态改变时,通知所有子Controls的处理机制:

procedure TWinControl.NotifyControls(Msg: Word);

var

Message: TMessage;

begin

Message.Msg := Msg;

Message.WParam := 0;

Message.LParam := 0;

Message.Result := 0;

Broadcast(Message);//广播当前的变更消息

end;

其中:

procedure TWinControl.Broadcast(var Message);

var

I: Integer;

begin

for I := 0 to ControlCount - 1 do

begin

Controls[I].WindowProc(TMessage(Message));

//改为:with TMessage(Message) do Cads[I].CadPerform(msg, WParam, LParam);

if TMessage(Message).Result <> 0 then Exit;

end;

end;

但是,我们处理图形对象时,可能会直接调用 Cads 的CanPerform公共函数即可

{ No. 14 }需要时,动态创建你的对象

比如:http://www.delphibbs.com/keylife/iblog_show.asp?xid=824 中的

//*******方案二 当需要的时候在创建属性窗体

uses

...

fProperty;

type

TfrmMyMap = class

...

procedure OnfrmMyMapDestroy(Sender: TObject);

procedure OnMapGeoSelected(AGeo: TGeometry);

private

FfrmProperty: TfrmProperty;

procedure ShowPropertyForm(aVisible: Boolean);

public

end;

procedure TfrmMyMap.ShowPropertyForm(aVisible: Boolean);

begin

if Not Assigned(FfrmProperty) then FfrmProperty := TfrmProperty.Create(Application);

FfrmProperty.Visible := aVisible;

end;

procedure TfrmMyMap.OnfrmMyMapDestroy(Sender: TObject);

begin

if Assigned(FfrmProperty) then FfrmProperty.Free;

end;

procedure TfrmMyMap.OnMapGeoSelected(AGeo: TGeometry);

begin

if Assigned(FfrmProperty) then FfrmProperty.MyRefresh(AGeo);

end;

这里说明了:

1、需要时,动态创建你的对象 FfrmProperty

2、当前对象释放时,判断你的对象的合法性,然后释放动态创建的对象。

{ No. 15 }创建接口还是创建结构

//项目描述:我开发一个表格控件时,如果我将单元格设置为一个Com,则如果表格现实的信息过多的话,则装载速度无法保证,甚至于有死机的可能。我之所以用Com是为了将来每个单元格的处理和信息都可以在控件外扩展。

我的解决办法是:对于每个从Cell派生来的控件创建一个实例,通过动态创建若干个结构对象Record来记录个单元格的信息,如果需要对单元格进行操作,则将结构对象指针赋值给Cell组件,测试结果很令人满意。

所以,如果需要使用某个Com大量实例的话,尽量管理和维护一个实例,而对于其中的数据可以实行动态创建管理,速度上会有很好的效果。

另外,尽量声明一个 pMyInterface = ^IMyInterface 借口指针,参数传递或使用时,直接使用接口指针,这样可以减少调用计数函数_AddInft等,如果操作平凡也可以提高速度的。

注:此文作者笔名:JoyYuan97。(自己很菜,写不出来什么,找到好的东西希望大家一起分享,也感谢作者给我带来的经验和技巧)

希望看过的人留下意见,下面为作者的话:

“另外,最好请将您转贴位置的连接给我一份。我向定期看看别人的建议。谢谢!

有好经验大家分享!”

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有