Data-Browse型Data-Aware控件的制作
在MIS系统中,使用得最常见的当属数据感知控件了。学习如何编写自已的组件,一条很重要的原则就是从自己熟悉的 组件入手,派生出新的合乎自己要求的控件。在数据感知控件中,Data-Browse型是非常简单而又实用的。所以下面 我们就讲解一个一个自定义的TSunDBText(功能等同于TDBText)的编写:
TSunDBText = class(TCustomLabel) {...} end;
因为DBText仅起着显示数据的作用,即是个具有数据感知功能的标签,又根据Delphi的习惯,从Custom系列控件派生, 所以我们选择了TCustomLabel。
如何具有数据感知功能,其实大部分的书上都没有讲得很明白,包括Delphi Help。大致上有这么几点,我们慢慢叙述: 一:选择一个能数据感知的DataLink对象,通常我们选用TFieldDataLink,表示仅与一个数据库字段关联 二:组件必须提供DataSource和DataField两个设计时可读写属性 三:组件必须处理FDataLink的OnDataChange事件,以反映数据字段的变化 四:必须提供Notification重载方法,以便当关联的TDataSource组件在设计期或者运行期删除时,能得到通知,并且 反映出这种改变 五:习惯上,我们还要处理CM_GETDATALINK消息,以符合VCL内部通信的要求 六:为了组件的灵活性,建议提供一个Field属性,以便可以利用TField的方法来增强编程的适用性
下面我们就来一一讲解: private FDataLink:TFieldDataLink; constructor Create(AOwner:TComponent);override; begin inherited; FDataLink := TFieldDataLink.Create; {创建一个TFieldDataLink的对象} FDataLink.OnDataChange := DataChange; { 将TFieldDataLink对象的OnDataChange事件处理交给TSunDBText的DataChange来处理 这样就要以感知数据库字段的变化,并且进行自己想要的处理 } end;
destructor Destroy;override; begin { 这里很简单,仅仅是回收资源而已 } FDataLink.Free; FDataLink := nil; inherited; end;
从上面我们已经看到,数据感知的关键就在于DataChange事件,大致上我们可以知道,是需要将该字段的显示值赋予 本标签组件的Caption属性即可,所以下面的代码便是做这部分工作的。 (注意,之所以要用GetFieldText来完成赋值工作,是出于多方面的考虑,包括设计期和运行期,及异常情况) procedure TSunDBText.DataChange(Sender: TObject); begin Caption := GetFieldText; {read only displaytext when make an data browing component} end;
function TSunDBText.GetFieldText: String; begin { 正常情况下,只需要取得FDataLink所代表的Field的DisplayText即可,如果你开发的不是Data-Browse控件,请用其他 Field属性 } if(FDataLink <> nil) then Result := FDataLink.Field.DisplayText else if(csDesigning in ComponentState) then Result := Name else Result := ''''''''; { 如果是处在设计期,则标签中显示的是组件的名称,如果是运行期,则标签为空;当然,这只是习惯而已,但对于使用Delphi IDE的人来说, 几乎就是规则。 } end;
如果没有DataSource和DataField这两个属性,那么控件几乎就没法使用了。这也是重要步骤。
property DataSource:TDataSource read GetDataSource write SetDataSource; property DataField:String read GetDataField write SetDataField; 这些方法十分简单,只要存取TFieldDataLink之DataSource和FieldName属性则可。 function TSunDBText.GetDataSource: TDataSource; begin Result := FDataLink.DataSource; {仅需简单地返回TFieldDataLink之DataSource属性 从这就可以看出,DataSource属性的写方法也是对FDataLink赋值} end;
procedure TSunDBText.SetDataSource(Value: TDataSource); begin FDataLink.DataSource := Value; {如上所云,对DataSource属性赋值}
if(Value <> nil) then Value.FreeNotification(self); { 这里很重要,TComponent提供了一个FreeNotification(AComponent:TComponent)方法,这样,当Value释放时,就会自动调用AComponent的Notification 方法,我们就可以调整对应的Data-Browse控件,以反映这种变化。如TSunDBText对应的DataSource组件删除掉,则应该反映在标签上 } end;
function TSunDBText.GetDataField: String; begin Result := FDataLink.FieldName; {获得TFieldDataLink之FieldName属性,也就知道了连接的是哪一个数据库字段名称} end;
procedure TSunDBText.SetDataField(const Value: String); begin FDataLink.FieldName := Value; {这应该不用解释了} end;
接上面的,我们说过Notification的由来,下面就进行相关的处理: procedure TSunDBText.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if(Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil; end;
当关联组件被删除时,而且被删除的正好是本身关联的DataSource组件,就应该设置其DataSource属性为空
function TSunDBText.GetField: TField; begin Result := FDataLink.Field; end;
最后,数据感知控件还要响应CM_GETDATALINK消息。通常处理是将TDataLink作为Message的Result域返回 procedure CMGetDataLink(var Message:TMessage);message CM_GETDATALINK;
procedure CMGetDataLink(var Message:TMessage); begin Message.Result := Integer(FDataLink); end; 到此,基本上组件的功能就已齐备了,然而,有一点许多组件编写者都没有注意到,即Action的应用。如果自定义组件能融入VCL的Action机制, 必然可以使自定义控件的功能更强大,更为一些高级使用者喜欢。
下一次,我们就来讲一讲Action之来龙去脉。
没有相关教程
|