Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Auf globale Variable im Projekt zugreifen


Pow - Sa 05.06.10 12:21
Titel: Auf globale Variable im Projekt zugreifen
Hallo,

ich bin noch recht neu mit Delphi und habe gemerkt, dass es ein mal procedure und function gibt und wenn ich es richtig verstanden habe, kann nur function einen Wert zurückgeben.
D.h. wenn ich im Projekt mit mehreren Formularen arbeite, muss ich global etwas deklarieren, das ich auch in den anderen Formularen verwenden möchte und dann nicht mit procedure diese Variable füllen, sondern mit function oder?

Gibt es da etwas bestimmtes zu beachten?
Also wenn man z.B. Doppelklick auf einen Button macht, dann wird ja automatisch ein procedure erstellt und auch alles dafür deklariert.
Bei function müsste ich ja hingegen auch die Deklaration bei type beachten usw.

Ist sicher eine blöde Anfängerfrage - aber ich wär sehr froh, wenn ich Sicherheit hab :)
Ein kleiner Beispiel-Quellcode wäre echt super


Moderiert von user profile iconNarses: Topic aus Dateizugriff verschoben am So 06.06.2010 um 23:19


Delete - Sa 05.06.10 17:04

Werte zwischen zwei Formularen tauscht man so aus: http://www.michael-puff.de/Programmierung/Delphi/Code-Snippets/werte-zwischen-formen-austauschen.shtml


Delphi-Laie - Sa 05.06.10 17:52

user profile iconPow hat folgendes geschrieben Zum zitierten Posting springen:
wenn ich es richtig verstanden habe, kann nur function einen Wert zurückgeben.

Nein, auch Prozeduren können es, und zwar über (einen oder mehrere) sog. Variablenparameter. Hört sich hochtrabend an, ist aber einfacher dadurch beschrieben, daß es all' die Variablen sind, die in der Prozedurdeklaration ein (nicht notwendiges, also optionales) var vorangestellt bekommen, z.B. procedure(a:integer;var b:word), dort wäre es die Variable b. Es ist also beiderseitiger Informationsaustausch über die Prozedurschnittstelle möglich, aber nicht notwendig. Bei den anderen Parametern, den Werteparametern, existiert hingegen nur ein Informationsfluß in das Innere der Prozedur.

Allerdings sind Funktionen wesentlich flexibler: Man kann sie (bzw. Ihren Funktionswert) auch als Argument benutzen, z.B. für neue, weitere, oder eben auch sogar diesselbe Funktion (Funktionsverschachtelung). Allerdings benötigen sie zwingend einen Ergebnistyp; ob man den benutzt, ist davon unbeschadet.

Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function Funktion1:integer;
function Funktion2(x:integer):string;

....

a:=Funktion2(Funktion1(3))


Ist im Prinzip genau wie in der Mathematik: y=sin(cos(x)). Diese Flexibilität hinsichtlich Aufrufen und Verschachtelungen besitzen jedenfalls Prozeduren nicht. Zusätzlich können Funktionen aber auch weitere Ausgaben über die o.g. Variablenparameter haben, doch die lassen sich eben nicht als Argumente verwenden.

Moderiert von user profile iconNarses: Quote- durch Delphi-Tags ersetzt


hansa - Sa 05.06.10 20:04

Delphi-Laie hat folgendes geschrieben:
daß es all' die Variablen sind, die in der Prozedurdeklaration ein (nicht notwendiges, also optionales) „var“ vorangestellt bekommen

Was heisst hier nicht notwendig ? :shock: In der Theorie gibt es Const-, Wert- und Variablen-Parameter. Unterschied zwischen den ersten beiden weiss ich jetzt gerade nicht. Rückgabewerte liefern die VAR - Parameter.

Programmiere mal das hier :


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure test (VAR st : string);
begin
  st := 'Test';
end;

procedure TForm1.Button1Click(Sender: TObject);
var st : string;
begin
  st := '';
  test (st);
