2个创建组件属性的问题(组件高手请进)(300分)

  • 主题发起人 主题发起人 autumn
  • 开始时间 开始时间
A

autumn

Unregistered / Unconfirmed
GUEST, unregistred user!
1.如何在我的组件中建立一个Connection:TADOConnection 的属性?(200分)
我现在是这样作的
Type
TMyComponent=class(TComponent)
private
FConnection:TADOConnection;
published
Connection:TADOConnection read FConnection write FConnection;
end;
但是这样写的话,问题就来了。当我在IDE中指定了Connection为AdoConnection1后,
直接选中adoconnection1,然后按del,删除adoconnection1组件,那么会激发一个异常。
我观察了ADODB.pas单元关于adocommand的描述
procedure TADOCommand.SetConnection(const Value: TADOConnection);
begin
if Connection <> Value then
begin
FConnectionString := '';
if Assigned(FConnection) then
FConnection.UnRegisterClient(Self);
FConnection := Value;
if Assigned(FConnection) then
FConnection.RegisterClient(Self, ConnectionStateChange);
ClearActiveConnection;
end;
end;
它是这样写的,用了Connection.RegisterClient,UnRegisterClient。我也仿写了
上面的代码到我的TMyComponent上,但是还是没有解决问题。

2.如何在组件编写中实现IDE的CreateOrder功能?(100分)
我有个A组件,必须要在B组件之后创建,在IDE中有CreateOrder给我指定,我可以在A组件
的代码中指定吗?
 
1, 以前没有注意,今天看看果然向你说的这样,学习。
 
关注。顶顶。学习。
 
Type
TMyComponent=class(TComponent)
private
FADOCon: TADOConnection;
procedure SetADOCon(const Value: TADOConnection);
published
Property ADOCon:TADOConnection read FADOCon write SetADOCon;
end;

procedure TMyComponent.SetADOCon(const Value: TADOConnection);
begin
If FADOCon <> Value Then FADOCon:=Value;
end;

 
LGXing:
这样做就会出现我所说的那种情况了.但是tadocommand,tadocustomdataset就不会,不知道为什么
 
你有好的习惯知道学习VCL代码,但你怎么不更仔细看呢?
TADOConnection的UnRegisterClient()和RegisterClient()代码都有这个
if (Client is TADOCommand) and not (TADOCommand(Client).Owner is TCustomADODataSet)条件
你的控件满足么?!
//如果你控件不是,那就需要你自己SetConnection过程用你的代码代替这两个函数
提外话:一般自己做的控件多是数据感知控件,没必要有CONNECTION属性的,一般有DATASOURCE属性,难不成你要做自己的数据处理控件?

第2个问题,我有个A组件,必须要在B组件之后创建这个需求和在IDE中有CreateOrder有什么联系
后者根本和前者是两回事情。后者只是告诉DELPHI谁先创建谁后创建,而前者说明有依赖关系,
A组件创建时一定要检测B组件是否存在,这个在CREATE代码检测很简单,如果你做的好,你可以
在检测没有B时自动先创建一个B!





 
to :autumn

我没有看到的组件的实现,不过我看了一下 delphi的Tadocommand 组件的实现细节。
我觉得如果你仅只处理了它的 setconnection肯定是不行的。因为Tadoconnection组件
要求指定它作为一个属性的组件,能够处理连接、断开时过程。
我想你先把所有 与connection有关的属性,比如 ConnectionStateChange等,
就如Tadocommand一样,写进你的控件看看。如果不行,先完全 copy Tadocommand的
结构及实现,再删除不必要的。
 
不过对第1个问题,我感觉你没必要完全和ADOCOMMAND一样的
其实如果某对象被删除,你的组件只要得到通知并对该通知做处理就不出你说的问题
这就需要你的组件重载Notification函数,下面是我一个数据感知控件的代码片段
procedure THSBarCodeImage.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (FDataLink <> nil) and
(AComponent = DataSource) then DataSource := nil;
//这意思是如果有我当前指定的Datasource组件被删除,就执行datasource:=nil就是让我的组件的Datasource为NIL
end;
 
我这里没有出现过错误!不知你那里是否是环境问题
 
小秋,问题1:

unit Component1;

interface

uses
Windows, Messages, SysUtils, Classes,AdoDB;

type
TComponent1 = class(TComponent)
private
Fconnection: TadoConnection;
procedure Setconnection(const Value: TadoConnection);
{ Private declarations }
protected
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
{ Protected declarations }
public
{ Public declarations }
published
Property connection : TadoConnection read Fconnection write Setconnection;
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Samples', [TComponent1]);
end;

{ TComponent1 }

procedure TComponent1.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
case Operation of
opRemove:
if Fconnection = nil then
exit;
end;

end;

procedure TComponent1.Setconnection(const Value: TadoConnection);
begin
Fconnection := Value;
end;

end.

 
o o,不好意思,没仔细看onedot的帖子,意思差不多[:)]
 
根据我以前编写控件的经验,
这个问题的答案应该和onedot与千中元说的一样的,
但是他们好象都忘了一个必须调用的函数,这个函数叫做
FreeNotification,它可以保证
一个控件(叫做A)的属性是另一个窗体上的控件(叫做B),
当删除掉A的时候,IDE不会出现异常。

