2008-10-27 18 views
12

पर घटकों को डुप्लिकेट करना क्या उनके प्रकाशित गुणों सहित मूल घटक के तहत सभी बाल घटकों को डुप्लिकेट करने का कोई आसान तरीका है?रन-टाइम

उदाहरण के लिए:

  • TPanel
    • TLabel
    • TEdit
    • TListView
    • TSpecialClassX

बेशक सबसे महत्वपूर्ण कारक, इसे किसी भी नए घटक को डुप्लिकेट करना चाहिए जिसे मैं सामान्य परिस्थितियों में कोड को संशोधित किए बिना टीपीनल पर छोड़ देता हूं।

मैंने आरटीटीआई के बारे में सुना है, लेकिन वास्तव में इसका उपयोग कभी नहीं किया। कोई विचार?

उत्तर

6

यह पेज

Run-Time Type Information In Delphi - Can It Do Anything For You?

अनुभाग Copying Properties From A Component To Another

जो एक प्रक्रिया है, जो तुम क्या चाहते का हिस्सा करने के लिए लगता है के साथ एक यूनिट, RTTIUnit है ध्यान देने योग्य बात का रीड है, लेकिन मैं डॉन ' टी लगता है कि यह किसी भी बच्चे के घटकों को अतिरिक्त कोड के साथ कॉपी करेगा। (मैं इसे यहाँ पेस्ट करने के लिए ठीक है लगता है ...)

procedure CopyObject(ObjFrom, ObjTo: TObject);  
    var 
PropInfos: PPropList; 
PropInfo: PPropInfo; 
Count, Loop: Integer; 
OrdVal: Longint; 
StrVal: String; 
FloatVal: Extended; 
MethodVal: TMethod; 
begin 
//{ Iterate thru all published fields and properties of source } 
//{ copying them to target } 

//{ Find out how many properties we'll be considering } 
Count := GetPropList(ObjFrom.ClassInfo, tkAny, nil); 
//{ Allocate memory to hold their RTTI data } 
GetMem(PropInfos, Count * SizeOf(PPropInfo)); 
try 
//{ Get hold of the property list in our new buffer } 
GetPropList(ObjFrom.ClassInfo, tkAny, PropInfos); 
//{ Loop through all the selected properties } 
for Loop := 0 to Count - 1 do 
begin 
    PropInfo := GetPropInfo(ObjTo.ClassInfo, PropInfos^[Loop]^.Name); 
// { Check the general type of the property } 
    //{ and read/write it in an appropriate way } 
    case PropInfos^[Loop]^.PropType^.Kind of 
    tkInteger, tkChar, tkEnumeration, 
    tkSet, tkClass{$ifdef Win32}, tkWChar{$endif}: 
    begin 
     OrdVal := GetOrdProp(ObjFrom, PropInfos^[Loop]); 
     if Assigned(PropInfo) then 
     SetOrdProp(ObjTo, PropInfo, OrdVal); 
    end; 
    tkFloat: 
    begin 
     FloatVal := GetFloatProp(ObjFrom, PropInfos^[Loop]); 
     if Assigned(PropInfo) then 
     SetFloatProp(ObjTo, PropInfo, FloatVal); 
    end; 
    {$ifndef DelphiLessThan3} 
    tkWString, 
    {$endif} 
    {$ifdef Win32} 
    tkLString, 
    {$endif} 
    tkString: 
    begin 
     { Avoid copying 'Name' - components must have unique names } 
     if UpperCase(PropInfos^[Loop]^.Name) = 'NAME' then 
     Continue; 
     StrVal := GetStrProp(ObjFrom, PropInfos^[Loop]); 
     if Assigned(PropInfo) then 
     SetStrProp(ObjTo, PropInfo, StrVal); 
    end; 
    tkMethod: 
    begin 
     MethodVal := GetMethodProp(ObjFrom, PropInfos^[Loop]); 
     if Assigned(PropInfo) then 
     SetMethodProp(ObjTo, PropInfo, MethodVal); 
    end 
    end 
end 
finally 
    FreeMem(PropInfos, Count * SizeOf(PPropInfo)); 
end; 
end; 
0

रनटाइम पर मौजूदा घटकों को डुप्लिकेट करना वास्तव में काफी आसान है। मुश्किल हिस्सा उनकी सभी प्रकाशित गुणों को नई (डुप्लिकेट) ऑब्जेक्ट्स में कॉपी करना है।

मुझे खेद है, लेकिन मेरा कोड उदाहरण सी ++ बिल्डर में है। वीसीएल वही है, सिर्फ एक अलग भाषा है।