ShowMessage(st);
end;


Da steht dann : 'Test'. Mache das VAR mal weg und gucke mal, was da steht. Nix. :mrgreen:


Delphi-Laie - Sa 05.06.10 20:10

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Delphi-Laie hat folgendes geschrieben:
daß es all' die Variablen sind, die in der Prozedurdeklaration ein (nicht notwendiges, also optionales) „var“ vorangestellt bekommen

Was heisst hier nicht notwendig ? :shock:


Das heißt, daß Prozeduren nicht mit Variablenparametern arbeiten müssen. Man kann sie damit natürlich arbeiten lassen, aber man muß nicht.

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Da steht dann : 'Test'. Mache das VAR mal weg und gucke mal, was da steht. Nix. :mrgreen:


Sicher steht dann nichts drin. Doch was soll dieses Beispiel beweisen oder widerlegen? Das bestätigt doch nur meine obigen Sätze!


Pow - Sa 05.06.10 20:21

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Werte zwischen zwei Formularen tauscht man so aus: http://www.michael-puff.de/Programmierung/Delphi/Code-Snippets/werte-zwischen-formen-austauschen.shtml


Hey super, genau sowas brauch ich :)
Variablen zwischen verschiedenen Formularen aufrufen

Ich habe mein Programm genauso angepasst, wie es auf der Seite beschrieben ist, seltsamerweise sagt er mir an einer Stelle "undefinierter Bezeichner"

Hier mal der Quellcode:
Hier quasi mein Form1:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TFrame_Anmelden.B_AnmeldenClick(Sender: TObject);

var       TempS : string;
          Form_Anmelden :  TFrame_Anmelden;

begin

     Table1.Open;
     TempS := Table1.FieldByName('Vorname').AsString;
     TempS := TempS + ' ' + Table1.FieldByName('Name').AsString;
     Label2.Caption := TempS;
     Form_Anmelden := TFrame_Anmelden.Create(nil);
     Form_Anmelden.Bediener := Table1.FieldByName('Kürzel').AsString;


end;


Hier quasi mein Form2:

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:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
unit Unit_Anmelden;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, DB, DBTables, Unit_Auftraege, ExtCtrls;

type
  TF_Anmelden = class(TForm)
    { Sachen zur übersichtlichkeit weggelöscht }
    Frame21: TFrame_Anmelden;

  private
    { Private-Deklarationen }
    FBediener : String;
  public
    { Public-Deklarationen }
     property Bediener : String read FBediener write FBediener;
  end;

var
  F_Anmelden: TF_Anmelden;

implementation

uses Konfiguration, Unit1;

{$R *.dfm}

procedure TF_Anmelden.FormCreate(Sender: TObject);
begin
  L_datum.Caption := DateToStr(date());
  Timer1.Enabled := true;
  Label2.Caption := FBediener;
end;

procedure TF_Anmelden.Timer1Timer(Sender: TObject);

begin
     L_uhrzeit.Caption := TimeToStr(Time);
end;



Soll also im Frame, wo man sich anmeldet, belegt werden und dann in Form1, das als Hauptfenster offen ist verwendet

Ach ja, beim ersteren meldet er in Zeile 13, dass "Bediener" ein undefinierter Bezeichner ist
Hab ich irgendwo was falsch deklariert oder vergessen? :s


Tryer - Sa 05.06.10 20:29

Vielleicht "Frame21.Label2" ?
Ansonsten bring es nichts Label.Caption im Create auf FBediener zu setzen, denn das ist ja noch nicht zugewiesen.
Besser:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
..
protected
  procedure SetBediener(Value: string); virtual;
public
  property Bediener: string read FBediener write SetBediener;


..
procedure TF_Anmelden.SetBediener(Value: string);
begin
  FBediener := Value;
  Frame21.Label2.Caption := FBediener;
end;


[EDIT]Und "TFrame_Anmelden.Create(nil);" soll vermutlich "TF_Anmelden.Create(nil);" heißen?[/EDIT]

