मैं एक ड्राइंग ऐप के लिए एक सरलीकृत ऑब्जेक्ट इंस्पेक्टर बनाने की कोशिश कर रहा हूं जिसे मैं लिख रहा हूं।

मैं चयनित वस्तु और उसके बाल वस्तुओं के लिए गतिशील रूप से आरटीटीआई प्राप्त करने की कोशिश कर रहा हूं। यदि दी गई संपत्ति एक वर्ग (tkClass) है, तो मैं GetRTTIObject को पुनरावर्ती रूप से कॉल करना चाहता हूं, उस संपत्ति को इसके लिए "उपप्रॉपर्टीज" प्राप्त करने के लिए ऑब्जेक्ट के रूप में सौंपना चाहता हूं (यानी BaseObj.Brush.Color या BaseObj.Pen.Width आदि)। मुझे संदेह है कि मैं उस वस्तु के उदाहरण को पारित करना चाहता हूं और यह दर्दनाक रूप से स्पष्ट होगा जब कोई बताता है कि वह क्या है। मैं अपने फ़ंक्शन को पास करने के लिए एक उदाहरण कैसे प्राप्त करूं? या क्या मुझे कक्षाओं के गुणों के लिए TRttiInstance देखना चाहिए ....?

मुझे पता है कि यह "स्तर 0" पर काम करता है, क्योंकि मैं बेसऑब्जेक्ट में पास कर सकता हूं। GetRTTIObject की मेरी पहली कॉल पर ब्रश करें और मुझे टीबीश गुणों की एक सूची मिलती है। मैं पुनरावर्ती रूप से कैसे ड्रिल कर सकता हूं?

मुझे वैल्यू के साथ किसी प्रकार का पॉइंटर मिलता है: = GetPropValue (AObj, Prop.Name);

क्या मैं इसे किसी भी तरह से अपना उदाहरण प्राप्त करने के लिए अस्वीकार करता हूं ...?

सादर, रोबो

सरलीकृत परीक्षण वर्ग परिभाषित किया गया है:

TBaseClass = class(TObject)
  private
    FFont: TFont;
    FBrush: TBrush;
    FPen: TPen;
    FCaption: String;
    FFloat1: Real;
    FInt1: Integer;
  published
    property Font: TFont Read FFont Write FFont;
    property Brush: TBrush Read FBrush Write FBrush;
    property Pen: TPen Read FPen Write FPen;
    property Caption: String Read FCaption Write FCaption;
    property Float1: Real Read FFloat1 Write FFloat1;
    property Int1: Integer Read FInt1 Write FInt1;
end;

मेरी आरटीटीआई प्रक्रिया है:

procedure TfrmMain.GetRTTIClass(AClass: TClass; Items: TStrings; Indent: Integer);
var
  LContext: TRttiContext;
  LType: TRttiType;
  Prop: TRttiProperty;
  PropString: String;
  PropInfo: PPropInfo;
  Tabs: String;
  I: Integer;
  Value: Variant;
begin
  LContext := TRttiContext.Create();

  try
    for I := 0 to Indent do
      Tabs := Tabs + '  '; //chr(9)

    Log(Format('Get RTTI (Class) for "%s"', [AClass.ClassName]));

    LType := LContext.GetType(AClass.ClassInfo);

    Items.Add(Tabs + 'RTTI for: ' + Ltype.Name);
    Items.Add(Tabs + 'Package Name: ' + LType.Package.Name);

    Items.Add(Tabs + '-- Properties --');

    for Prop in LType.GetProperties do
    begin
      PropString := 'property: ' + Prop.Name;

      PropInfo := GetPropInfo(AClass, Prop.Name);
      PropString := PropString + ': ' + GetEnumName(TypeInfo(TTypeKind), Ord(Prop.PropertyType.TypeKind));

      if propInfo <> nil then begin
        PropString := PropString + ': ' + PropInfo^.PropType^.Name;

        case propInfo.PropType^.Kind of
          tkClass: begin
           PropString := PropString + ' (Class)' ; // ' GetProp Value: ' + IntToHex(PropInfo.GetProc, 8); //     Items.Add('--- Get RTTI ---');(Class)';
           Log(Format('GetRTTI: %s (%s)', [Prop.Name, PropInfo^.PropType^.Name]));
           // TODO: Get a reference to the object and call GetRTTI
           // TODO: Or change function to work from classtype rather than object

