PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Delphi5: Globale Variablen und verschiene Units


mobius
2004-10-26, 20:26:23
Nabend Jungs,

hab ein paar Probleme mit Delphi und ich hoffe ihr könnt mir helfen.

Hier mal ein paar Auszüge aus dem funktionierenden Programm:


Unit1:


implementation

uses Unit2, KomplexeZahlen, Eingabe, Ergeb, Eingabe2;

{$R *.DFM}

//diverse procedures...

procedure TForm1.JuliaMengen1Click(Sender: TObject);
var Aalt, Aneu, A0, C : TKomplex;
var i, Iteration, Radius, xp, yp : Integer;
var Kante : Real;
begin
EingabeForm2.ShowModal;
With EingabeForm2 do
begin
c.re:=StrToFloat(creEdit.text);
c.im:=StrToFloat(cimEdit.text);
A0.re:=StrToFloat(a0reEdit.text);
A0.im:=StrToFloat(a0imEdit.text);
Iteration:=StrToInt(IterationEdit.text);
Radius:=StrToInt(RadiusEdit.text);
Kante:=StrToFloat(KanteEdit.text);
end;
for xp:=1 to 640 do
begin
for yp:=1 to 480 do
begin
Aalt.re:=a0.re+Kante*xp/640;
Aalt.im:=a0.im+Kante*3/4*yp/480;
I:=0;
While (i<=Iteration) and (KompBetrag(Aalt)<=Radius) do
begin
i:=i+1;
Aneu:=KompAddieren(KompMultiplizieren(Aalt, Aalt), C);
Aalt:=Aneu;
end;
If i> Iteration then
Image1.Canvas.Pixels[xp,481-yp]:=clblack
else
Image1.Canvas.Pixels[xp,481-yp]:=$111111*i;
end;
end;
end;


KomplexeZahlenUnit:


interface
type
TKomplex = record
re : Real;
im : Real;
end;
function KompAddieren(A ,B : TKomplex) : TKomplex;
function KompMultiplizieren(A,B:TKomplex) : TKomplex;
function KompBetrag(Betrag:TKomplex) : Real;
function KompArgument(Argument:TKomplex) :Real;

implementation

function KompAddieren (A, B : TKomplex) : TKomplex;
...


Eingabe2: (weitere Unit)

procedure TEingabeForm2.BitBtn1Click(Sender: TObject);
begin
close;
end;





Was ich eigentlich will ist folgendes: Wenn ich das einlesen dar Variablen in der Unit1 mache, dann funktioniert alles wunderbar, aber nun möchte ich das in der Eingabe2 machen und es ergeben sich Übergabefehler und die Frage wo ich welche Variablen global definieren muss.

Hier nun der Umbauversuch:


Unit1:

procedure TForm1.JuliaMengen1Click(Sender: TObject);
var xp, yp, i : Integer;
var Aalt, Aneu : TKomplex;
begin
EingabeForm2.ShowModal;
Einlesen(C, A0 : TKomplex; Iteration, Radius : Integer; Kante : Real);
for xp:=1 to 640 do
begin
for yp:=1 to 480 do
begin
Aalt.re:=a0.re+Kante*xp/640;
Aalt.im:=a0.im+Kante*3/4*yp/480;
I:=0;
While (i<=Iteration) and (KompBetrag(Aalt)<=Radius) do
begin
i:=i+1;
Aneu:=KompAddieren(KompMultiplizieren(Aalt, Aalt), C);
Aalt:=Aneu;
end;
If i> Iteration then
Image1.Canvas.Pixels[xp,481-yp]:=clblack
else
Image1.Canvas.Pixels[xp,481-yp]:=$111111*i;
end;
end;
end;


KomplexeZahlenUnit:


interface
type
TKomplex = record
re : Real;
im : Real;
end;
function KompAddieren(A ,B : TKomplex) : TKomplex;
function KompMultiplizieren(A,B:TKomplex) : TKomplex;
function KompBetrag(Betrag:TKomplex) : Real;
function KompArgument(Argument:TKomplex) :Real;