Grüsse, Dirk


hansa - Sa 05.06.10 20:40

user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Das heißt, daß Prozeduren nicht mit Variablenparametern arbeiten müssen. Man kann sie damit natürlich arbeiten lassen, aber man muß nicht.


Moment ! Wer Rückgabewerte braucht, der MUSS var-Parameter verwenden ! Das von Dir gesagte suggeriert eher, man könne "var" einfach weglassen und fertig. Selber Effekt. :shock: Brauche ich keinen Rückgabewert, DANN kann man nicht, sondern sollte das VAR weglassen. Alleine aufgrund der Programmlogik. Unerwähnt blieb auch noch, dass sowohl Function, als auch Procedure VAR-Rückgabewerte liefern können. Betonung liegt dabei auf der Mehrzahl. Das können auch 10 sein.


Pow - Sa 05.06.10 20:48

Ui, da sind schon einige Elemente, die für mich total neu sind
Könntest du bitte deinen kleinen Code Zeile für Zeile erklären? :)
dieses protected z.B. oder das virtual am Ende davon


Ich habe mir auch gedacht, ob es nicht auch so gehen könnte

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TFrame_Anmelden.B_AnmeldenClick(Sender: TObject);

var       TempS : string;
          Frame_Anmelden :  TFrame_Anmelden;

begin

     Table1.Open;
     TempS := Table1.FieldByName('Vorname').AsString;
     TempS := TempS + ' ' + Table1.FieldByName('Name').AsString;
     Label2.Caption := TempS;
     Frame_Anmelden := TFrame_Anmelden.Create(nil);
     Frame_Anmelden.Label2.Caption := Table1.FieldByName('Kürzel').AsString;

end;


Er kompiliert zwar fehlerfrei, aber irgendwie setzt er die Caption trotzdem nicht im Formular - aber ich schätze, es ist kein Problem ersichtlich, oder? ^^


// EDIT
Zitat:
Und "TFrame_Anmelden.Create(nil);" soll vermutlich "TF_Anmelden.Create(nil);" heißen?

Dachte ich auch - als ich aber auf TFrame änderte, lieferte er keine Fehler mehr. Scheint aber das richtige zu sein, weil er die ganzen Objekte (Labels usw.) auch findet, wenn ich einen Punkt setze


Delphi-Laie - Sa 05.06.10 20:49

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Das heißt, daß Prozeduren nicht mit Variablenparametern arbeiten müssen. Man kann sie damit natürlich arbeiten lassen, aber man muß nicht.


Moment ! Wer Rückgabewerte braucht, der MUSS var-Parameter verwenden !


Oder er nimmt eine Funktion (wenn er nur einen benötigt). Diese Voraussetzung, daß man Rückgabewerte benötigt, wurde von mir doch gar nicht genannt, ich hielt mich doch allgemein(gültig)er! Ich schrieb lediglich, daß Prozeduren keine Variablenparameter (logischerweise zwingend) voraussetzen. Was gibt es an dieser korrekten Aussage zu zerreden?

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Das von Dir gesagte suggeriert eher, man könne "var" einfach weglassen und fertig. Selber Effekt. :shock:


Es suggeriert es vielleicht bei Dir. Du darfst allerdings nicht der Versuchung erliegen, daß das, wie es Dir erscheint, auch objektiv so sei.

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Unerwähnt blieb auch noch, dass sowohl Function, als auch Procedure VAR-Rückgabewerte liefern können. Betonung liegt dabei auf der Mehrzahl. Das können auch 10 sein.


Nun, weil ich nicht die Mehrzahl verwandte, wäre es falsch geschlossen, daß ich behauptet hätte, daß es nicht mehr als einer sein könne.


hansa - Sa 05.06.10 21:18

Du willst das nicht verstehen. Verstehe. :mrgreen: Lese mal im nachhinein das hier :
Delphi-Laie hat folgendes geschrieben:
..daß es all' die Variablen sind, die in der Prozedurdeklaration ein (nicht notwendiges, also optionales) „var“ vorangestellt bekommen

