cast TObject using his ClassType?

前端 未结 5 1228
抹茶落季
抹茶落季 2021-01-13 07:27

how can i make my code to work ? :) i`ve tried to formulate this question but after several failed attempts i think you guys will spot the problem faster looking at the code

相关标签:
5条回答
  • 2021-01-13 07:50

    You must explicitly cast object to some class. This should work:

     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;
    

    This can be shortened using "is" operator - no need for ct variable:

     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 讨论(0)
  • 2021-01-13 07:51

    You need to cast the ct object to a TMemo/TEdit/TButton before you can set properties on the object.

    The line where you're getting errors are erroring because ct is still a TClass, not a TButton/etc. If you cast to a TButton, then you'll be able to set enabled to true.

    I recommend reading up on casting in Delphi. Personally, I would recommend using the as/is operators instead of using ClassType, as well. The code will be simpler in that case, and much more understandable.


    Personally, I would write this more like:

    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;
    
    0 讨论(0)
  • 2021-01-13 08:00

    You can avoid referencing various units and the explicit casting if you do not mind a small performance hit and limit the changes to published properties. Have a look at the TypInfo unit included with Delphi.

    0 讨论(0)
  • 2021-01-13 08:01

    There is no need to cast to TMemo and TEdit separately, as they are both descendants from common parent class, which have ReadOnly property:

    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;
    
    0 讨论(0)
  • 2021-01-13 08:02

    It would be easier to use RTTI instead of explicit casting, ie:

    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;
    
    0 讨论(0)
提交回复
热议问题