Variablen zur Laufzeit erzeugen?

Hallo.

Wie erzeuge ich zur Laufzeit z.B. eine Stringvariable?

Mit Komponenten ist das ja ganz einfach:

Var Mylabel: TLabel;

Mylabel:=TLabel.Create(Form1);
Mylabel.Parent:=Form1;
Mylabel.Name:='Textzeile';

Mylabel:=TLabel.Create(Form1);
Mylabel.Parent:=Form1;
Mylabel.Name:='Textzeile2';

Mylabel:=TLabel.Create(Form1);
Mylabel.Parent:=Form1;
Mylabel.Name:='Textzeile3';

… und fertig sind drei neue Komponenteninstanzen. Aber eine Stringvariable kennt ja kein Create oder Name.

Wie mache ich es dann?

Hallo Johannes.

Ähhh … vielleicht so?

var
myStringVarible: String;

oder habe ich jetzt die Frage falsch verstanden?

Manfred

Ich meinte, das ich Stringvariablen erzeugen will, jedoch erst im Verlauf des Programmes weiß, wie viele und welche Namen.

Wenn ich es mir recht bedenke, müsste es jedoch ein eindimensionales Array of String sein, damit ich auf die Variable zugreifen kann.

Beispiel: Formular mit Eingabefeld und Button, wenn auf dem Button gedrückt wird, speichert das Programm den Text des Eingabefeldes in das Array. Dazu müsste das Array sich zur Laufzeit aber vergrößern oder ich müsste 1000 Arrayfelder definieren oder so.

Wie ermögliche ich also ein Array in Variabler größe?

Wenn ich doch mit Sringvariablen arbeite, müsste ich Zeiger verwenden. Das geht natürlich auch.

In jedem Fall sollen zwischen begin und end Variablen definiert werden können. mit var geht das ja nur im Programmkopf.

Ich meinte, das ich Stringvariablen erzeugen will, jedoch erst
im Verlauf des Programmes weiß, wie viele und welche Namen.

Hallo,

grundsätzlich mit „new“ und Angabe des Typs, das Ergebnis ist ein Pointer auf eine Variable des Typs (benamt ist der Pointer). Bei Nichtmehrgebrauch Freigabe mit dispose, lies die Hilfe dazu.

Gruss Reinhard

ReHi,

nimm doch einfach eine TStringList.

Hat denn Vorteil, daß du bequem die Strings durchsuchen kannst.

CU, DiJey

Wie ermögliche ich also ein Array in Variabler größe?

Das ist ein Standardproblem. Die Lösung heißt „dynamisches Array“. Ein d. A. wird so deklariert:

VAR IntArray: ARRAY OF INTEGER;

oder

VAR StrArray: ARRAY OF STRING;

oder allgemein

VAR a: ARRAY OF ;

Der Typ kann dabei beliebig sein. Beachte, daß die Angabe der Arraygrenzen („ARRAY[0…99] OF …“) hier fehlt. Daran erkennt der Compiler, daß Du ein d. A. willst.

Die Länge des Arrays kannst Du beliebig zur Laufzeit setzen und ändern, und zwar mit dem Befehl „SetLength“. Nach

SetLength(StrArray, 100) 

steht Dir also das Array „StrArray“ mit einhundert Elementen zur Verfügung, indexiert von 0 bis 99 (Basisindex ist bei d. A. immer 0).

Möchtest Du StrArray zu irgendeinem Zeitpunkt auf 200 anwachsen lassen, genügt dazu der Befehl

SetLength(StrArray, 200) 

Sonst mußt Du nichts tun! Die Werte der schon belegten unteren 100 Elemente bleibt natürlich erhalten. Aufpassen mußt Du nur, wenn die Elemente keine Elementartypen (BOOLEAN, INTEGER, STRING, Records aus Elementartypen etc.), sondern Objektinstanzen sind; dann obliegt es Deiner Verantwortung, diese Objekte nach einer Arrayvergrößeung per SetLength erst händisch zu creatieren, bevor Du Daten in ihnen abspeichern kannst.

Falls Du dynamische Arrays als Klassenfelder deklarierst, solltest Du im Destruktor der entsprechenden Klasse die Zeile „StrArray := NIL“ unterbringen, damit der mit dem d. A. verknüpfte Speicher sicher freigegeben wird.

Gruß
Martin

dynamisches Array
Hallo.