procedure TComponent1.Setconnection(const Value: TadoConnection);
begin
if FConnection <> Value then
begin
FConnection := Value;
FConnection.FreeNotification(self);
end;
end;
 
onedot都说了,应该是能够解决你的问题的。
 
首先在这里谢谢onedot的指教。
问题1已经解决了,我的具体测试代码如onedot所说:
unit test;

interface

uses
Windows, Messages, SysUtils, Classes,adodb;

type
ttest = class(tcomponent)
private
fconnection: tadoconnection;
procedure setconnection(const Value: tadoconnection);
{ Private declarations }
protected
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
public
{ Public declarations }
published
property connection:tadoconnection read fconnection write setconnection;
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Standard', [ttest]);
end;

{ ttest }

procedure ttest.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
case Operation of
opRemove:
if AComponent = Fconnection then
Fconnection := nil;
end;
end;

procedure ttest.setconnection(const Value: tadoconnection);
begin
fconnection := Value;
end;

end.
我这样作的主要作用是封装一些公司常用的对象,例如公用的统一用户管理,我需要将它作成一个component,然后我的下一级程序员只需要
拖一个我写的控件到form就可以了。以前我的做法是TMyObject=class,然后将一堆dcu,dfm交给别人使用的,但是这样一来,他们就经常抱怨他

们的unit经常和我定义的重名,或const重名,所以我现在将它们作成了tcomponent的形式。
谢谢onedot的方法,我学会了一个技巧:如何得知一个组件被free了。也谢谢其他朋友的指教。onedot得到195得分,千中原得到5的得分,待

我第二个问题获得答案立马付钱

第二个问题:
我在Form中放了一个A,然后又放了一个B,然后运行,正常,因为B必须要在A之前释放。但是如果我在Form中先放B,然后再放A,那么我必须重新

在IDE中设定一下Creation Order,保证B在A之前释放。因为B在正常的释放过程中要利用A的资源完成一个特定的任务。
我这样作的目的是给我的下线程序员使用的,我希望作的好一点,不用他老是需要调整creation order.大家有什么好的提议呢?
 
我倒。不要给分我。
 
干什么?留下你的msn我好联系你。现在我都不用qq了:D
 
autumn老兄:
第一个问题:
你有没有注意到我前面的跟贴?
我提醒你的地方是确实存在的,
为了你的程序的健壮性,
请加上我给你的代码。

第二个问题:
你可以重载A中的SetParent函数,
在SetParent函数中首先检测AParent中是否有B,
如果有,就用一个临时对象保存B,再调用
AParent.RemoveControl(B)函数删除B的指针,
然后调用AParent.InsertControl(A);把A插入到AParent的列表中。
最后调用AParent.InsertControl(B);把B插入到AParent的列表中。
 
谢谢小班。我测试了一下,正如小班所说,当a和b不在同一个form上的时候,上面我和onedot
的代码仍然会发生我原来的问题的,加上小班的代码后就解决了。我看了一下borland关于freenotification的帮助:
Ensures that AComponent is notified that the component is going to be destroyed.

procedure FreeNotification(AComponent: TComponent);

Description

Use FreeNotification to register AComponent as a component that should be notified when the component is about to be destroyed. It is only necessary to register components this way when they are in a different form or have a different owner. For example, if AComponent is in another form and uses the component to implement a property, it must call FreeNotification so that its Notification method is called when the component is destroyed.

For components with the same owner, the Notification method is called automatically when an application explicitly frees the component (for example, by calling the Free method). This notification is not sent out when components are freed implicitly (because the Owner is freed).

修改后代码如下:
unit test;

interface

uses
Windows, Messages, SysUtils, Classes,adodb;

type
ttest = class(tcomponent)
private
fconnection: tadoconnection;
procedure setconnection(const Value: tadoconnection);
{ Private declarations }
protected
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
public
{ Public declarations }
published
property connection:tadoconnection read fconnection write setconnection;
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Standard', [ttest]);
end;

{ ttest }

procedure ttest.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
case Operation of
opRemove:
if AComponent = Fconnection then
Fconnection := nil;
end;
end;

procedure ttest.setconnection(const Value: tadoconnection);
begin
if Value<>fconnection then
begin
fconnection := Value;
if assigned(fconnection) then
fconnection.FreeNotification(self);
end;
end;

end.
 
NOD,小班说的对,我确实忘记提醒你。我的控件和很多数据感知控件就在自己的
procedure THSBarCodeImage.SetDataSource(const Value: TDataSource);
begin

if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
FDataLink.DataSource := Value;
if Value <> nil then Value.FreeNotification(Self);
end;

对于第2个问题,如果是你这样需求,我的态度就是,A控件本身是个包含一个B的空间。
A的CREATE创建一个B,并且ESTROY代码里负责
自动FREE这个对应B。对应你的要求,A控件应该有个属性,它是B控件。
比如我的HSPACK包里就一组控件就是这样的,放一个EDIT,自动有个LABLE和它一起创建并由
EDIT去负责管理它。而这个LABLE不能直接在IDE里删除,而是EDIT删除,它一起FREE掉。
就如同DELPHI的TLabeledEdit差不多。你可以参考它的代码。

不知道我的意思是不是符合你要做组件要求?



 
后退
顶部