implementation

function KompAddieren (A, B : TKomplex) : TKomplex;
...


Eingabe2:


implementation

uses Unit1

{$R *.DFM}

procedure Einlesen(C, A0 : TKomplex; Iteration, Radius : Integer; Kante : Real);
begin
c.re:=StrToFloat(creEdit.text);
c.im:=StrToFloat(cimEdit.text);
A0.re:=StrToFloat(a0reEdit.text);
A0.im:=StrToFloat(a0imEdit.text);
Iteration:=StrToInt(IterationEdit.text);
Radius:=StrToInt(RadiusEdit.text);
Kante:=StrToFloat(KanteEdit.text);
end;

procedure TEingabeForm2.BitBtn1Click(Sender: TObject);
begin
close;
end;




Kleines Bild zur Veranschaulichung: http://www.picupload.net/show_image.php?pic=http://www.picupload.net/files/20042610/1098813912.jpg

Probleme:

[Fehler] Unit1.pas(280): Undefinierter Bezeichner: 'Einlesen'
Ich muss die Prozedur Einlesen jetz global bekanntmachen oder? Was muss ich wohin schreiben? Mit dem Variablen, die ich bei der Prozedur angeben muss hab ich auch Probleme. Was is der Unterschied wenn ich schreibe:
Procedure(var Test : Integer); -> Var wird eingelesen?
Procedure(Test : Integer); -> Var wird übergeben?

Wo muss ich die Variablen global bekannt machen, damit ich sie in Eingabe2 einlesen und in Unit1 verwenden kann?

Noch nicht solange mit der Programmiersprache vertraut und doch schon so viel vergessen, hoffe ihr könnt mir helfen.

Nagelbrett
2004-10-26, 21:34:47
Hallo, zuersteinmal solltest du statt Zitaten die code-tags verwenden... der unformatierte Code ist so nur schwer zu erfassen :/

Dann zu deinen Fragen:
wenn du die Funktion als global deklarieren willst, mache das einfach im var Abschnitt unter "interface" der jeweiligen Unit.
also einfach

interface

[.. deine klassen etc.]

var
procedure Einlesen(C, A0 : TKomplex; Iteration, Radius : Integer; Kante : Real);

implementation

...


Dann brauchst du diese Unit eigentlich nurnoch ins Uses derjenigen Unit einzufügen, in der du sie verwenden willst (wenn das nicht sowieso schon der Fall ist).

Der Unterschied zwischen
Procedure(var Test : Integer); -> Var wird eingelesen?
und
Procedure(Test : Integer); -> Var wird übergeben?
ist der, dass in der ersten Funktion die Variable Test quasi nur als Referenz übergeben wird, d.h. wenn du in der Prozedur den Wert von Test änderst, ändert er sich auch dort, wo du sie aufgerufen hast. In der zweiten hingegen wird eine Kopie der Übergabevariable erstellt, die dann nur innerhalb der Prozedur gilt.

mobius
2004-10-27, 18:31:15
Sorry für das mit dem Code Tag, kannte das noch net. Dann werd ich das jetz mal benutzen:

Hab jetzt die Prozedur in den Type Teil geschrieben um sie bekannt zu machen, allerdings meckert er jetzt das er TKomplex nicht kennt. Es sieht folgendermaßen aus:


type
//TKomplex = record
// re : Real;
// im : Real;
TForm1 = class(TForm)
MainMenu1: TMainMenu;
...
ZoomStufe: TEdit;
procedure Beenden1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure RClick(Sender: TObject);
procedure FeigenbaumDiagramm1Click(Sender: TObject);
procedure Neu1Click(Sender: TObject);
procedure ffnen1Click(Sender: TObject);
procedure Speichern1Click(Sender: TObject);
procedure Drucken1Click(Sender: TObject);
procedure Info1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Addieren1Click(Sender: TObject);
procedure Multiplizieren1Click(Sender: TObject);
procedure Betrag1Click(Sender: TObject);
procedure Argument1Click(Sender: TObject);
procedure JuliaMengen1Click(Sender: TObject);
procedure EinlesenEinlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;

