![]() |
Objekt kopieren
Ichhabe das Problemm, dass ich ein Objekt kopieren muss. Ich habe auch schon im Forum gesucht und Muetze1s Methode mit dem Copy-Constructor gewählt:
Delphi-Quellcode:
Und der Aufruf:
constructor TPageCollection.Create(pc: TPageCollection);
begin inherited Create; FInnerList := TList.Create; FInnerList.Assign(pc.FInnerList); FPageParent := pc.FPageParent; FPageOptions := pc.FPageOptions; FOnProgress := pc.FOnProgress; FOnSaveFinish := pc.FOnSaveFinish; FOnLoadFinish := pc.FOnLoadFinish; end;
Delphi-Quellcode:
Nur leider wird doch keine Kopie erzeugt, so dass sich die Änderungen ScalePage doch wieder auf die Originale auswirken und das darf nicht sein. Wo liegt hier der Fehler oder was mache ich falsch?
procedure TFotoBook.DisplayDoublePage(PageIndex: Integer; ScaleFactor: Double);
var TempPC: TPageCollection; TempLeftPage: TImageEnVect; TempRightPage: TImageEnVect; begin TempPC := TPageCollection.Create(FPageCollection); if PageIndex = -1 then Inc(PageIndex); if (not Odd(PageIndex)) and (PageIndex <> 0) then Inc(PageIndex); // Alles unsichtbar machen, sonst funktio0niert Update nicht if Assigned(LeftPage) then begin LeftPage.Visible := False; end; if Assigned(RightPage) then begin RightPage.Visible := False; end; if (PageIndex = 0) or (PageIndex = -1) then begin LeftPage := nil; TempLeftPage := nil; end else begin LeftPage := FPageCollection.Items[PageIndex]; TempLeftPage := TempPC.Items[PageIndex]; TempLeftPage.Visible := False; end; if Assigned(TempLeftPage) then begin TempLeftPage.Parent := PageParent; TempLeftPage.ScrollBars := ssNone; TempLeftPage.UnSelAllObjects; TempLeftPage.LayersCurrent := 0; ScalePage(TempLeftPage, ScaleFactor); TempLeftPage.Left := PageParent.Width div 2 - TempLeftPage.Width - PAGEGAP div 2; TempLeftPage.Top := PageParent.Height div 2 - TempLeftPage.Height div 2; TempLeftPage.Visible := True; end; if (PageIndex > 0) and not (FPageCollection.Count < 0) then Inc(PageIndex); if PageIndex < FPageCollection.Count then begin RightPage := FPageCollection.Items[PageIndex]; TempRightPage := TempPC.Items[PageIndex]; end else begin RightPage := nil; TempRightPage := nil; end; if Assigned(TempRightPage) then begin TempRightPage.Parent := PageParent; TempRightPage.ScrollBars := ssNone; TempRightPage.UnSelAllObjects; TempRightPage.LayersCurrent := 0; ScalePage(TempRightPage, ScaleFactor); TempRightPage.Left := PageParent.Width div 2 + PAGEGAP div 2; TempRightPage.Top := PageParent.Height div 2 - TempRightPage.Height div 2; TempRightPage.Visible := True; end; end; |
Re: Objekt kopieren
Hallo!
Ohne jetzt die zweite Prozedur richtig verstanden zu haben: Im Konstruktor rufst du ja FInnerList.Assign auf. Wie ist FInnerlist.Assign definiert? Eventuell kopierst du hier nur die Zeiger der Objekte von einer Liste in die andere... Edit:Ist ein TList-Objekt, ergo nur Zeiger damit kopiert... :) Cu, Udontknow |
Re: Objekt kopieren
Mist und wie mache ich das dann?
|
Re: Objekt kopieren
Natürlich, indem Du die einzelnen Elemente der Liste klonst. Es gibt ja die Eigenschaft Assign, die Du für die Listen-Elemente überschreiben könntest. Oder Du überschreibst die 'Assign'-Methode der Liste und erstellst Kopien.
Wir leiten unsere Objekte nicht von TObject ab, sondern von einem Nachfahren von TObject, dem wir dann eigene Grundfunktionalität beibringen. Eine davon ist die Clone-Methode (Funktion). Sie liefert eine exakte Kopie des Objektes. Nur das Objekt selbst weiss ja am Besten, wie es sich reproduziert (da würdest Du dir auch nicht reinreden lassen :lol: ) Eine Collection kann sich dann sehr einfach klonen:
Delphi-Quellcode:
Eine weitere Möglichkeit ist es, die Klasse von TPersistent abzuleiten, um dann die Reader und Writer Methoden zu erweitern. Dann kannst Du eine Kopie anlegen, indem du das Quellobjekt in einen Stream schreibst, und dann in die Kopie reinlädst.
Function TMyCollection.Clone : TMyCollection;
Var i : Cardinal; Begin Result := TMyCollection.Create; // <Copy Attributes> For i:=0 to Count- 1 do Result.Add (Items[i].Clone); End; |
Re: Objekt kopieren
Ach du meine Güte ist das kompliziert. :roll: Na ja gut, dann werde ich mir das mal angucken. Ich arbeite hier übrigens mit dem BDS2006, falls das weiterhilft.
|
Re: Objekt kopieren
Nö. Auch nicht komplizierter, als bei Off-Topic Posts einzugreifen, hinrlose Beiträge zu löschen, ausgewogen zu moderieren und BDS 2006 zu bedienen.
Ich präferiere selbstgefrickeltes, weswegen ich die Clone-Variante implementiert habe. Ich denke aber, mit TPersistent und eín paar Stunden reinfriemeln kommst Du klar. Ist eine ziemlich coole Angelegenheit. |
Re: Objekt kopieren
Ein anderer Weg:
Ich implementiere bei vielen Objekten die Routinen LoadFromStream & SaveToStream. Die kann man dann natürlich hervorragend nutzen, um mittels MemoryStream ein Assign zu implementieren... Cu, Udontknow |
Re: Objekt kopieren
Mein Problem ist, ich habe in einer Liste Komponenten vom Typ TImage. Diese werden jetzt auf der Form dargestellt. Um sie aber darstellen zu können, müssen sie erst noch entsprechend skaliert werden. Wenn ich diese TImage-Komponenten jetzt aber skaliere, sind sie dann auch in der Liste skaliert. Das heißt beim nächsten Anzeigen, werden sie noch mal skaliert, so dass sie immer kleiner werden und nicht nur das, in der Liste sollen sie natürlich in ihrer original Größe verbleiben. Was aber natürlcih nicht der Fall ist, da ich eben nur mit Zeigern arbeite.
Jetzt dachte ich mir, ich kopiere die Liste mit den Komponenten, skaliere sie und zeige sie an, so dass die original Komponenten unberührt davon bleiben. Soweit der Plan. Aber an der Ausführung hapert es eben noch etwas. ;) |
Re: Objekt kopieren
Das verstehe, wer will. Wozu willst Du die Images skalieren? Reicht es nicht, zu wissen, wie groß sie werden würden? Das sollte über ein Array of TRect doch gut zu machen sein...
|
Re: Objekt kopieren
Ganz einfach. Das Image hat Din-A4 Größe oder was auch immer. Das kann ich natürlich nicht auf dem Bildschirm darstellen, weil zu groß. Deswegen muss ich es runterskalieren. Da die Images aber Objekte in einer Liste sind, verändere ich sie für immer, wenn ich sie anzeige und das soll / darf nicht sein.
Ich habe es jetzt so gelöst, dass ich sie mit der gleichen Funktion wieder zurückskaliere. Nicht schön, aber geht. ;) |
Re: Objekt kopieren
Also wenn ich ein Bild habe, das ich irgendwie modifiziere, dann mach ich das so, dass ich einen Buffer habe (TBitmap) wo das Original noch drauf ist. Weiß nicht ob das in dein Programm reinpasst...
|
Re: Objekt kopieren
Zitat:
Beim Runterskalieren gehen Bildinformationen verloren - die beim Hochskalieren nicht wieder zurückgewonnen werden können. Grüße Klaus |
Re: Objekt kopieren
Hallo probier das doch mal mit Image1.Stretch:=True; aus. vom Typ TImage.
Vorher musst du halt noch die Breite und Höhe des Images festlegen. Image1.Width=300; Image1.Height=300; Als Beispiel |
Re: Objekt kopieren
Zitat:
|
Re: Objekt kopieren
Das Kopieren von Objekten findet über die Methode Assign statt!
Dazu muss das Zielobjekt von TPersistent abgeleitet sein. Die Assign-Methode hat immer folgenden Aufbau:
Delphi-Quellcode:
Der Copy-Constructor ist der schnelle Ersatz für folgenden Code:
procedure TVerpackung.Assign(Source: TPersistent);
begin if Source is TVerpackung then begin FIdVerp := TVerpackung(Source).IdVerp; FBezeichnung := TVerpackung(Source).Bezeichnung; FVLength := TVerpackung(Source).VLength; FVHeight := TVerpackung(Source).VHeight; FVWidth := TVerpackung(Source).VWidth; FTara := TVerpackung(Source).Tara; FPicture.Assign(Source); // Unterobjekt kopieren ... end else // Ganz wichtig: // wenn ich die Klasse von "Source" nicht kenne, // dann immer inherited aufrufen // Könnte sein, dass ein Parentklasse die Zuweisung vornehmen kann // falls nicht, hat die VCL noch einen Supertrick in der Hinterhand // es wird die Methode AssignTo aufgerufen // falls dies auch fehlschlägt, gibt's ein Exception inherited; end;
Delphi-Quellcode:
Der Copy-Constructor macht dann Sinn, wenn in .Create viele Properties zugewiesen werden,
objA := TEinObjekt.Create;
objA.Assign(objB); nur um dann in .Assign überbügelt zu werden. Ganz allgemein ist aber die Assign-Methode wertvoller, da mit ihr auch Objekte unterschiedlicher Klassen kopiert werden können. Wenn ein Objekt UnterObjekte hat, dann gibt es zwei Varianten: 1.) nur Hauptobjekt wird kopiert. Bei den Unterobjekten werden nur Referenzen kopiert (2 Zeiger auf's gleiche Objekt) 2.) "Deep-Copy": auch die Unterobjekte werden sauber über Assign kopiert. Alle Objekte sind nun völlig unabhängig voneinander.
Delphi-Quellcode:
Es wäre nun zu prüfen, ob TObjectList.Assign einen Depp-Copy ausführt.
constructor TPageCollection.Create(pc: TPageCollection);
begin inherited Create; FInnerList := TList.Create; // die TList-Klasse weiss nicht, dass seine Items Objekte sind // also wird hier kein "Deep-Copy" ausgeführt FInnerList.Assign(pc.FInnerList); |
Re: Objekt kopieren
Hi shmia, siehe meinen Beitrag #4 (1. Zeile). Aber Du hast es wunderbar erklärt :thumb:
|
Re: Objekt kopieren
Zitat:
Cu, Udontknow |
Re: Objekt kopieren
Ich brauche jetzt doch eine Kopie der Objekte in der Collection. Deswegen habe ich alzaimars Clone-Methode versicht zu implementieren:
Zitat:
|
Re: Objekt kopieren
Ist Assign (wie zuvor von shmia geschrieben) nicht eine notwendige Funktion für jedes TCollectionItem (was ja imho von TPersist kommt)?
Sprich:
Delphi-Quellcode:
Vorausgesetzt Dein Assign dort funktioniert vernünftig natürlich ;)
For i := 0 to Pred(Count)
do Result.Add.Assign(Items[i]); |
Re: Objekt kopieren
So wie ich ihn verstanden habe sollte man seine Methode benutzen können um Objekte vom Typ TObject kopieren zu können.
Was meinst du mit: Zitat:
|
Re: Objekt kopieren
Weil man bei Collections soviel tippen muss (eben auch das Assign), hatte ich mir ja
![]() Ein Beispiel, weil ein Assign zu implementieren ist, hat shmia ja in Post #15 stehen (in obigem Link ebenfalls eins). Die "Herausforderung" bei Collections ist da halt immer, daß man, wenn man neue Properties hinzufügt, gerne mal vergisst, auch das Assign zu aktualisieren - dort musst Du halt selber von Hand eine Kopie jeder kopiergewünschten Eigenschaft anlegen (das automatisch machen zu lassen kann imho nicht funktionieren, da es z.B. bei Zeigern auf Objekten je nach Code drumherum darauf ankommen würde, ob man etwa eine TStringList ebenfalls mit Assign auf die neue kopiert, oder nur den Zeiger selber kopiert, wenn er etwa auf ein spezielles externes Objekt zeigt). Warum alzaimar da jetzt eine zusätzliche "Clone"-Methode hat, kann ich mir nur so halb vorstellen, da sie halt auch nicht irgendwie automatisierter laufen kann (imho), und zudem genau dasselbe erledigen soll, was Assign macht - nur daß der Aufruf (Rückgabewert & Parameter) vertauscht ist. |
Re: Objekt kopieren
Zitat:
|
Re: Objekt kopieren
Puh, ich steige da nicht mehr durch. :wall:
Delphi-Quellcode:
So sieht meine Klasse aus. Und davon brauche ich eine Kopie mitsamt der inneren Liste. Was muss ich jetzt konkret wie und wo implementieren, damit man davon eine Kopie erstellen kann?
TPageCollection = Class(TObject);
private FInnerList: TList; x: Double; // ...; // ...; public procedure Add; // ...; // ...; end; procedure TPageCollection.Add(Item: TImageEnVect); begin FinnerList.Add(Item); end; |
Re: Objekt kopieren
Leider kennen die TImages keine eigene Assign-Methode, von daher müsstest Du auch das Kopieren der Eigenschaften Deiner Images von Hand machen. Am Einfachsten wäre es natürlich, wenn Du anstatt einer TList als innerList eine TImagelist verwendest, die kann das nämlich von alleine.
Wenn Du Dir genau ansehen willst, was Du "von Hand" machen musst, um die TList zu kopieren, dann solltest Du Dir das TImagelist.Assign mal ansehen, das könntest Du dann relativ einfach für Deine Liste übernehmen. |
Re: Objekt kopieren
Zitat:
Delphi-Quellcode:
Cu,
Function TMyCollection.Clone : TMyCollection;
Var i : Cardinal; Begin Result := TMyCollection.Create; // <Copy Attributes> For i:=0 to Count- 1 do Result.Add (TMyCollectionItem(Items[i]).Clone); End; Udontknow |
Re: Objekt kopieren
Liste der Anhänge anzeigen (Anzahl: 1)
@Udontknow: Meine Item-Klasse ist vom Typ TList:
Delphi-Quellcode:
oder meinst du den Typ der Objekte in der Liste? Die sind vom Typ TImageEnvect (so was wie ein TImage) und kennt die Methode Assign (falls das hilft).
TPageCollection = Class(TObject);
private FInnerList: TList; x: Double; // ...; // ...; public procedure Add; // ...; // ...; end; Lösen wir uns mal von dem TImage. Ich habe eben mal schnell eine Demo erstellt:
Delphi-Quellcode:
Wie stelle ich jetzt eine Kopie von TKontaktCollection her mitsamt der inneren List? Das ist das Problem. Den bisherigen Code hab eich leider nicht ganz verstanden, weil es doch irgendwie immer etwas durcheinander ging.
unit Adressen;
interface uses Classes; type TKontakt = class(TObject) private FName: String; FAlter: Integer; function GetAlter: Integer; function GetName: String; procedure SetAlter(const Value: Integer); procedure SetName(const Value: String); public property Name: String read GetName write SetName; property Alter: Integer read GetAlter write SetAlter; end; TKontaktCollection = class(TObject) private FInnerList: TList; function GetItem(Index: Integer): TKontakt; procedure SetItem(Index: Integer; const Value: TKontakt); public constructor Create; destructor Destroy; override; procedure Add(Item: TKontakt); function Count: Integer; property Items[Index: Integer]: TKOntakt read GetItem write SetItem; end; implementation { TKontakt } function TKontakt.GetAlter: Integer; begin Result := FAlter; end; function TKontakt.GetName: String; begin Result := FName; end; procedure TKontakt.SetAlter(const Value: Integer); begin FAlter := Value; end; procedure TKontakt.SetName(const Value: String); begin FName := Value; end; { TCollection } procedure TKontaktCollection.Add(Item: TKontakt); begin FInnerList.Add(Item); end; function TKontaktCollection.Count: Integer; begin Result := FInnerLIst.Count; end; constructor TKontaktCollection.Create; begin inherited; FInnerList := TLIst.Create; end; destructor TKontaktCollection.Destroy; var i : Integer; begin if FInnerList.Count > 0 then begin for i := FInnerList.Count - 1 to 0 do begin TObject(FInnerList.Items[i]).Free; end; end; inherited; end; function TKontaktCollection.GetItem(Index: Integer): TKontakt; begin Result := FInnerList.Items[Index]; end; procedure TKontaktCollection.SetItem(Index: Integer; const Value: TKontakt); begin FInnerList.Items[Index] := Value; end; end. (Im Anhang das gesamte Projekt.) |
Re: Objekt kopieren
Hier die zwei notwendigen Methoden, allerdings ungetestet und ohne, dass ich mir das Projekt angesehen habe:
Delphi-Quellcode:
procedure TKontakt.Assign(Source: TKontakt);
begin Name := Source.Name; Alter := Source.Alter; end; procedure TKontaktCollection.Assign(source: TKontaktcollection); var i: Integer; kontakt: TKontakt; begin clear; for i := 0 to source.count-1 do begin kontakt := Add(TKontakt.Create); kontakt.Assign(source.Items[i]); end; end; |
Re: Objekt kopieren
Liste der Anhänge anzeigen (Anzahl: 1)
Ich glaube ich habs:
Delphi-Quellcode:
Und:
procedure TKontakt.Assign(Source: TKontakt);
begin Name := Source.Name; Alter := Source.Alter; end;
Delphi-Quellcode:
Der Test:
procedure TKontaktCollection.Assign(Source: TKontaktCollection);
var i: Integer; kontakt: TKontakt; begin for i := 0 to source.count-1 do begin kontakt := TKontakt.Create; kontakt.Assign(source.Items[i]); Add(kontakt); end; end;
Delphi-Quellcode:
und:
procedure TForm1.Button2Click(Sender: TObject);
var TempCollection: TKontaktCollection; i: Integer; begin TempCollection := TKontaktCollection.Create; try TempCollection.Assign(Adressen); for i := 0 to TempCollection.Count - 1 do begin TempCollection.Items[i].Name := TempCollection.Items[i].Name + ' ist doof.'; ListBox2.Items.Add(TempCollection.Items[i].Name); end; finally TempCollection.Free; end; end;
Delphi-Quellcode:
Die TempCollection wird am Ende der Procedure ja freigegeben. Wären jetzt nur Pointer in der Liste, würde Prozedur UpdateLB1 gar nichts mehr ausgeben - tut sie aber. Ergo wurden die Objekte kopiert und nicht nur die Pointer. Oder sehe ich das falsch?
procedure TForm1.UpdateLB1;
var i: Integer; begin Listbox1.Clear; for i := 0 to Adressen.Count - 1 do ListBox1.Items.Add(Adressen.Items[i].Name + ', ' + IntToStr(Adressen.Items[i].Alter)); end; Im Anhang das ganze Projekt. |
Re: Objekt kopieren
Zitat:
Delphi-Quellcode:
procedure TKontakt.Assign(Source: TPersistent);
begin if Source is TKontakt then begin Name := TKontakt(Source).Name; Alter := TKontakt(Source).Alter; end // weitere (fiktive) Klasse, die zugewiesen werden könnte else if Source is TPerson then begin Name := TPerson(Source).FirstName + ' ' + TPerson(Source).LastName; Alter := round((now - TPerson(Source).BirthDate) / 365.0); end // Wichtig!! wenn mir die Source-Klasse nicht bekannt ist, inherited aufrufen else inherited; end; |
Re: Objekt kopieren
Jupp. Es fehlen zwei Zeilen (Source is TKontakt und inherited), das habe ich mir mal schnell gespart, da eh nichts anderes da ankommen kann. ;)
Aber ich habe das dumpfe Gefühl bei meiner TIMageEnVect-Komponente kopiert Assign nichts, so dass ich alles selber von Hand kopieren muss. :? |
Re: Objekt kopieren
Zitat:
Denk an den *Supertrick* der VCL falls Assign nicht fruchtet die AssignTo-Methode aufzurufen. Ohne das inherited kann der Trick nicht funktionieren. Zitat:
|
Re: Objekt kopieren
Zu mindest kommt zum Beispiel die Breite nur korrekt an, wenn ich sie explizit zuweise. :?
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:59 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz