p> 用delphi开发c/s应用方便而快速,因为它拥有大量易于使用的数据访问和数据感知控件。然而万事总是难以完美,delphi的dbedit控件用于输入日期时间型字段却很不方便,为了改善这一缺点,笔者开发了一个dbdatetime数据感知控件,大大方便了时间和日期的输入。
创建一个构件时,最重要的一步是选择正确的父类,这样可以减少代码的编写。delphi的构件库中已有一个tdatetimepicker构件,可以以下拉日历或利用spinbutton递增、递减的方式方便地输入和改变日期、时间,但它没有数据感知的能力。因此,我们可以以它为父类,派生出一个新的控件,加上能与数据集通信的数据感知功能。
数据感知控件通过datalink对象与datasource进行交互,所以为控件增加数据感知能力需要创建一个tdatalink(或其派生类)对象作为控件的成员,并为控件创建公开的datafield和datasource属性;然后需响应tdatalink对象的ondatachange和onupdatedata事件。下面是控件的主要源代码,并带有相应的注释:
{定义从tdatetimepicker派生的tdbdatetime类。注意,在单元接口的uses中应加入db,dbctrls引用}type
tdbdatetime=class(tdatetimepicker)
private
fdatalink:tfielddatalink;
//tfielddatalink是tdatalink的派生类,处理单个字段与datasource的交互
proceduredatachange(sender:tobject);
//当dataset的记录改变(如浏览记录)时触发ondatachange事件,datachange将作为该事件的事件处理句柄
procedureupdatedata(sender:tobject);
//更新dataset前触发onupdatedata事件,updatedata将作为该事件的事件处理句柄
functiongetdatasource:tdatasource;
proceduresetdatasource(value:tdatasource);
functiongetdatafield:string;
proceduresetdatafield(value:string);
procedurecmexit(varmessage:tcmexit);message cm_exit;//当控件失去焦点时触发cm_exit消息
protected
procedurechange;override;//控件中日期、时间改变时触发onchange事件
procedurenotification(acomponent:tcomponent;
operation:toperation);override;
//当某一控件从form上移走时delphi的ide调用该方法通知其它控件
public
constructorcreate(aowner:tcomponent);override;
destructordestroy;override;
lished
propertydatasource:tdatasourcereadgetdatasource
writesetdatasource;//为控件增加datasource属性,使它能与datasource构件连接
propertydatafield:stringreadgetdatafield
writesetdatafield;
end;//为控件增加datafield属性,
使它指向代表某一字段的tfield对象
procedureregister;//注册构件
implementation
proceduretdbdatetime.cmexit;
begin
try
fdatalink.updaterecord;
//控件失去焦点时更新dataset,这将触发onupdatedata事件
except
setfocus;
raise;
end;
doexit;
end;
constructortdbdatetime.create(aowner:tcomponent);
begin
inheritedcreate(aowner);
//创建datalink对象,挂接ondatachange、
onupdatedata事件处理句柄
fdatalink:=tfielddatalink.create;
fdatalink.ondatachange:=datachange;
fdatalink.onupdatedata:=updatedata;
end;
destructortdbdatetime.destroy;
begin
fdatalink.ondatachange:=nil;
fdatalink.onupdatedata:=nil;
fdatalink.free;
inheriteddestroy;
end;
functiontdbdatetime.getdatasource:tdatasource;
begin
result:=fdatalink.datasource;
end;
proceduretdbdatetime.setdatasource(value:tdatasource);
begin
fdatalink.datasource:=value;
end;
functiontdbdatetime.getdatafield:string;
begin
result:=fdatalink.fieldname;
end;
proceduretdbdatetime.setdatafield(value:string);
begin
fdatalink.fieldname:=value;
end;
proceduretdbdatetime.datachange(sender:tobject);
begin
datetime:=now;
//若控件连了活动的dataset则数据集变动时
控件显示当前记录的相应字段值
iffdatalink.field nilthen
iffdatalink.field.text then
datetime:=fdatalink.field.asdatetime;
end;
proceduretdbdatetime.updatedata(sender:tobject);
begin
fdatalink.field.asdatetime:=datetime;
//用控件中的日期、时间更新相应字段
end;
proceduretdbdatetime.change;
begin
//当用户改变了控件中的内容时将dataset置为编辑状态
fdatalink.modified;
ifnotfdatalink.editingthen
fdatalink.edit;
inheritedchange;
end;
proceduretdbdatetime.notification(acomponent:
tcomponent;operation:toperation);
begin
inheritednotification(acomponent,operation);
//当与控件相连的tdatasource
被删除时将控件的datasource属性置为空
if(operation=opremove)and(fdatalink nil)
and(acomponent=datasource)then
datasource:=nil;
end;
procedureregister;
begin
registercomponents(datacontrols,
[tdbdatetime]);//控件注册后安装于datacontrols页
end;
end.
本控件安装后能以下拉日历和递 增递减方式改变数据库的日期时间型字段,并能以长、短两种格式显示日期,方便实用。控件在delphi3、delphi4中使用安全可靠。