const xmax=641;
ymax=481;
var
Form1: TForm1;



implementation

uses Unit2, KomplexeZahlen, Eingabe, Ergeb, Eingabe2;


Bisher war das mit der Verbundvariablen TKomplex nur in der Unit KomplexeZahlen bekannt:


unit KomplexeZahlen;

interface
type
TKomplex = record
re : Real;
im : Real;
end;
function KompAddieren(A ,B : TKomplex) : TKomplex;
function KompMultiplizieren(A,B:TKomplex) : TKomplex;
function KompBetrag(Betrag:TKomplex) : Real;
function KompArgument(Argument:TKomplex) :Real;

implementation


Wie du oben siehst, wollt ich es genauso in der Unit1 anwenden, doch es geht nicht, daher hab ichs wieder auskommentiert.

Lass ichs normal stehen kommen folgende Fehlermeldungen (hab Fehlerstellen fett markiert):
[Fehler] Unit1.pas(13): ',' oder ':' erwartet, aber '=' gefunden [Zeile 13 ist das hier: TForm1 = class(TForm)]
[Fehler] Unit1.pas(59): Typ 'TKomplex' ist nicht vollständig definiert [Zeile 59 ist das hier: procedure EinlesenEinlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);]
[Fehler] Unit1.pas(68): 'END' erwartet, aber 'CONST' gefunden [Zeile 68 ist das hier: const xmax=641;]

Falls ich in Unit1 folgendes schreibe:


type
TKomplex = record
re : Real;
im : Real;
end;
TForm1 = class(TForm)
MainMenu1: TMainMenu;
...

dann kommt die Fehlermeldung:
[Fehler] Unit1.pas(221): Inkompatible Typen: 'KomplexeZahlen.TKomplex' und 'Unit1.TKomplex'
Das tritt in einer Rechenprozedur auf, die in Unit1 aufgerufen wird und dann in der Unit KomplexeZahlen ausgeführt wird. Diese funktioniert normalerweise.

Kannst du mir bitte weiterhelfen?

P.s. wenn es hilft, dass Programm hochzuladen, dann mach ich das gerne

Nagelbrett
2004-10-27, 18:56:00
Also das end muss da auf jeden Fall erstmal hin, um die record-Deklaration abzuschließen. Was genau der Fehler ist, der dann auftritt, kann ich dir aber nicht sagen ohne gesehen zu haben, wie Zeile 221 aus Unit1 da nun genau aussieht. Eventuell hast du TKomplex in zwei Units mehrmals unterschiedlich deklariert... deswegen inkompatible Typen (nur eine Vermutung).

Wenn es dir nichts ausmacht wäre es schon hilfreich, den Code mal hochzuladen, dann könnt ich mir das genauer anschaun.

mobius
2004-10-27, 19:03:24
Könntest du mir deine Email Addy per PM schicken? Dann kann ich dir das Programm komplett (ohne exe versteht sich) zuschicken. Das dürfte die Sache extrem erleichtern.

Nagelbrett
2004-10-27, 19:53:10
Hallo nochmal, ich hab mir den Code mal eben angeschaut, bei der geänderten Variante sind jedenfalls noch eine Menge Fehlerchen drin, z.b. hast du wie schon vermutet den Record TKomplex 2mal deklariert und der Aufruf der Prozedur passte so auch nicht (das "var" schreibt man nur bei der Implementierung, nicht beim Aufruf)

Jedenfalls: du möchtest also das Einlesen der Daten in den Editfeldern in eine Prozedur auslagern, die in der Unit "Eingabe2" implementiert ist, wenn ich das richtig verstanden habe? (der Übersicht halber, nehme ich an)