Da steht drin : Variable sind alle die in der Prozedurdeklaration ein (nicht notwendiges, also optionales) „var“ vorangestellt bekommen. Ziehe ich den Umkehrschluss, dann heisst das eben : var-Parameter können ein VAR vorangestellt kriegen, ist aber nicht notwendig. Sieht zumindest für mich so aus, als wäre es egal. Ist es aber eben ganz und gar nicht, weil es um Rückgabewerte geht ! Ich bin jetzt wirklich kein Prinzipienreiter oder gar Lehrer. Aber die Aussage ist so nicht richtig. Wird Rückgabewert gebraucht, dann ist VAR nicht optional, sondern zwingend notwendig. Die Anzahl der Rückgabewerte sind nur der Vollständigkeit halber angemerkt worden.

Moderiert von user profile iconNarses: Zitat repariert.


Tryer - Sa 05.06.10 21:40

Du willst doch nicht den Frame, sondern die Form erzeugen!

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TFrame_Anmelden.B_AnmeldenClick(Sender: TObject);
var       
  TempS : string;
  F_Anmelden :  TF_Anmelden;
begin
     ..
     F_Anmelden := TF_Anmelden.Create(nil);
     F_Anmelden.Benutzer := Table1.FieldByName('Kürzel').AsString;
end;


"protected" beschreibt die Sichtbarkeit, genauso wie das "public" das du schon verwendest.
"protected" ist aber nur in abgeleiteten Klassen sichbar, nicht "überall". SetBenutzer braucht ja niemand sehen, dafür ist "property Benutzer" da.
"virtual" ermöglicht es nur die Prozedur in abgeleiteten Klassen zu überschreiben. Das hält einem also einfach Möglichkeiten offen die sonst verbaut wären. Das braucht dich aber vielleicht noch nicht unbedingt zu belasten.. alles zu seiner Zeit. Zu dem Thema findest Du auch einiges in der Hilfe (Sichtbarkeit von Klassenelementen, Vererbung, .. findet sich vermutlich mit "public" bzw. "virtual"+F1)

Grüsse, Dirk


Delphi-Laie - Sa 05.06.10 21:46

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Du willst das nicht verstehen. Verstehe. :mrgreen:


Oder hier möchte irgendjemand irgendetwas mit aller Gewalt zerreden.

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Lese mal im nachhinein das hier :
user profile iconhansa hat folgendes geschrieben:
..daß es all' die Variablen sind, die in der Prozedurdeklaration ein (nicht notwendiges, also
optionales) „var“ vorangestellt bekommen


Da steht drin : Variable sind alle die in der Prozedurdeklaration ein (nicht notwendiges, also optionales) „var“ vorangestellt bekommen.


Sicher, ich weiß, was ich schrieb, dort steht aber nicht, daß man diese Freiheit auch dann noch hat, wenn man einen Rückgabewert benötigt.

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Ziehe ich den Umkehrschluss, dann heisst das eben : var-Parameter können ein VAR vorangestellt kriegen, ist aber nicht notwendig.


Für Fehlkonklusionen fühle ich mich nicht verantwortlich, ja, ich bin es nicht. Der Delphi-Compiler wird eine Prozedur auch dann meldungsfrei übersetzen, wenn sie ohne Variablenparameter definiert wurde - wetten?

user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Wird Rückgabewert gebraucht, dann ist VAR nicht optional, sondern zwingend notwendig.


Richtig, wenn, dann! Aber mein Schnellexkurs weiter oben ging nicht von dieser Voraussetzung aus, daß ein Rückgabewert in jedem Falle benötigt wird. Ist schon schwierig, das zu begreifen...


Delete - Sa 05.06.10 21:48

Jetzt kommt mal wieder runter und führt die Diskussion sachlich weiter. Bei der Diskussion um var und const hat das ja auch wunderbar geklappt.


Pow - Sa 05.06.10 22:01

user profile iconTryer hat folgendes geschrieben Zum zitierten Posting springen:
Du willst doch nicht den Frame, sondern die Form erzeugen!

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TFrame_Anmelden.B_AnmeldenClick(Sender: TObject);
var       
  TempS : string;
  F_Anmelden :  TF_Anmelden;
begin
     ..
     F_Anmelden := TF_Anmelden.Create(nil);
     F_Anmelden.Benutzer := Table1.FieldByName('Kürzel').AsString;
end;


"protected" beschreibt die Sichtbarkeit, genauso wie das "public" das du schon verwendest.
"protected" ist aber nur in abgeleiteten Klassen sichbar, nicht "überall". SetBenutzer braucht ja niemand sehen, dafür ist "property Benutzer" da.
"virtual" ermöglicht es nur die Prozedur in abgeleiteten Klassen zu überschreiben. Das hält einem also einfach Möglichkeiten offen die sonst verbaut wären. Das braucht dich aber vielleicht noch nicht unbedingt zu belasten.. alles zu seiner Zeit. Zu dem Thema findest Du auch einiges in der Hilfe (Sichtbarkeit von Klassenelementen, Vererbung, .. findet sich vermutlich mit "public" bzw. "virtual"+F1)

Grüsse, Dirk


Hmpf, ich komm einfach nicht drauf, warum er mir dann in der Zeile F_Anmelden : TF_Anmelden; sagt undefinierter Bezeichner "TF_Anmelden"
TF_Anmelden existiert ja, ist nur eben das Hauptfenster, wohin ich meine Variable hinbeordern möchte :?


// EDIT
Kann es vielleicht sein, dass es doch Frame_Anmelden sein muss?
Ich hab nämlich eine etwas ungeschickte Bezeichnung im Nachhinein - das Hauptfenster heißt nämlich F_Anmelden und der Frame, in dem man sich eigentlich anmeldet, heißt Frame_Anmelden


Tryer - Sa 05.06.10 22:37

Wenn der Bezeichner unbekannt ist fehlt "Unit_Anmelden" vermutlich in der uses-Klausel.


Pow - Sa 05.06.10 22:43

user profile iconTryer hat folgendes geschrieben Zum zitierten Posting springen:
Wenn der Bezeichner unbekannt ist fehlt "Unit_Anmelden" vermutlich in der uses-Klausel.


Wenn ich das hinzufüge, sagt er mir in der anderen Unit "Überkreuezender Bezug zweier Units auf 'Unit_Anmelden'"
Weil in der Unit_Anmelden unter uses die Unit_Auftraege steht (also vom Frame .. wieder sehr ungeschickte Bezeichnung)


Delete - Sa 05.06.10 22:52

Füge sie der Uses-Klausel im Implementation-Abschnitt hinzu.


Tryer - Sa 05.06.10 22:53

Einmal im interface-Teil in die uses-Klausel, und einmal unter implementation, dann sollte es gehen.
Der Frame sollte ja wohl _nur_ in Unit_Anmelden benötigt werden, dann könnte er an anderer Stelle ganz ausgetragen werden.
Ohne kompletten Überblick ist das schwer zu analysieren.

Grüsse, Dirk


Pow - Sa 05.06.10 23:07

Wenn ich es unter Implementation einfüge, ändert sich leider nichts.

Ich hänge mal das Projekt mit dem Quellcode als Anhang rein, damit man bei Bedarf reinschauen kann.. vielleicht wird es dann ersichtlicher, was ich falsch mache :s



//EDIT

Oke, ich hab es nun etwas anders und scheinbar viel simpler gelöst

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
...
 public
    { Public-Deklarationen }
    BedienerName : String;
...
 Label2.Caption := Frame21.BedienerName;
...


Herzlichen Dank für die Hilfestellungen :)
Hab auf jeden Fall ein paar Dinge gelernt