AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Komponente aus Array löschen

Ein Thema von DeathsShadow · begonnen am 11. Jun 2010 · letzter Beitrag vom 13. Jun 2010
Antwort Antwort
DeathsShadow

Registriert seit: 26. Apr 2008
22 Beiträge
 
#1

Komponente aus Array löschen

  Alt 11. Jun 2010, 11:56
Hallo

das Thema klingt simpel und wurde z.B. für Arrays of Integer schon sehr oft beantwortet, jedoch stellt es sich nicht ganz so leicht dar, weil meine Elemente initialisierte Komponenten sind. Folgendes Problem:

Ich habe in ein dynamisches Array of TShape wobei dessen Elemente während der Laufzeit manuell erstellt werden können. Den Elementen ist ein Popupmenu (Popupmenu2) zugeordnet, welches u.a. zum löschen eines Elements dient. Die Position des Elements im Array, wird dabei über den Tag bestimmt.

Nun möchte ich gerne ein Element an einer beliebigen Stelle löschen, wobei alle anderen Elemente im Array aufrücken müssen. Die Lösung über eine List ist aufgrund des restlichen Programmes leider nicht möglich. Hier ein Ansatz der (nicht funktioniert wobei er jedoch) meine Idee verdeutlicht.

Delphi-Quellcode:
  [...]

var
  Form1: TForm1;
  Btns : Array of TShape;

  [...]

procedure TForm1.Lschen2Click(Sender: TObject);
var i, Helper : Integer;
begin
  Helper := Popupmenu2.PopupComponent.Tag; //Wo ist das zu löschende Shape im Array

  [...]

  for i := helper to length(btns)-2 do //Alle Elemente um eins vorrücken(Das zu löschende SOLL überschreiben werden)
  begin
  btns[i] := btns[i+1];
  end;
  
  btns[length(btns)-1].Free; //letztes (doppeltes) Element wird gelöscht
  setlength(btns,length(btns)-1);
  
  for i := 0 to length(btns)-1 do btns[i].Tag := 1; // Tag wird wieder Position im Array

end;

[...]

end.
Ich hoffe auf eure Hilfe!

lg Flo
Florian S.
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#2

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 13:36
Viele Programmierer versuchen Objekte, Komponenten und Controls in Arrays zu speichern,
obwohl es viel geeignetere Datenstrukturen gibt.

Zitat:
Die Lösung über eine List ist aufgrund des restlichen Programmes leider nicht möglich
Dann solltest du das ändern!
Arrays sind low-Level Datenstrukturen.
Je anspruchsvoller die gewünschte Funktionalität eines Programms wird umso höherwertiger müssen auch die Datenstrukturen werden.

Z.B. bringt die Klasse TComponent schon alles mit was du brauchst.
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    ShapeList : TComponent; // Liste von Shapes
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   ShapeList := TComponent.Create(Self);
end;
Wichtig zu wissen: ShapeList wird automatisch freigegeben, wenn das Formular freigegeben wird.
Und ausserdem werden alle Shapes in der Liste ebenfalls automatisch freigegeben.

So kann man z.B. ein neues Shape hinzufügen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
   newshape : TShape;
begin
   newshape := TShape.Create(ShapeList);
   newshape.Left := random(300);
   newshape.Top := random(300);
   newshape.Parent := Self;
end;
Um ein bestimmes Shape anhand des Tag zu finden und zu löschen:
Delphi-Quellcode:
procedure TForm1.DeleteShapeByTag(ATag:integer);
var
   c : TControl;
   i : integer;
begin
   for i := ShapeList.ComponentCount-1 downto 0 do
   begin
     c := ShapeList.Components[i];
     if c.Tag=ATag then
     begin
       // Shape löschen
       c.Free;
       // die ShapeList wird im Hintergrund automatisch korrigiert
       // d.h. ComponentCount verringert sich um eins
     end;
   end;
Anstatt in dem Tag des PopupMenue die Position in der Liste zu speichern, kann man auch gleich das Shape selbst speichern.
Andreas
  Mit Zitat antworten Zitat
DeathsShadow

Registriert seit: 26. Apr 2008
22 Beiträge
 
#3

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 16:24
Danke für die Antwort, jedoch existieren dabei 3 Probleme.

Das erste ist, dass der Code einen sehr wichtigen Fehler enthält, so ist der Rückgabewert an c
c := ShapeList.Components[i];
vom Typ TComponent nicht von TControl.
c : TControl;
Ändert man dies und ersezt es durch TComponent und versucht ein Element zu löschen so kommt man zum zweiten Problem, es sind 2 Fälle möglich:

Fall1:
Man löscht Shape mit dem Index 0, dann werden alle Shapes gelöscht.

Fall2:
Man löscht ein Shape größer als Null, dann passiert nichts.


So ... das dritte und das schwerwiegenste Problem ist, dass ich selbst weiß wie es anders geht, jedoch wollte ich wissen wie es mit array funktioniert.



PS: Ist nicht böse gemeint, ich hoffe jemand hat noch eine Idee!
Florian S.
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.771 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 16:56
Hallo,

wenn es denn unbedingt mit Arrays sein soll,
würde ich so vorgehen:

Shape aus dem Ursprungsarray löschen.
Position auf nil setzen.