for (i = 0; i < ComponentCount; ++i) { 
    TControl *Comp = dynamic_cast<TControl *>(Components[i]); 
    if (Comp) { 
     if (Comp->ClassNameIs("TLabel")) { 
      TLabel *OldLabel = dynamic_cast<TDBEdit *>(Components[i]); 
      TLabel *NewLabel = new TLabel(this); // new label 
      // copy properties from old to new 
      NewLabel->Top = OldLabel->Top; 
      NewLabel->Left = OldLabel->Left; 
      NewLabel->Caption = Oldlabel->Caption 
      // and so on... 
     } else if (Comp->ClassNameIs("TPanel")) { 
      // copy a TPanel object 
     } 

हो सकता है कि किसी को नया करने के लिए पुराने नियंत्रण से प्रकाशित सभी गुणों की प्रतिलिपि बनाई जा रही का एक बेहतर तरीका है: यह यह डेल्फी अनुवाद करने के लिए बहुत ज्यादा मुसीबत नहीं होना चाहिए।

9

आप propably उपयोग कर सकते हैं CLoneProperties routine from the answer करने के लिए "Replace visual component at runtime", के बाद आप माता-पिता के नियंत्रण के माध्यम से एक पाश में dup घटक बनाया है।

अद्यतन: कुछ काम कर कोड ....

। मैं आपके प्रश्न से मानता हूं कि आप WinControl में निहित नियंत्रणों को डुप्लिकेट करना चाहते हैं (एक अभिभावक एक TWINControl है)।
। जैसा कि मुझे नहीं पता था कि आप मूल ईवेंट के समान इवेंट हैंडलर के साथ डुप्लिकेट नियंत्रण को भी हुक करना चाहते हैं, मैंने इसके लिए एक विकल्प बनाया है।
। और आप डुप्लिकेट नियंत्रणों के लिए एक उचित सार्थक नाम देना चाह सकते हैं।

uses 
    TypInfo; 

procedure CloneProperties(const Source: TControl; const Dest: TControl); 
var 
    ms: TMemoryStream; 
    OldName: string; 
begin 
    OldName := Source.Name; 
    Source.Name := ''; // needed to avoid Name collision 
    try 
    ms := TMemoryStream.Create; 
    try 
     ms.WriteComponent(Source); 
     ms.Position := 0; 
     ms.ReadComponent(Dest); 
    finally 
     ms.Free; 
    end; 
    finally 
    Source.Name := OldName; 
    end; 
end; 

procedure CloneEvents(Source, Dest: TControl); 
var 
    I: Integer; 
    PropList: TPropList; 
begin 
    for I := 0 to GetPropList(Source.ClassInfo, [tkMethod], @PropList) - 1 do 
    SetMethodProp(Dest, PropList[I], GetMethodProp(Source, PropList[I])); 
end; 

procedure DuplicateChildren(const ParentSource: TWinControl; 
    const WithEvents: Boolean = True); 
var 
    I: Integer; 
    CurrentControl, ClonedControl: TControl; 
begin 
    for I := ParentSource.ControlCount - 1 downto 0 do 
    begin 
    CurrentControl := ParentSource.Controls[I]; 
    ClonedControl := TControlClass(CurrentControl.ClassType).Create(CurrentControl.Owner); 
    ClonedControl.Parent := ParentSource; 
    CloneProperties(CurrentControl, ClonedControl); 
    ClonedControl.Name := CurrentControl.Name + '_'; 
    if WithEvents then 
     CloneEvents(CurrentControl, ClonedControl); 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    DuplicateChildren(Panel1); 
end; 
+0

बहुत अच्छा समाधान! आपकी सहायताके लिए धन्यवाद! –

3

आप स्रोत घटक को एक स्ट्रीम में लिख सकते हैं और इसे वापस लक्षित घटक में पढ़ सकते हैं।

MemStream := TMemoryStream.Create; 
try 
    MemStream.WriteComponent(Source); 
    MemStream.Position := 0; 
    MemStream.ReadComponent(Target); 
finally 
    MemStream.Free; 
end; 

हालांकि आपको डुप्लिकेट घटक नामों के साथ समस्याएं हो सकती हैं।

+1

@ उवे, आप सही हैं कि डुप्लिकेट घटक नाम एक समस्या होगी यदि स्रोत और लक्ष्य दोनों एक ही माता-पिता को साझा करते हैं। एक समाधान अस्थायी रूप से स्रोत घटक नाम को स्ट्रीम पर लिखने से पहले एक खाली स्ट्रिंग पर सेट करना है। लक्ष्य घटक पढ़ने के बाद आपको लक्ष्य घटक के लिए एक उपयोगकर्ता नाम मिलना होगा यदि आप लक्ष्य घटक को जारी रखना चाहते हैं क्योंकि डेल्फी खाली नाम संपत्ति के साथ घटकों को स्ट्रीम नहीं करता है। – iamjoosy