Wenn du dies so wie von dir versucht umsetzen möchtest, ist eine Prozedur wie du sie angelegt hast (mit var) wohl schon korrekt. Diese implementierst du dann in Eingabe2, allerdings als Teil deiner Formular-Klasse (bloß nicht im private-Abschnitt, sonst kannst du von Form1 aus nicht darauf zugreifen):


[...]

type
TEingabeForm2 = class(TForm)
[...]
procedure TEingabeForm2.Einlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);


[...]

implementation

[...]

procedure TEingabeForm2.Einlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);
begin
c.re:=StrToFloat(creEdit.text);
c.im:=StrToFloat(cimEdit.text);
A0.re:=StrToFloat(a0reEdit.text);
A0.im:=StrToFloat(a0imEdit.text);
Iteration:=StrToInt(IterationEdit.text);
Radius:=StrToInt(RadiusEdit.text);
Kante:=StrToFloat(KanteEdit.text);
end;
Wenn du das nicht als Teil der Form machst, müsstest du vor die ganzen Edit-Namen noch EingabeForm2. schreiben, aber so ist wohl besser (da ja auch Daten der Form verarbeitet werden).

Als nächstest musst du sicherstellen, dass in Eingabe2 der Typ TKomplex bekannt ist, also oben zur uses-Liste noch KomplexeZahlen anfügen (da dort TKomplex deklariert wird). Ebenso musst du dann natürlich in Unit1 die Unit Eingabe2 ins uses aufnehmen, damit deine Einlesen-Prozedur von dort aufgerufen werden kann (aber das war im urspr. Code sowieso schon der Fall).

Nun brauchst du nur in Unit1 in deinem JuliaMengen1Click... die Prozedur folgendermaßen aufrufen:
EingabeForm2.Einlesen(C, A0, Iteration, Radius, Kante);
die 'var's und Typenangaben kannst du dir hier logischerweise Sparen, da sie nur in der Deklaration/implementierung angegeben werden müssen, wie oben schon gesagt.
Die Variablen (Übergabeparameter) müssen an dieser Stelle natürlich trotzdem noch vorhanden sein, da sie ja von der Einlesen-Prozedur nur geändert werden, also darfst du sie in JuliaMengen1Click nicht aus dem var-abschnitt entfernen.
So sollte das ganze zumindest klappen (ich ging hierbei von dem Ursprungs-Code aus, also wenn du diesen hernimmst und meiner Anleitung schritt für schritt folgst, sollte es so klappen)

Jedoch noch ein kleiner Hinweis am Rande: man macht sich hier den Befehl ShowModal zunutze, der dein Main-Window solang stoppt, bis das aufgerufene Fenster wieder geschlossen wird. Alternativ könntest du auch einfach in JuliaMengen1Click NUR das andere Fenster anzeigen lassen, und in der Unit Eingabe2 (der unit des Fensters) dann im OnClick-Event des Bestätigen-Buttons die ganzen Variablen zuweisen und die Berechnungen ausführen. So könntest du dir den ganzen Umstand mit der Prozedur sparen und hättest es trotzdem in der richtigen Unit... aber keine Ahnung, was du dir dabei gedacht hast, es so zu machen... ist deine Entscheidung :)

mobius
2004-10-27, 20:51:48
Hab jetzt mal alles so geändert wie du geschrieben hast, aber funktioniert leider nicht wirklich.

Wenn ich das hier reinschreibe,

procedure TEingabeForm2.Einlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);


kommt folgende Fehlermeldung:
'=' erwartet, aber '(' gefunden

Ist das TEingabeForm2 vor der Prozedur vielleicht falsch?

Wenn ichs wegmache, kommen ein paar nette Fehler, selbst wenn ich uses KomplexeZahlen verwende:
[Fehler] Eingabe2.pas(28): Undefinierter Bezeichner: 'TKomplex'
[Fehler] Eingabe2.pas(45): Fehlender Parametertyp
[Fehler] Eingabe2.pas(47): Operator oder Semikolon fehlt
[Fehler] Eingabe2.pas(48): Undefinierter Bezeichner: 'cimEdit'
[Fehler] Eingabe2.pas(49): Operator oder Semikolon fehlt
[Fehler] Eingabe2.pas(49): Undefinierter Bezeichner: 'a0reEdit'
[Fehler] Eingabe2.pas(49): '(' erwartet, aber ')' gefunden
[Fehler] Eingabe2.pas(50): Operator oder Semikolon fehlt
[Fehler] Eingabe2.pas(50): Undefinierter Bezeichner: 'a0imEdit'
[Fehler] Eingabe2.pas(50): '(' erwartet, aber ')' gefunden
[Fehler] Eingabe2.pas(51): Operator oder Semikolon fehlt
[Fehler] Eingabe2.pas(51): Undefinierter Bezeichner: 'IterationEdit'
[Fehler] Eingabe2.pas(52): Operator oder Semikolon fehlt
[Fehler] Eingabe2.pas(52): Undefinierter Bezeichner: 'RadiusEdit'
[Fehler] Eingabe2.pas(52): ')' erwartet, aber Bezeichner 'text' gefunden
[Fehler] Eingabe2.pas(53): Operator oder Semikolon fehlt
[Fehler] Eingabe2.pas(53): Undefinierter Bezeichner: 'KanteEdit'
[Fehler] Eingabe2.pas(53): '(' erwartet, aber ')' gefunden
[Fehler] Eingabe2.pas(54): Anweisung erforderlich, aber Ausdruck vom Typ 'Text' gefunden
[Fataler Fehler] Unit1.pas(71): Verwendete Unit 'Eingabe2.pas' kann nicht compiliert werden



P.s. Muss ich A0, C, Iteration, Radius und Kante eigentlich noch global definieren oder ist das mit der beschriebenen Zeile schon so ok?

Nagelbrett
2004-10-27, 21:14:28
Oops, natürlich du hast recht... vor die Deklaration oben in der Class muss natürlich nicht nochmal das TEingabeForm2 (nur unten bei der Implementierung dann)

Hmm, aber wieso da nun noch immer Fehler kommen ist mir rätselhaft... ich habs ja genau so bei mir probiert und es ging. An welcher stelle hast du die andere Unit ins uses eingetragen? es gibt da ja einmal die möglichkeit im interface und einmal im implementation Abschnitt... du solltest es allerdings schon oben im interface Teil tun.

unit Eingabe2;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons, KomplexeZahlen;

type
TEingabeForm2 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
creEdit: TEdit;
cimEdit: TEdit;
a0reEdit: TEdit;
Edit4: TEdit;
a0imEdit: TEdit;
Edit6: TEdit;
IterationEdit: TEdit;
RadiusEdit: TEdit;
KanteEdit: TEdit;
Label7: TLabel;
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
procedure Einlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;

var
EingabeForm2: TEingabeForm2;

implementation

{$R *.DFM}

procedure TEingabeForm2.Einlesen(var C, A0 : TKomplex; var Iteration, Radius : Integer; var Kante : Real);
begin
c.re:=StrToFloat(creEdit.text);
c.im:=StrToFloat(cimEdit.text);
A0.re:=StrToFloat(a0reEdit.text);
A0.im:=StrToFloat(a0imEdit.text);
Iteration:=StrToInt(IterationEdit.text);
Radius:=StrToInt(RadiusEdit.text);
Kante:=StrToFloat(KanteEdit.text);
end;
..also so in etwa, dann dürften eigentlich die von dir genannten fehler auch nicht mehr auftreten.

mobius
2004-10-27, 21:25:46
OMG es funktioniert! Danke dir vielmals, du hast mir mein Leben gerettet :)