2008-10-27 9 views
12

Gibt es eine einfache Möglichkeit, alle untergeordneten Komponenten unter der übergeordneten Komponente zu duplizieren, einschließlich ihrer veröffentlichten Eigenschaften?Duplizieren von Komponenten zur Laufzeit

Zum Beispiel:

  • TPanel
    • TLabel
    • TEdit
    • TListView
    • TSpecialClassX

Natürlich der wichtigste Faktor, es sollte jede neue Komponente kopieren, die ich auf dem TPanel absetze, ohne den Code unter normalen Umständen zu ändern.

Ich habe von der RTTI gehört, aber nie tatsächlich verwendet. Irgendwelche Ideen?

Antwort

6

haben eine Lese dieser Seite

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

die Copying Properties From A Component To Another

Abschnitt Kenntnis nehmend, die eine Einheit hat, RTTIUnit mit einem Verfahren, das Teil von dem, was Sie tun möchten, scheint aber ich don‘ Ich denke, es wird alle untergeordneten Komponenten ohne zusätzlichen Code kopieren. (ich glaube, es ist ok, es hier einfügen ...)

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

Es ist eigentlich ziemlich einfach, vorhandene Komponenten zur Laufzeit zu duplizieren. Der schwierige Teil besteht darin, alle veröffentlichten Eigenschaften auf die neuen (duplizierten) Objekte zu kopieren.

Es tut mir leid, aber mein Codebeispiel ist in C++ Builder. Die VCL ist dieselbe, nur eine andere Sprache. Es sollte nicht zu viel Mühe es Delphi zu übersetzen:

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 
     } 

Vielleicht hat jemand eine bessere Methode alle veröffentlichten Eigenschaften der alten Steuerung auf die neue kopieren.

9

Sie propably die auf „Replace visual component at runtimeCLoneProperties routine from the answer verwenden können, nachdem Sie die dup Komponenten in einer Schleife durch die Kontrollen der Eltern erstellt.

aktualisieren: einige Arbeitscode ....

. Ich gehe von Ihrer Frage aus, dass Sie die Controls duplizieren wollen, die in einem WinControl enthalten sind (als Eltern ist ein TWinControl).
. Da ich nicht wusste, ob Sie die duplizierten Steuerelemente auch mit den gleichen Event Handlern wie die Originale verbinden wollten, habe ich eine Option dafür gewählt.
. Und Sie möchten den duplizierten Steuerelementen möglicherweise einen sinnvollen Namen geben.

+0

Sehr gute Lösung! Danke für Ihre Hilfe! –

3

Sie können die Quellkomponente in einen Stream schreiben und in die Zielkomponente zurücklesen.

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

Sie können jedoch Probleme mit doppelten Komponentennamen bekommen.

+1

@ Uwe, Sie haben Recht, dass doppelte Komponentennamen ein Problem sein werden, wenn Source und Target das gleiche Elternteil teilen. Eine Lösung besteht darin, den Namen der Quellkomponente vor dem Schreiben in einen Stream vorübergehend auf eine leere Zeichenfolge zu setzen. Nach dem Lesen der Zielkomponente müssen Sie einen Eigennamen für die Zielkomponente finden, wenn Sie die Zielkomponente beibehalten möchten, da Delphi keine Komponenten mit einer leeren Namenseigenschaft streamt. – iamjoosy