Das ist genau das, was ich suche.
Bin erst heute zum testen gekommen und es zeigte sich, dass da etwas nicht stimmt. Der Compiler(Delphi 3) meldet „’[’ erwartet, aber ‚OF‘ gefinden.“. Außerdem steht in der Hilfe, dass SetLength nur für Strings (also nicht für Arrays) gedacht ist. Was nun?

cu

Hallo,

etwas nicht stimmt. Der Compiler(Delphi 3) meldet „’[’
erwartet, aber ‚OF‘ gefinden.“. Außerdem steht in der Hilfe,
dass SetLength nur für Strings (also nicht für Arrays) gedacht
ist.

mein dickes Delphibuch (Delphi 5 von E. Warken) hat mir gerade verraten, daß dynamische Arrays erst mit Delphi 4 eingeführt wurden.

Was nun?

Eine Möglichkeit: Auf eine höhere Delphi-Version umsteigen. Delphi 3 ist ja nun auch nicht mehr so ganz brandaktuell.

Andere Möglichkeit: „Handgemachte“ dynamische Arrays benutzen, die Du über Zeiger und Routinen zur dyn. Speicherverwaltung „nachbildest“. Das ist natürlich mit einem Haufen Programmiererei verbunden.

Gruß
Martin

eine Lösung
Hallo.
Habe es jetzt so gelöst:

Deklaration:
var mystr:TLabel;

Erzeugen:
for i:=1 to x do begin
 mystr:=TLabel.Create(Form1);
 mystr.Parent:=Form1;
 mystr.Hide;
 mystr.Name:='mystr\_'+inttostr(i);

 mystr.Caption:=....(Stringvariable)
 mystr.tag:=....(Integervariable)

Zugriff:
mystr:=TLabel(FindComponent('mystr\_'+inttostr(1)));
mystr.Caption:='test';

Jetzt meine Frage:
Muss ich die TLabels wieder freigeben? Ich habe sie ja mit Create an Form1 gebunden, da müssten sie mit schließen des Programms ja gelöscht werden. Und wie ist das mit Create(self)?

cu

Hi Johannes,

wenn die Labels mit TLabel.Create(Form1) erzeugt wurden, werden Sie wieder freigegeben, wenn Form1 freigegeben wird. Die Labels können aber auch zur Laufzeit freigegeben werden wenn sie nicht mehr benötigt werden. Die Entscheidung liegt bei dir.

Hier ein etwas einfacherer Vorschlag:

Deklaration:
var mystrings : TStringList;

Erzeugen:
mystrings := TStringList.Create;
for i := 1 to x do
 mystrings.Add(Stringvariable);

Zugriff:
mystrings[0] := 'test';

Freigabe:
mystrings.Free; 

Achte bei dieser Variante darauf, dass das erste Element in der Stringliste 0 ist und nicht 1. Folglich ist das letzte Element Count - 1. Der Vorteil der Stringliste ist der einfachere Quelltext, es werden nicht unnötig Objekte (TLabels) erzeugt, die gar nicht benötigt werden (Du erzeugst ja auch keinen Rekord oder ein Objekt wenn du eine Zahl speichern willst). Zudem hat die Klasse TStringList einige Methoden und Propertys, die evtl. nutzlich sind z.B. Sortieren der Einträge.

Gruß
Mike

P.S.
Das ist natürlich keine Komplettlösung sondern nur ein Ansatz. Entsprechende Sicherheitsmechanismen wie try…except-Blöcke sollten natürlich mit implementiert werden. (Auch bei der Version mit den TLabels).

Hallo.

Der Vorteil der Stringliste ist der
einfachere Quelltext, es werden nicht unnötig Objekte
(TLabels) erzeugt, die gar nicht benötigt werden

Das ist natürlich richtig, aber es war ja nur ein Beispiel. Es kann sich ja auch um jede andere Komponente handeln.

Die Frage ist nur, ob das Free; nötig ist, denn mit Create(Form1); ist die Komponente ja dem Formular unterstellt. Wie ist das?

cu

Hi nochmal,

es kommt bei den Komponenten (und/oder Objekten) eigentlich nur darauf an, wann sie benötigt werden. Wenn eine Komponente (ich nenne sie mal Label1) zur Laufzeit erzeugt wird, passiert das dann, wenn sie benötigt wird. Wird Label1 beim Erzeugen an eine andere Komponente2 gebunden (z.B. Form1), dann entfernt Form1 die Komponente Label1, wenn Form1 selbst entfernt wird. Sollte Label1 aber nicht mehr benötigt werden obwohl Form1 nicht entfernt (geschlossen) wird, spricht nichts dagegen Label1 mittels Free sofort wieder freizugeben.

Zusammenfassend könnte man sagen, dass es nicht nötig ist Label1 zu entfernen (das würde ich aber als schlampigen Programmierstil bezeichnen), der Übersicht halber aber von großem Vorteil gerade bei größeren Projekten. Das spart Resourcen und macht den Quelltext einfacher. Auch bei kleinen Projekten solltest du dir angewöhnen sauber zu programmieren denn diverse Unsitten gewöhnt man sich sehr schnell an und braucht lange um sie sich wieder abzugewöhnen. Ich spreche da aus Erfahrung.

Ich hoffe deine Frage beantowrtet zu haben.

Gruß Mike

Danke. owT
.