Neues Array erstellen mit der Länge des Ursprungsarrays -1.
Alle Elemente <> nil in das neue Array kopieren.
Ursprungsarray löschen.

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 17:05
Warum mit zwei Arrays arbeiten? Einfach alle nachfolgenden Elemente um eins nach vorne kopieren. Vorher aber das zu löschende Objekt freigeben. Und danach natürlich das Array um ein Element verkürzen.
Muss die Sortierreihenfolge nicht erhalten bleiben, kann man auch das letzte Element an die Stelle des zu löschenden Elementes kopieren.
Michael
Ein Teil meines Codes würde euch verunsichern.

Geändert von Luckie (11. Jun 2010 um 17:12 Uhr)
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#6

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 17:15
jedoch wollte ich wissen wie es mit array funktioniert.
Wenn im Array ein "Loch" entsteht, dann muss man halt die Elemente zusammenschieben.
Man kann das mit einer Schleife machen.
Hardcore - Programmierer setzen hier auch die Procedure Move ein.
Delphi-Quellcode:
procedure RemoveElementFromArray(a : Array of TShape; idx:integer);
var
  i : integer;
begin
  Assert(idx >= 0);
  for i := idx to High(a)-1 do
  begin
    a[idx] := a[idx+1];
  end;
  SetLength(a, Length(a)-1); // Array verkürzen
end;
Anschliesend musst du wohl auch noch noch die Tag-Werte von deinem Popupmenu korrigieren.
Delphi-Quellcode:
for i := 0 to Popupmenu2.Items.count-1 do
begin
  if Popupmenu2.Items[i].Tag >= Helper then
     Popupmenu2.Items[i].Tag := Popupmenu2.Items[i].Tag -1;
end;
Ich kann nur sagen, dass du so einen hässlichen Sourcecode bekommst.

Würdest du meinen Vorschlag annehmen, dann sähe das Löschen so aus:
Delphi-Quellcode:
procedure TForm1.Lschen2Click(Sender: TObject);
var
  mi : TMenuItem;
  c : TComponent;
begin
  mi := Sender as TMenuItem;
  // im Tag des Menuitems steckt die Verbindung zum Shape
  c := TComponent(mi.Tag);
  if not Assigned(c) then
     Exit;
  c.Free; // Shape wird gelöscht und automatisch auch aus ShapeList entfernt
Andreas
  Mit Zitat antworten Zitat
DeathsShadow

Registriert seit: 26. Apr 2008
22 Beiträge
 
#7

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 17:29
@Klaus: Nette Idee aber eher die brachiale methode ^^

@Luckie: Guck dir mal an, was ich gemacht hab. Oder was meinst du?

@shima: Vielen Danke, aber bei deinem Vorschlag zum Thema Array, wird das Elemten was zu löschen ist, aus dem Array entfernt, aber nicht gelöscht. Das letzte Element im Array wird auch aus dem Array entfernt, jedoch auch nichts gelöcht. Hab ich mich vielleicht vertippt? Kannst du das bitte selbst probieren ob es bei dir klappt?


lg
Florian S.
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.771 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 18:00
.. schon mal überlegt was diese Zeile macht?

 for i := 0 to length(btns)-1 do btns[i].Tag := 1; // Tag wird wieder Position im Array Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von x000x
x000x

Registriert seit: 21. Jan 2004
Ort: Bei Hamburg
308 Beiträge
 
Delphi XE2 Professional
 
#9

AW: Komponente aus Array löschen

  Alt 11. Jun 2010, 18:22
Moin moin,

ich würde auch Shimas Methode bevorzugen...
Delphi-Quellcode:
type
   TShapeArr = Array of TShape;
//..
procedure RemoveElementFromArray(var a : TShapeArr; Idx: Integer);
var
  I, x: Integer;
begin
   x := Length(a);
   if x > 0 then begin
      Assert((idx >= 0) and (idx < x));
      a[idx].Free;
      for I := Idx to x-2 do begin
         a[I] := a[Succ(I)];
      end;
      SetLength(a, x -1);
   end;
end;
So sollte es aber funktionieren.
Peter
-= Gruss Peter =-
-= alias x000x =-
  Mit Zitat antworten Zitat
Benutzerbild von xZise
xZise

Registriert seit: 3. Mär 2006
Ort: Waldbronn
4.303 Beiträge
 
Delphi 2009 Professional
 
#10

AW: Komponente aus Array löschen

  Alt 13. Jun 2010, 10:39
Moin,
warum gibst du das letzte Element frei? Nicht der Inhalt sondern die Referenz wird bei der Aktion kopiert.
Das heißt die letzten beiden Einträge zeigen (vor den .Free) auf das gleiche Element. Durch das freigeben, wir das letzte Element aber freigegeben und zwar das letzte Element für „beide“ Arrays (also bevor du es verkürzt: Das letzte (was du evtl. willst) und das vorletzte (was du bestimmt nicht willst)).

Und warum setzt du den Tag für jedes Shape auf 1? Und auf das Popupmenü bekommt kein neues Tag, soll das so sein? Außerdem gibst du nicht (!) das gelöscht Element frei. Das verschwindet ins Nirvana, weil du einfach die Referenz mit den nachfolgenden Element überschreibst.

Das heißt, einfach Luckies Rat folgen und:
[...]Vorher aber das zu löschende Objekt freigeben.[...]
Interessant finde ich diesen Hinweis:
[...]Muss die Sortierreihenfolge nicht erhalten bleiben, kann man auch das letzte Element an die Stelle des zu löschenden Elementes kopieren.
Das ist noch einfacher zu implementieren.

MfG
Fabian
Fabian
Eigentlich hat MS Windows ab Vista den Hang zur Selbstzerstörung abgewöhnt – mkinzler
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:11 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz