Autor Beitrag
Terra23
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Sa 23.02.13 00:52 
Moderiert von user profile iconMartok: 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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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?

ausblenden Delphi-Quelltext
1:
2:
private
List: TStrings;


Wäre das so korrekt?

_________________
Hasta La Victoria Siempre
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
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)
BeitragVerfasst: Sa 23.02.13 03:13 
Hey,

so ähnlich sollte das bei dir aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  TForm1 = class(TForm)
  private
    { private declarations }
    fList: TStringList
  public
    { public declarations }
  end;


MfG Bergmann.

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Sa 23.02.13 09:25 
Dann kannst Du mit einer Property auf die Liste zugreifen:

ausblenden Delphi-Quelltext
1:
2:
3:
// im Public-Bereich des Formulars
  public
    property myList : TStringlist read GetList write SetList;


Wenn Du dann Strg + Umsch + C drückst werden die Funktion und Prozedur automatisch erzeugt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
   Function TForm.GetList : TStringList;
   begin
     Result := fList // Dies musst Du manuell eintragen
   end;

   procedure TForm.SetList(Value : TStringList);
   begin
     fList := Value;  // Dies musst Du ebenfalls selber eintragen.
   end;

Wichtig ist natürlich: Im Constructor Create des Formulars und im Destructor Destroy folgende Zeilen hinzufügen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
   constructor TForm.Create(AOwner: TWinControl);  // AOwner ist die 
   begin
    inherited;     // es wird die Create-Prozedur von TCustomForm, dem "Vorgänger" von TForm aufgerufen, um alle wichtigen Dinge zu initialisieren
    fList : TStringList.Create(Self);  // Self ist eine Variable, die in Klassen die Referenz auf die Klasse selber bezeichnet (= selbst).
   end;

   destructor TForm.Destroy;
   begin
    fList.Destroy;
    inherited
   end;


Der Aufruf der Liste erfolgt dann (z.B.):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
// im Formular (in Prozeduren des Formulars, gekennzeichnet durch vorangestelltes "TForm.")

   myList.Strings.Clear;
   myList.Strings.Add(Zeile);

// außerhalb des Formulars (Form = Instanz Deines Formulars TForm)
   
   Form.myList.Strings.Clear;
   Form.myList.Strings.Add(Zeile);



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.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Sa 23.02.13 10:05 
Hallo,
unabhängig von den anderen gegebenen Antworten beschäftigt mich:
user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: 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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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):
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
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)
BeitragVerfasst: 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:
ausblenden Delphi-Quelltext
1:
property List: TStringList read fList write fList;					


MfG Bergmann.

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Sa 23.02.13 16:22 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
€: 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:
ausblenden Delphi-Quelltext
1:
property List: TStringList read fList write fList;					

Das trifft zu, wenn die Instanz die Liste gar nicht selbst erzeugt, meinst Du das damit? Ansonsten wäre es falsch, siehe weiter oben.
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Sa 23.02.13 17:46 
user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
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!?!

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Sa 23.02.13 18:21 
Was ich meinte:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Sa 23.02.13 18:36 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Wie schon gesagt initialisiert man Variablen und Objekte im OnCreate.

Ich machs meistens im Abschnitt initialization bzw Freigabe unter finalization.
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
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)
BeitragVerfasst: 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?! :shock:

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Sa 23.02.13 20:47 
user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
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.
Das ist, mit Verlaub, Blödsinn.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
private
  fFoo: TFoo;
public
  property Foo: TFoo read GetFoo write SetFoo;

procedure TTest.GetFoo: TFoo;
begin
  Result:= fFoo;
end;

procedure TTest.SetFoo(const aFoo: TFoo);
begin
  fFoo:= aFoo;
end;

ist einfach nur die langsamere Version von
ausblenden Delphi-Quelltext
1:
2:
3:
4:
private
  fFoo: TFoo;
public
  property Foo: TFoo read fFoo write fFoo;


Unter Umständen kann man den Compiler da zum inlinen überreden, dann ist es zumindest nicht mehr langsamer. Schlechter zu lesen aber auf jeden Fall.

_________________
"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