Autor |
Beitrag |
Terra23
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Sa 23.02.13 00:52
Moderiert von Martok: Abgetrennt von hier, Titel an der ersten Antwort orientiert
Sorry, wenn ich diesen alten Thread nochmal ausgrabe, aber ich wollte für die Frage nicht unbedingt einen neuen Thread eröffnen.
Ist es möglich, eine Stringlist in der FormCreate zu erzeugen und sie erst im FormClose zu beenden?
Aktuell, weil ich noch nicht so bewandert bin, arbeite ich mit Hilfskomponenten, d.h. ich lade die Stringliste in eine ListBox oder ein Memo, weil ich im laufenden Programm noch mit den Inhalten arbeiten will.
Kann ich stattdessen also folgendes tun:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| globale Variable = var List: TStrings;
TForm1.FormCreate(Sender: TObject) begin List := TStringList.Create; end;
TForm1.FormClose(Sender: TObject); begin List.Free; end; |
Oder gibt es da noch andere Lösungen? Hilfskomponenten finde ich persönlich nicht sehr professionell...
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 01:18
Das passt nicht ganz zusammen. Wenn Du die Liste (BTW: besser als privates Feld des Formulars deklarieren, globale Variablen sind böse) im OnCreate erzeugst, ist OnDestroy der richtige Zeitpunkt zum Freigeben.
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Sa 23.02.13 01:50
Aber generell wäre sowas möglich ohne dass ich immer diese Listen mit Try-Finally-End bzw. Try-Except-End nutzen muss? Wie deklariere ich die Listen denn als privates Feld?
Delphi-Quelltext 1: 2:
| private List: TStrings; |
Wäre das so korrekt?
_________________ Hasta La Victoria Siempre
|
|
Bergmann89
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Sa 23.02.13 03:13
Hey,
so ähnlich sollte das bei dir aussehen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| type TForm1 = class(TForm) private fList: TStringList public end; |
MfG Bergmann.
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Sa 23.02.13 09:25
_________________ Toleranz ist eine Grundvoraussetzung für das Leben.
|
|
Mathematiker
      
Beiträge: 2622
Erhaltene Danke: 1448
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: Sa 23.02.13 10:05
Hallo,
unabhängig von den anderen gegebenen Antworten beschäftigt mich:
WasWeißDennIch hat folgendes geschrieben : | Das passt nicht ganz zusammen. Wenn Du die Liste ... im OnCreate erzeugst, ist OnDestroy der richtige Zeitpunkt zum Freigeben. |
Was spricht gegen OnClose?
Ich habe bisher immer die Listen in der Close-Methode entfernt und hatte noch keine Probleme. Ich lasse mich aber gern überzeugen.
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Sa 23.02.13 10:46
Das kann stimmen. Wenn OnClose dann den Destruktor aufruft. Aber dann muss OnShow den Construktor aufrufen. Schaue mal nach.
Aber eines ist bei OnClose klar: Erst das Destroy der Komponente einbauen, wenn wirklich das Programm (Formular) beendet wird, da ja möglicherweise die Close-Prozedur ohne Beenden abgeschlossen wird:
Action != caFree !!! (caNone, caHide, caMinimize)
_________________ Toleranz ist eine Grundvoraussetzung für das Leben.
Für diesen Beitrag haben gedankt: Mathematiker
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 14:23
Die Property würde ich weglassen, wenn die Liste nicht von außen zugänglich sein muss. Außerdem sollte man Objekte niemals(!!!) mit Destroy freigeben, sondern immer mit Free. Grund: Free prüft intern auf nil und ruft erst dann ggf. Destroy auf. Und zur Freigabe im OnDestroy, wenn im OnCreate erzeugt, hat Tranx ja bereits alles gesagt.
[edit]Nachtrag: im Setter der Property würde ich keine einfache Zuweisung machen, sondern mit Assign die Eigenschaften der übergebenen Liste kopieren. Ansonsten schafft man sich ein Speicherleck, da man die selbst erzeugte Instanz mit der übergebenen überschreibt und somit nicht mehr freigeben kann. [/edit]
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Sa 23.02.13 14:44
Wasweißichdenn hat Recht. das mit dem Setxxx habe ich nicht bedacht. Aber das benötigt man auch eigentlich nicht. Es reicht für die Property, falls man von außen auf die Liste zugegriffen werden muss:
Delphi-Quelltext 1:
| property myListe : TStringlist read GetListe; |
dann fällt Setliste weg und man kann die Liste nicht zuordnen. Aber das geschieht eh im Konstruktor.
Klar benötigt man die Property nur, falls man von außen auf die Liste zugreifen muss. Aber wenn ich Eigenschaften kapseln will, dann ist es besser, sie nur der Klasse sichtbar zu machen. Und das ist dann in dem private-Bereich der Klasse. Dann sieht man die Eigenschaft nicht mehr außerhalb der Klasse. Benötigt man die Liste aber gerade da, und das ist bei Listen ja zu erwarten, dann benötigt man die property, die dann über Umwege anderen Klassen diese Eigenschaft zugänglich macht. Alles andere geht auch, aber es wäre eben keine Kapselung mehr.
_________________ Toleranz ist eine Grundvoraussetzung für das Leben.
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 14:59
Ich will ja nicht nerven, aber selbst bei einer ReadOnly-Objektproperty gibt es noch einen Pferdefuß: sie kann "von außen" freigegeben werden, ohne dass man das mitbekommen würde. Will man auch das verhindern, muss die Liste komplett verborgen und nur über definierte Schnittstellenmethoden zugänglich gemacht werden. Z.B. (ungetestet, direkt im Editor getippt):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| private FMyList: TStrings; function GetItem(Index: integer): string; procedure SetItem(Index: integer; const Value: string); public procedure AddItem(const Value: string); property Items[Index: integer]: string read GetItem write SetItem;
...
function TKlasse.GetItem(Index: integer): string; begin Result := FMyList[Index]; end;
procedure TKlasse.SetItem(Index: integer; const Value: string); begin FMyList[Index] := Value; end;
procedure TKlasse.AddItem(const Value: string); begin FMyList.Add(Value); end; |
Usw. usf.
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Sa 23.02.13 15:14
Danke für eure rege Beteiligung und danke auch an Martok fürs Abtrennen vom anderen Thema. Im Gegensatz zu anderen Foren in denen ich aktiv war / bin, wird hier halt zu 100% auf Ordnung geachtet.
Was mich interessiert: Warum ist es "böse", wie Wasweißdennich sagte, eine Liste als globale Variable zu deklarieren? Was ist denn der Unterschied zwischen einer globalen Variable und der Art von Deklaration über die wir in diesem Thread sprechen?
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 15:18
Globale Variablen gehören zu keiner Instanz und sind völlig "ungeschützt". Wenn Du mehrere Instanzen von TForm1 hast, gibt es trotzdem nur eine einzige globale Variable, das könnte für Chaos sorgen. Außerdem kann jeder, der herankommt, mit der Variablen anstellen, was er möchte. Bei einer Property hingegen steht die Liste unter der Kontrolle der Instanz, der sie gehört.
|
|
Bergmann89
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Sa 23.02.13 15:58
Hey,
kurz gesagt: Globale Variablen wiedersprechen einer objektorientierten Programmiereung. Hier und da muss man sie verwenden, aber das hat dann auch seine Gründe.
nochmal was zu dem OnCreate, OnShow, OnClose und OnDestroy: Wie schon gesagt initialisiert man Variablen und Objekte im OnCreate. OnCreate wird aufgerufen sobald das Objekt (die Form) erzeugt wurde. @Tranx: Das hat nix mit OnShow zu tun! OnDestroy ist das genaue Gegenteil zu OnCreate und wird aufgerufen, kurz bevor das Objekt freigegeben wird. OnShow wird aufgerufen wenn die Form angezeigt wird, und OnClose, wenn sie wieder geschlossen wird. OnCreate und OnDestroy bzw. OnShow und OnClose gehören sozusagen immer zusammen. Wenn man jetzt im OnCreate ein Objekt erzeugt, und im OnClose wieder freigibt, dann knallt es sobald das Fenster das zweite mal angezeigt wird. Bei den Standarteinstellungen der MainForm wird die Form nach dem Close freigegeben und kann demzufolge nicht mehr genutzt werden, aber das kann man auch verhindern und die Form z.B. in den Tray legen. Wenn sie dann wieder geöffnet wird, ist die Liste weg, weil diese ja im OnClose freigegeben wurde. Wenn ihr das wirklich im OnClose freigeben wollt, dann muss das auch im OnShow erzeugt werden. Das kommt dann darauf an was genau ihr damit bezwecken wollt. Bei OnShow/OnClose wird halt bei jedem neu öffnen des Fensters alles wieder initialisiert. Bei OnCreate/OnDestroy habt ihr solange das Programm läuft immer die gleiche Liste.
Ich hoffe ich konnte jetzt noch einige Missverständnisse klären
€: noch ne kleine Anmerkung zu den properties. Wenn die Get- bzw. Set-Methode die Liste nur zurück gibt bzw. setzt, dann brauch man keine extra Methode:
Delphi-Quelltext 1:
| property List: TStringList read fList write fList; |
MfG Bergmann.
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 16:22
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Sa 23.02.13 17:46
Tranx hat folgendes geschrieben : | Dann kannst Du mit einer Property auf die Liste zugreifen:
ANMERKUNG:
Wenn Du eine Stringlist so einbindest, dann darfst Du auf keinen Fall zwei Sachen machen:
in einer Prozedur oder Funktion außerhalb von TForm.Create und TForm.Destroy :
TStringlist.Create und TStringlist.Destroy
denn dann würdest Du eine existierende Liste neu erzeugen, oder eine zerstören. Und am Ende würde der Destruktor dann nichts (NIL) zerstören wollen, und das geht nun mal nicht. Das gibt dann einen Laufzeitfehler und Du kannst (normalerweise) das Programm nicht mehr beenden. Du kannst mit den Inhalten arbeiten, aber nie die Liste neu erzeugen oder zerstören. Bitte beim Einbinden und bei der Programmierung daran denken. |
Du redest hier aber von der immergleichen Liste, oder? Also wenn ich eine Liste global deklariert habe... Ich kann trotzdem noch in bestimmten Prozeduren weiterhin Listen verwenden, sofern sie nicht den gleichen Namen haben wie die global deklarierte Liste!?!
WasWeißDennIch hat folgendes geschrieben : | Außerdem kann jeder, der herankommt, mit der Variablen anstellen, was er möchte. |
Wie meinst du das? Herankommen? Meinst du, wenn jemand von außen den Code eines bestehenden Programms "reproduziert"? Geht sowas?
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 18:21
Was ich meinte:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| unit Tralala;
interface
...
var MeineListe: TStringlist;
implementation
... |
Somit hat man aus allen Units, die Unit Tralala eingebunden haben, Zugriff auf MeineListe. Button2 in Form23 trägt da etwas ein, Button24 auf Form123 löscht Einträge heraus, Button12 auf Form2 gibt die Liste frei. Wie will man das noch überblicken?
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Sa 23.02.13 18:36
Bergmann89 hat folgendes geschrieben : | Wie schon gesagt initialisiert man Variablen und Objekte im OnCreate. |
Ich machs meistens im Abschnitt initialization bzw Freigabe unter finalization.
|
|
Bergmann89
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Sa 23.02.13 19:46
@WasWeißDennIch: wieso is das falsch? Is doch genau das selbe wenn du ne Get und Set-Methode hast, die die Variable liest oder schreibt. Das wollt ich damit sagen.
@Gerd Kayser: aber keine objektabhängigen bzw. formabhängigen Variablen, oder?! 
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Sa 23.02.13 20:42
Für Objektproperties, die auch gesetzt werden dürfen, ist IMO ein Setter Pflicht, sofern die enthaltende Klasse die Instanz selbst anlegt. Innerhalb dieses Setters wird dann lediglich der Inhalt der übergebenen in die eigene Instanz kopiert. Wie ich weiter oben schon sagte: damit vermeidet man ein Speicherleck.
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Sa 23.02.13 20:47
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Für diesen Beitrag haben gedankt: Bergmann89
|
|