2009-07-04 130 views
5

我该如何让我的代码工作? :)我试图制定这个问题,但经过几次失败的尝试后,我认为你们会发现问题的速度比阅读我的'解释'更快。谢谢。使用他的类类型转换TObject?

setCtrlState([ memo1, edit1, button1], False); 

_

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
    ct: TClass; 
begin 
    for obj in objs do 
    begin 
    ct := obj.ClassType; 


    if (ct = TMemo) or (ct = TEdit) then 
     ct(obj).ReadOnly := not bState;  // error here :(

    if ct = TButton then 
     ct(obj).Enabled:= bState;  // and here :(

    end; 
end; 

回答

5

这将是更容易使用RTTI,而不是明确的铸造,即:

uses 
    TypInfo; 

setCtrlState([ memo1, edit1, button1], False); 

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
    PropInfo: PPropInfo; 
begin 
    for obj in objs do 
    begin 
    PropInfo := GetPropInfo(obj, 'ReadOnly'); 
    if PropInfo <> nil then SetOrdProp(obj, PropInfo, not bState); 

    PropInfo := GetPropInfo(obj, 'Enabled'); 
    if PropInfo <> nil then SetOrdProp(obj, PropInfo, bState); 
    end; 
end; 
4

您需要CT目标转换为TMemo/TEDIT/TButton的前可以设置对象的属性。

你得到错误的行是错误的,因为ct仍然是TClass,而不是TButton/etc。如果你投掷到TButton,那么你可以将启用设置为true。

我推荐阅读casting in Delphi。就个人而言,我建议使用as/is操作符,而不是使用ClassType。在这种情况下,代码会更简单,而且更容易理解。


就个人而言,我会写这更像是:

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
begin 
    for obj in objs do 
    begin 
    // I believe these could be merged by using an ancestor of TMemo+TEdit (TControl?) 
    // but I don't have a good delphi reference handy 
    if (obj is TMemo) then 
     TMemo(obj).ReadOnly := not bState; 

    if (obj is TEdit) then 
     TEdit(obj).ReadOnly := not bState; 

    if (obj is TButton) then 
     TButton(obj).Enabled := bState; 
    end; 
end; 
7

你必须明确地转换对象的一些类。 这应该工作:

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
    ct: TClass; 
begin 
    for obj in objs do 
    begin 
    ct := obj.ClassType; 

    if ct = TMemo then 
     TMemo(obj).ReadOnly := not bState 
    else if ct = TEdit then 
     TEdit(obj).ReadOnly := not bState 
    else if ct = TButton then 
     TButton(obj).Enabled := bState; 
    end; 
end; 

这可以通过使用“is”运营商缩短 - 无需CT变量:

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
begin 
    for obj in objs do 
    begin 
    if obj is TMemo then 
     TMemo(obj).ReadOnly := not bState 
    else if obj is TEdit then 
     TEdit(obj).ReadOnly := not bState 
    else if obj is TButton then 
     TButton(obj).Enabled := bState; 
    end; 
end; 
+0

不应该在每一种情况下第二类型转换为“TEDIT”,而不是“TMemo”? – Argalatyr 2009-07-04 23:21:04

+0

+0.5表示你必须对每种类型进行演员表演。 +0.5使用“是” – 2009-07-04 23:23:19

3

没有必要投给TMemo和TEDIT分开,因为它们是从常见的父类两个后代,具有只读属性:

procedure TForm1.FormCreate(Sender: TObject); 

    procedure P(const Obj: TComponent); 
    begin 
    if Obj is TCustomEdit then 
     TCustomEdit(Obj).ReadOnly := True; 
    end; 

begin 
    P(Memo1); 
    P(Edit1); 
end; 
2

你能避免引用各单位,如果你明确的铸造不要介意小的性能影响并限制对已发布属性的更改。查看Delphi附带的TypInfo单元。