5

我怎样才能让我的代码工作?:) 我试图提出这个问题,但经过几次失败的尝试后,我认为你们会更快地发现问题,而不是阅读我的“解释”。谢谢你。

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;
4

5 回答 5

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;
于 2009-07-04T22:59:46.157 回答
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;
于 2009-07-08T01:02:14.833 回答
4

您需要先将 ct 对象转换为 TMemo/TEdit/TButton,然后才能在对象上设置属性。

您遇到错误的行正在出错,因为 ct 仍然是 TClass,而不是 TButton/等。如果您投射到 TButton,那么您将能够将 enabled 设置为 true。

我建议阅读有关在 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;
于 2009-07-04T22:38:52.033 回答
3

无需分别转换为 TMemo 和 TEdit,因为它们都是公共父类的后代,具有 ReadOnly 属性:

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;
于 2009-07-05T13:21:36.533 回答
2

如果您不介意小的性能损失并限制对已发布属性的更改,则可以避免引用各种单元和显式转换。查看 Delphi 附带的 TypInfo 单元。

于 2009-07-06T10:17:10.807 回答