Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   TObjectList Problem (https://www.delphipraxis.net/164893-tobjectlist-problem.html)

Dennis07 5. Dez 2011 08:47

TObjectList Problem
 
Hallo Leute,
ich hoffe dass ich hier richtig liege, ist ja mehr oder weniger wie ein 6er im Lotto zu wissen wo genau hier ein beitrag reingehört.
Also nun zu meinem Problem:
Ich muss ein Programm schreiben dass Panels zur Laufzeit erstellt und per Knopdruck wieder alle brav entfernt.
Das mit dem Erstellen ist ja kein Problem, habe ich mit NewPanel := TPanel.Create. Erst bei der 2. Frage fängt es an zu Hacken...
Ich habe mich entschlossen, für das Löschen der Panels eine TObjectList direkt zum Programmstart zu erstellen, in die ich alle erstellen Panels einordne. Wie ich die Panels lösche, zu dem Problem bin ich nicht einmal gekommen, denn es hackt bereits hier:
Aus irgenteinem Grund listet der die Neu erstellen Panels nicht in die Liste ein (k.a.wieso, wharcheinlich habe ich nur irgentetwas dummes übersehen. Hier mal schnell alles, was euch hierzu interessieren könnte:

Delphi-Quellcode:
var
  NewPanel: TPanel;
  PanelID: Integer = 1;
  PanelsList: TObjectList;
  { ... }

procedure TfmPool.FormCreate(Sender: TObject);
begin
  PanelsList := TObjectList.Create;
  { ... }
end;

procedure SpawnPanel(PanelX,PanelY: Integer);
begin
  NewPanel := TPanel.Create(Application);
  PanelsList.Add(NewPanel);
  with NewPanel do
  begin
    Name := 'Panel' + IntToStr(PanelID);
    PanelID := PanelID + 1;
    Left := PanelX;
    Top := PanelY;
    Caption := ObjectCaption;
    Parent := fmPool;
    Enabled := False;
    { ... }
    OnClick := fmPool.SelectObject;
  end;
end;

procedure TfmPool.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  PanelsList.Free;
end;
Anzuumerken wäre vielleicht, dass keine Fehlermeldung erscheint.
Vielen Dank
--Dennis

DeddyH 5. Dez 2011 09:01

AW: TObjectList Problem
 
Soll heißen, die Liste bleibt leer? Wieso verwendest Du übrigens globale Variablen, die sind doch gar nicht nötig. Und wenn Du die Panels eh in die Objektliste einfügst, musst Du auch keinen Owner angeben.

Sir Rufo 5. Dez 2011 09:18

AW: TObjectList Problem
 
Er fügt die Panels doch in die Liste ein, oder was macht
Delphi-Quellcode:
PanelsList.Add(NewPanel);
:gruebel:

Wie kommst du darauf, dass die nicht in der Liste stehen?

BTW: Da du ja anscheinend eine eindeutige ID für die Panels benötigst, würde ich ja schon eher eine TCollection vorschlagen, da wird die ID gleich mitproduziert

DeddyH 5. Dez 2011 09:21

AW: TObjectList Problem
 
Gab es TCollection schon unter Delphi 5? Oder stimmt die angegebene Delphi-Version nicht? Achja, eins noch: wenn man die Objekliste im FormCreate anlegt, sollte man sie im FormDestroy freigeben und nicht im FormClose. Sonst kann es passieren, dass man darauf zugreift, obwohl sie bereits entsorgt wurde.

Codewalker 5. Dez 2011 09:39

AW: TObjectList Problem
 
Und nicht vergessen: TObjectList hat ein Property namens OwnsObjects (wird im Constructor gesetzt). Ist es true (standard), dann werden beim Löschen der Object-List auch alle noch enthaltenen Objekte automatisch freigegeben.

DeddyH 5. Dez 2011 09:47

AW: TObjectList Problem
 
Nicht nur beim Löschen der Liste selbst, sondern auch beim Löschen von Elementen aus der Liste.

Gollum 5. Dez 2011 10:10

AW: TObjectList Problem
 
Hallo,

die Variable NewPanel darf nicht global sein, sondern sie muss lokal in der Procedure SpawnPanel deklariert werden.

DeddyH 5. Dez 2011 10:18

AW: TObjectList Problem
 
Wieso denn das? Es ist zwar nicht schön so wie im Moment, aber darf und muss ist IMHO die falsche Wortwahl.

Dennis07 5. Dez 2011 12:40

AW: TObjectList Problem
 
Zitat:

Soll heißen, die Liste bleibt leer?
Genau.

Zitat:

Wieso verwendest Du übrigens globale Variablen, die sind doch gar nicht nötig.
Ich habe euch nur einen kleinen Teil des Codes gegeben. Ich brauche sie noch in anderen Procedures, ist aber hier nicht relevant (deswegen euch erspart).

Zitat:

Und wenn Du die Panels eh in die Objektliste einfügst, musst Du auch keinen Owner angeben.
Danke, das wusste ich nicht.

Zitat:

Gab es TCollection schon unter Delphi 5?
Keine Ahrnung. Worauf willdst du hinaus (kenne diese Klasse nicht, sry)?

Zitat:

Wieso denn das? Es ist zwar nicht schön so wie im Moment, aber darf und muss ist IMHO die falsche Wortwahl.
Ich denke auch, das dürfte doch keinen Unterschied machen, oder?

DeddyH 5. Dez 2011 12:42

AW: TObjectList Problem
 
Das mit TCollection bezog sich auf Sir Rufos Post. Wie stellst Du denn fest, dass die Liste leer bleibt? Fragst Du testhalber die Anzahl der Elemente ab?

Dennis07 5. Dez 2011 12:48

AW: TObjectList Problem
 
Bingo.... das erschien mir die einfachste möglichkeit zu prüfen, warum der auf jegliche kommandos, die ich der OL zugewiesen habe (wie beispielsweise das Löschen von Objekten oder das freigeben der Liste) nicht reagiert hat.
Ich habe also (mithilfe meines besten freundes Showmessage()) mir anzeigen lassen, dass ich zum zeitpunkt, wo sich (beispielsweise) 5 Panels auf dem Formular befinden, sich jedoch 0 in meiner OL befinden. Darum hier die Frage: Was mache ich falsch?

PS: Wenn ich bei meinen Profileinstellungen D5 angebe dann lässt sich daraus schließen dass ich auch D5 benutze.

Dankeschön;

Sir Rufo 5. Dez 2011 12:58

AW: TObjectList Problem
 
Da ShowMessage dein Freund ist:
Delphi-Quellcode:
procedure SpawnPanel(PanelX,PanelY: Integer);
begin
  NewPanel := TPanel.Create(Application);
  ShowMessage( IntToStr( PanelsList.Count ) );
  PanelsList.Add(NewPanel);
  ShowMessage( IntToStr( PanelsList.Count ) );
  with NewPanel do
  begin
    Name := 'Panel' + IntToStr(PanelID);
    PanelID := PanelID + 1;
    Left := PanelX;
    Top := PanelY;
    Caption := ObjectCaption;
    Parent := fmPool;
    Enabled := False;
    { ... }
    OnClick := fmPool.SelectObject;
  end;
end;
Was zeigt bekommst du mit ShowMessage denn da angezeigt?
Oder wird dieses ShowMessage evtl. gar nicht aufgerufen?

DeddyH 5. Dez 2011 13:04

AW: TObjectList Problem
 
Ich hab das jetzt mal unter Delphi 2007 so versucht:
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FPanels: TObjectList;
    FPanelID: integer;
    procedure SpawnPanel(PanelX, PanelY: integer);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  SpawnPanel(10, 10);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FPanels.Clear;
  FPanelID := 1;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FPanels := TObjectList.Create;
  FPanelID := 1;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FPanels.Free;
end;

procedure TForm1.SpawnPanel(PanelX, PanelY: integer);
var
  NewPanel: TPanel;
begin
  NewPanel := TPanel.Create(nil);
  NewPanel.Left := PanelX;
  NewPanel.Top := PanelY;
  NewPanel.Parent := self;
  NewPanel.Name := 'Panel' + IntToStr(FPanelID);
  FPanels.Add(NewPanel);
  ShowMessage(IntToStr(FPanels.Count));
  inc(FPanelID);
end;
Klappt einwandfrei, soweit ich feststellen konnte.

Dennis07 5. Dez 2011 13:10

AW: TObjectList Problem
 
Zitat:

Zitat von Sir Rufo (Beitrag 1139460)
Da ShowMessage dein Freund ist:
Was zeigt bekommst du mit ShowMessage denn da angezeigt?
Oder wird dieses ShowMessage evtl. gar nicht aufgerufen?

Selbstverständlich qwird showmmesage aufgerufen. Beim ersten kommt (wieso auch anders) 0. Was mich allerdings völlig unerwartet trifft:
Beim zweiten kommt 1!

Hallo leute... habe gerade bemerkt dass ich den Showmessage unten falsch platziert habe, wewegen immer 0 rauskam. Das war zwar ein fehler meiner prüfung, aber den Fehler des Programms habe ich noch nicht gefungen.
Zum ersten: Ich brauche sehr wohl ein Parent, sonst wird der Panel nicht angezeigt.
Und wieso wird der Panel nicht gelöscht, wenn er doch in der liuste ist und diese freigegeben wird?
Danke

DeddyH 5. Dez 2011 13:20

AW: TObjectList Problem
 
Natürlich brauchst Du einen Parent, aber keinen Owner (richtig lesen!).

Dennis07 5. Dez 2011 13:30

AW: TObjectList Problem
 
Jaja is ja gut habe ich auch im nachhinein gemerkt. Wollte es nur bei einer Bearbeitung meiner Post lassen....

mfg

EDIT: Wie soll das gehen.. ich erhalte immer eine Fehlermeldung (nicht genügend parameter).... egal ich google man danach trotzdem bis hierhin danke.... jetzt muss ich nur noch das wesentliche problem lösen

DeddyH 5. Dez 2011 13:31

AW: TObjectList Problem
 
Hast Du mein Beispiel von oben einmal ausprobiert? Verhält es sich dort genauso?

Dennis07 5. Dez 2011 13:45

AW: TObjectList Problem
 
Nein noch nicht... mache ich morgen .... man schreibt sich.... danke aber schonmal für die Hilfe ;)

bd

himitsu 5. Dez 2011 15:28

AW: TObjectList Problem
 
Zitat:

Zitat von DeddyH (Beitrag 1139425)
Wieso denn das? Es ist zwar nicht schön so wie im Moment, aber darf und muss ist IMHO die falsche Wortwahl.

Ruft doch einmal die Funktion(en) gleichzeitig auf, welche die selbenglobale Variable nutzen.
Muß nicht gleich multithread sein ... rekursive Aufrufe reichen schon aus.

Variablen muß man also immer so nah wie möglich an deren Verwendungsort, bzw. an deren Gültigkeitsbereich deklarieren.

DeddyH 5. Dez 2011 15:32

AW: TObjectList Problem
 
Wo siehst Du in dem geposteten Code eine Rekursion? Dass die globalen Variablen alles andere als schön sind, wurde ja bereits gesagt und eine Alternative von mir gezeigt.

Dennis07 5. Dez 2011 18:58

AW: TObjectList Problem
 
Zitat:

Zitat von DeddyH (Beitrag 1139501)
Wo siehst Du in dem geposteten Code eine Rekursion? Dass die globalen Variablen alles andere als schön sind, wurde ja bereits gesagt und eine Alternative von mir gezeigt.

"Muss" ich es ändern oder nicht? Ich brauche globale Variablen, ansonsten, soviel könnt ihr mir ruhig zutrauen, würde ich sie nicht verwenden (ich finde ebenfalls, sie machen einen Quelltext extrem unübersichtlich, aber manchmal kommt man nicht, oder nur über erhebliche umwege, um sie herum).
Mir ist außerdem nicht bewusst, warum NewPanel bzw. PanelsList Probleme machen sollte, sie werden doch nirgendwo sonst vom Compiler belegt oder definiert.

DeddyH 5. Dez 2011 19:08

AW: TObjectList Problem
 
Wie himi schon sagte, in einer Rekursion kann es Dir passieren, dass die Instanz überschrieben und somit unerreichbar für Dich wird.

[edit] Nebenbei haben globale Variablen den ganz dummen Nachteil, dass jeder, der Zugriff darauf hat, ungeprüft da rein schreiben kann, auch wenn oder wann man das eigentlich gar nicht möchte. [/edit]

himitsu 5. Dez 2011 19:30

AW: TObjectList Problem
 
Zitat:

Zitat von Dennis07 (Beitrag 1139542)
Ich brauche globale Variablen, ansonsten, soviel könnt ihr mir ruhig zutrauen, würde ich sie nicht verwenden

Nein, brauchst du nicht, das kannst du mir ruhig glauben, soviel könntest du mir ruhig zutrauen, sonst würde ich es nicht sagen. :roll:

Zitat:

Delphi-Quellcode:
  NewPanel: TPanel;
  PanelID: Integer = 1;
  PanelsList: TObjectList;
  { ... }

procedure TfmPool.FormCreate(Sender: TObject);
begin
  PanelsList := TObjectList.Create;



Der Wert von NewPanel wird nur in und wärend der Laufzeit von SpawnPanel verwendet, es wird also nur lokal genutzt, also gehört diese Variable auch lokal in SpawnPanel rein.

Die anderen Beiden werden "nur" innerhalb von TfmPool erstellt, verwaltet und freigegeben.
TfmPool ist also dafür zuständig und somit gehören sie auch in dessen Zuständigkeitsbereich.
- als Property, wenn noch extern drauf zugegriffen wird
- und/oder als private Felder

SpawnPanel erstellt die Panele sichtbar auf der Form, es beeinflußt also direkt diese Form und somit gehört auch dieses als Methode in diese TfmPool.
Dabei hat sich auch gleich das Problem mit der bösen globalen fmPool gelöst, denn nun hat SpawnPanel direkten Zugriff auf diese Form.

Wieso bekommt eigentlich das neue Panel die Application als Owner?
Es liegt doch schließlich auf der Form und nicht im Application.
Und jetzt wo SpawnPanel eh schon zur Form gehört, kann man diese Form auch gleich als Owner nutzen.


Wozu soll eigentlich die PanelsList gut sein?
Vermutlich doch nur, damit die Panele alle wieder freigegeben werden ... nichwa?
PS: Der Owner ist für die Freigabe zuständig.

Deine Form gibt nun im OnDestroy (wie schon gesagt, ist OnClose falsch ... siehe nächster Punkt) diese PanelsList und somit auch die Panele frei.
Wäre die Form der Owner, würde sie es auch von selber machen und die ganze PanelsList wäre vollkommen unnötig.

im OnCreate erstellt => im OnDestroy freigeben
im Open erstellen => im OnClose freigeben
im OnShow erstellen => im OnHide freigeben
... fällt dir was auf?
Tipp: Gegensätze


PS: Wenn möglich verabschiede dich davon, diese globalen Form-Variablen zu verwenden, denn vor einer Weile hatte jemand mal mächtig Probleme damit.
... so als Beispiel, warum die böse sind ...

gegeben waren eine Form und darauf ein Edit
- leider wurde "ausversehn" die Form in der Projektdatei mehrfach erstellt
- die Form hatte, in der DFM, Visible als False stehen
- somit wirde nur die "MainForm" (also die Erste) angezeigt
- die nachfolgend erstellten Forms überschrieben aber alle diese globale Formvariabe, da sie ja ein Millisekündchen später erzeugt wurden.

Soooooooo

Man kann nun in diese Edit eingeben was man will,
in Form1.Edit1.Text stand und blieb immer der "Default-Wert" stehen, aus der DFM.
Genauso konnte man Form1.Edit1.Text zuweisen was man wollte ... das Angezeigte änderte sich nie.

Und nun rate mal warum?

Die angezeigt Form war nicht die, welche in der Globalen verlinkt war :stupid:

Dennis07 5. Dez 2011 20:26

AW: TObjectList Problem
 
Zitat:

Nebenbei haben globale Variablen den ganz dummen Nachteil, dass jeder, der Zugriff darauf hat, ungeprüft da rein schreiben kann, auch wenn oder wann man das eigentlich gar nicht möchte.
Hier irrelevant. Das Programm hat nur eine Form und wird auch nur einmal erzeugt.

Zitat:

Wozu soll eigentlich die PanelsList gut sein?
Vermutlich doch nur, damit die Panele alle wieder freigegeben werden ... nichwa?
Doch.

Zitat:

Deine Form gibt nun im OnDestroy (wie schon gesagt, ist OnClose falsch ... siehe nächster Punkt) diese PanelsList und somit auch die Panele frei.
Wäre die Form der Owner, würde sie es auch von selber machen und die ganze PanelsList wäre vollkommen unnötig.
Nun, das ist mir durchaus bewusst. Allerdings ist es nicht das, was ich will, bzw. nichts, wofür ich hilfe bräuchte. Was ich möchte, ist dass ALLE dieser Panels, die sich in der PanelsList-Objektliste befinden, per Knopfdruck gelöscht werden.

Zitat:

PS: Der Owner ist für die Freigabe zuständig.
Wofür ein Owner da ist weiß ich.

Zitat:

Und nun rate mal warum?
Soweit so gut, verstehe ich. Da ich kein "Visible" irgentwo, sowohl im Projekt, als auch in der (einzigen) Unit, irgentwo verwende, habe ich doch von da aus nichts zu befürchten. Außerdem funktionieren alle Anderen Globals auch einwandfrei....

Naja, das mit dem NewPanel kann ich ja mal Prozedurenbezogen machen und die Prozedur dann Formularbezogen. Mal sehen was rauskommt.
Danke auf jeden Fall schon mal für eure Hilfe ;)

Dennis07 7. Dez 2011 12:36

AW: TObjectList Problem
 
Hat alles geklappt....
Ich denke es lag an dem (gerade bemerkten) PanelsList.Clear....
ich dachte bisher ich müsse .Free verwenden....
Danke trotzdem für eure Unterstützung.....

Noch eine Frage hätte ich allerdings: Ist es möglich alle Panels gleichzeitig zu Aktivieren/Deaktivieren??
Danke

DeddyH 7. Dez 2011 13:32

AW: TObjectList Problem
 
Free gibt die Objektliste an sich frei, Clear hingegen löscht nur die enthaltenen Elemente. Wenn OwnsObjects auf true steht, werden in beiden Fällen die enthaltenen Objekte automatisch freigebeben. Und zur 2. Frage: einfach die Liste durchgehen und Enabled setzen.
Delphi-Quellcode:
for i := 0 to FPanels.Count - 1 do
  (FPanels[i] as TPanel).Enabled := false;

Dennis07 8. Dez 2011 12:17

AW: TObjectList Problem
 
Vielen Dank für deine Hilfe... ich denke mit dem Thema bin ich jetzt durch.....

Grüße;
Dennis


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:37 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