询问控件属性的赋值顺序如何设定?(300分)

  • 主题发起人 萧月禾
  • 开始时间

萧月禾

Unregistered / Unconfirmed
GUEST, unregistred user!
话说假设有一个自定义控件,有三个published属性:A1, A2, A3
在设计期于控件的属性面版上分别给A1, A2, A3三个属性赋值
在该控件中是通过SetA1,SetA2,SetA3来write这三个属性的
但在SetA1的过程中,要执行一个函数,该函数中使用到A2、A3的值
这就要求在给A1赋值前,需要先给A2、A3赋值
但这属性的赋值顺序我无法设定,还请有经验的朋友帮忙,谢谢

该控件类的定义大致如下:
TMyComponent = class(TComponent)
private
procedure SetA1(const Value: Integer);
procedure SetA2(const Value: string);
procedure SetA3(const Value: TAdoConnection);
protected
FA1: Integer;
FA2: string;
FA3: TAdoConnection;
public
procedure DoSomething; //在SetA1中调用

constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property A1: Integer read FA1 write SetA1;
property A2: string read FA2 write SetA2;
property A3: TAdoConnection read FA3 write SetA3;

end;

请问如何保证先执行了SetA2、SetA3,然后再执行SetA1?
 
增加一个域,在SetA2,SetA3中改变这个值,在SetA1中检查这个域的值,如果是经过SetA2和
SetA3改变的才执行,否则引发错误
 
我不要它引发错误,我要它生效
 
//这就要求在给A1赋值前,需要先给A2、A3赋值

A1怎么生效呢?如果A2,A3没赋值之前?
 
就要它先执行 SetA2, SetA3,然后再执行SetA1
但它现在是先执行了SetA1,再执行SetA2 , SetA3
就是要设置它们的执行顺序
我在published里把A1的位置放在最后都不起作用
 
当然不起作用了,那里的顺序又不是指赋值的顺序
赋值的顺序是根据实际代码来的,如果你发布这个对象,我写
a1:=1;
a2:='';
a3:=.....
如果不引发错误,就没有其它办法,如果a1是必须在a3建立之后赋值,你可以把
a3封装一下,增加一个属性,不能直接通过TMyComponent访问a1,只能通过a3来访问
 
靠。。这都不会。。你怎么不会转个弯想问题呢?
加个属性默认值不就搞定了吗?
例如
property ButtonSize: Integer read FButtonSize write SetButtonSize default 0;
i 服了 you
(不好意思是另一位老大让我这样教训你的)
 
published 中的位置是程序在执行时,从dfm读值的顺序;
在published里把A1的位置放在A2,A3后就行了!

//我在published里把A1的位置放在最后都不起作用
不太可能吧!你打开DFM文件看看!A1的值是否在A2,A3前!

 
还有
在代码中使用是要先对A2,A3赋值这样就可以先调用SETA2,SETA3,
再对A1赋值!
不要觉得麻烦,其实很多数据库控件都这样!
 
to delphi浪客:
1、加default值和这道题没有任何关系,那些值都是在设计期由开发人员在属性面版中设的
2、加default值也不影响SetValue的顺序
3、加default值,其值也不一定马上起作用,不信你试试
4、你那位老大是谁?[:)]

问题的目的其实已经解决了,方法是把要做的事情放在重载的 Loaded 方法中做
其将在所有赋值完成后执行,不过我还是想了解属性赋值的顺序如何设定?
开始认为是设其在Published中的顺序,验证后发现也不是绝对的
难道就真的没有办法?
 
据我所知,所有属性都是平等的,你见过在属性面板中的一个属性的值要等另一个属性设定
之后才能改吗?没有!
 
FA3: TAdoConnection;
你不把TAdoConnection.Connectionstring设定好就想
把Connected设为TRUE不错才怪!多数据库控件都这样!
 
另外再问一个问题: 控件的属性能否是一个Form?
在属性面版上,可选择一个Form给它赋值
把属性的类型定义成TForm,但每个Form都是从TForm继承下来的子类
把类型定义成 class of TForm , 结果在属性面版上连这个属性都不出现了
 
没搞过!
我想只能定义成从TForm继承下来的子类,而只能针对与一个从TForm继承
下来的子类;不可能通用;
每个Form都是从TForm继承下来的子类;
就算是定义成TForm,赋值成功,也没法,掉用子类的方法!
一般都用查找当前Form的方法,没搞过!
 
在SetA2,SetA3 的最后也执行 setA1 ,这样次序就不会有问题了。
 
to 萧月禾,那位老大说是你是他师弟,他的积分很高得,不过他不让我说他的名字,要不我
有天大的胆子也不敢教训您老啊,^_^,他现在和我在一个公司,很少上这来,我还是他
介绍才来这混的。。
 
哦,你说的是黎师兄罢,他近来可好?
 
GE WEI LAO DA
NENG BU NENG KAN KAN WO DE WEN TI?
 
procedure TReader.ReadProperty(AInstance: TPersistent);
var
I, J, L: Integer;
Instance: TPersistent;
PropInfo: PPropInfo;
PropValue: TObject;
PropPath: string;

procedure HandleException(E: Exception);
var
Name: string;
begin
Name := '';
if AInstance is TComponent then
Name := TComponent(AInstance).Name;
if Name = '' then Name := AInstance.ClassName;
raise EReadError.CreateResFmt(@SPropertyException, [Name, DotSep, PropPath, E.Message]);
end;

procedure PropPathError;
begin
SkipValue;
ReadError(@SInvalidPropertyPath);
end;

begin
try
PropPath := ReadStr;
try
I := 1;
L := Length(PropPath);
Instance := AInstance;
FCanHandleExcepts := True;
while True do
begin
J := I;
while (I <= L) and (PropPath <> '.') do Inc(I);
FPropName := Copy(PropPath, J, I - J);
if I > L then Break;
PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
if PropInfo = nil then
PropertyError(FPropName);
PropValue := nil;
if PropInfo^.PropType^.Kind = tkClass then
PropValue := TObject(GetOrdProp(Instance, PropInfo));
if not (PropValue is TPersistent) then PropPathError;
Instance := TPersistent(PropValue);
Inc(I);
end;
PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
if PropInfo <> nil then ReadPropValue(Instance, PropInfo) else
begin
{ Cannot reliably recover from an error in a defined property }
FCanHandleExcepts := False;
Instance.DefineProperties(Self);
FCanHandleExcepts := True;
if FPropName <> '' then
PropertyError(FPropName);
end;
except
on E: Exception do HandleException(E);
end;
except
on E: Exception do
if not FCanHandleExcepts or not Error(E.Message) then raise;
end;
end;


这段代码比较难看懂,但是也可以看得出来,属性是一个一个读的,是有先后顺序的,
而且这个顺序的确是和dfm文件中存放的顺序是一致的,这个顺序也是和我们
View as text一个form看到的顺序是一致的,而View as text中看到的顺序又与published段属性
定义的顺序是一致的.

也许你会说为什么Query控件的Active在前面,按照上面的理论,在读入Active,假如为True,
此时SQL属性还没有读入值,应该不能设为True才对,的确是这样的,是不能,所以才有如下代码
procedure TDataSet.SetActive(Value: Boolean);
begin
if (csReading in ComponentState) then
begin
//////////////////////////////////////////////////
FStreamedActive := Value;
//看到这行代码了吗?如果是正在读入属性值,则只是设置一个标志,
//////////////////////////////////////////////////
end
else
if Active <> Value then
begin
if Value then
begin
DoBeforeOpen;
try
OpenCursor;
finally
if State <> dsOpening then
OpenCursorComplete;
end;
end else
begin
if not (csDestroying in ComponentState) then DoBeforeClose;
SetState(dsInactive);
CloseCursor;
if not (csDestroying in ComponentState) then DoAfterClose;
end;
end;
end;

//属性读入完后发调用Loaded方法,这时再检查FStreamedActive属性,如是True则再把Active设为True.
procedure TDataSet.Loaded;
begin
inherited Loaded;
try
if FStreamedActive then Active := True;
except
if csDesigning in ComponentState then
InternalHandleException else
raise;
end;
end;
 
顶部