//           GetRTTIObject(### WHAT GOES HERE?!?!?, Items, Indent + 1);// := PropString + ' Class';
          end;

        end;
      end;

      Items.Add(Tabs + PropString);

    end;
  finally
    LContext.Free;
  end;
end;

उफ़ !!

मैं देखता हूं कि मैंने गलत कार्य किया है ..... प्रश्न में एक टॉब्जेक्ट लेता है और असाइनमेंट है:

एल टाइप := LContext.GetType((AObject.ClassInfo); (AObject.ClassType भी काम करने लगता है...)...

अभी मेरे देव स्टेशन पर नहीं, बल्कि सोचिए कि उसके बाद सब कुछ वैसा ही है...

1
Robatron 28 पद 2020, 05:21

2 जवाब

सबसे बढ़िया उत्तर

आपके उदाहरण में समस्या है कि टीबीट्रैश के पास टीबीआईटीमैप संपत्ति है, टीबीआईटीमैप में टीसीएनवास है, टीसीएनवास में टीबीराश है। फ़ंक्शन का कॉल GetRTTIClass अनंत पुनरावर्ती होगा। लेकिन यदि प्रत्येक वर्ग के लिए केवल एक बार RTTI प्राप्त करने की शर्त रखी जाए तो आपके कार्य को ठीक करना संभव है।

uses System.Generics.Collections;
var ListClasses:TList<TClass>;
    LContext : TRttiContext;
implementation

procedure TfrmMain.FormCreate(Sender: TObject);
begin
 LContext := TRttiContext.Create();
 ListClasses:=TList<TClass>.Create;
end;

procedure TfrmMain.GetRTTIClass(AClass: TClass; Items: TStrings; Indent: Integer);
var
  LType: TRttiType;
  Prop: TRttiProperty;
  PropString: String;
  Tabs: String;
  I: Integer;
begin
  if ListPrinted.Contains(AClass) then Exit
                                  else ListPrinted.Add(AClass);
  for I := 0 to Indent do Tabs := Tabs + '  ';
  LType := LContext.GetType(AClass.ClassInfo);
  Items.Add(Tabs + 'RTTI for: ' + Ltype.Name);
  Items.Add(Tabs + 'Package Name: ' + LType.Package.Name);
  Items.Add(Tabs + '-- Properties --');
  for Prop in LType.GetProperties do  begin
    PropString := 'property: ' + Prop.Name;
    PropString := PropString + ': ' + GetEnumName(TypeInfo(TTypeKind), Ord(Prop.PropertyType.TypeKind))+' '+Prop.PropertyType.Name;
    Items.Add(Tabs + PropString);
    case Prop.PropertyType.Handle^.Kind of
      tkClass: begin
        GetRTTIClass(Prop.PropertyType.Handle^.TypeData^.ClassType, Items,Indent+2);
      end;
    end;
end;
procedure TfrmMain.btn1Click(Sender: TObject);
begin
  GetRTTIClass(TBaseClass, Items,0);
end;
2
Andriy Sokolov 28 पद 2020, 23:44

ठीक है, मैंने प्रक्रिया में कुछ संशोधन किए हैं। कक्षा को पार्स करना काफी नहीं है। मुझे उदाहरणों के लिए हैंडल चाहिए।

मेरी प्रक्रिया को दोबारा कॉल करने के लिए (वह जो ऑब्जेक्ट लेता है, कक्षा को पहले पैरामीटर के रूप में नहीं), मुझे उप-ऑब्जेक्ट (उदाहरण के लिए AObj.Font) के उदाहरण की आवश्यकता है। मैं इसके साथ हासिल कर सकता हूं:

case Prop.PropertyType.TypeKind of
  tkClass: begin
    SubObj := GetObjectProp(AObj, Prop.Name);
    GetRTTIObject2(SubObj, Tree, ChildNode, Indent + 2);
  end;
end;

इतना सरल, वास्तव में, एक बार मैंने इसके चारों ओर अपना सिर लपेट लिया।

समाधान के रूप में अभी भी दूसरे उत्तर को वोट देने जा रहा है, क्योंकि इसने एक और नुकसान से बचने के लिए अच्छे संकेत दिए हैं। :)

0
Robatron 30 पद 2020, 03:49