brauche Hilfe mit Programmaufbau

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
stefankr77
Beiträge: 9
Registriert: Mo 13. Aug 2012, 20:16

brauche Hilfe mit Programmaufbau

Beitrag von stefankr77 »

Hallo!

ich habe gerade angefangen, mit Lazarus programmieren zu lernen, und ich komme bei meinem Übungsprogramm nicht weiter. So bin ich auf dieses Forum gestoßen...

Mein Programm ist ein einfaches Formular mit einem Label oben, darunter ein Edit und darunter ein Button. Ich will erreichen, dass der Benutzer nach jedem Klick auf den Button eine andere Anweisung auf dem Label sieht. So sollen dann bei jedem Schritt die benötigten Werte abgefragt und den Variablen zugewiesen werden. Am Ende wird alles ausgerechnet und das Ergebnis im Label angezeigt.

Jetzt meine Fragen:
1. Wie kann ich ganz zum Schluss nach der Berechnung mit dem Button wieder zum ersten Schritt zurückspringen, so dass alle Werte wieder abgefragt werden und ich eine neue Berechnung durchführen kann? Ich habe es mal versucht mit "If Nr = 7 then Nr := 1", aber dann stürzte das Programm ab.

2. Kann ich das nicht eleganter aufbauen als mit dem Hochzählen der Variablen "Nr"? Ich weiß leider nicht, wie ich sonst erreichen kann, dass Schritt für Schritt über das Label verschiedene Werte abgefragt werden.

Ich wäre Euch sehr dankbar für alle Tipps!

Viele Grüße,
Stefan

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  Nr:= 0;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Inc (Nr);
  If Nr = 1 then
  begin
    Edit1.Text := '';
    Label1.caption := 'Was ist der Kaufpreis des Autos?';
    Edit1.setfocus;
    Button1.Caption := 'Weiter';
  end;
 
  If Nr = 2 then
  begin
    Preis := StrToFloat(Edit1.text);
    Label1.Caption := 'Wieviel Kraftstoff braucht es auf 100km?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 3 then
  begin
    Verbrauch := StrToFloat(Edit1.text);
    Label1.Caption := 'Wieviele km fährst du im Jahr?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 4 then
  begin
    JahresKm := StrToFloat(Edit1.text);
    Label1.Caption := 'Wie hoch ist der Kraftstoffpreis?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 5 then
  begin
    Stoff := StrToFloat(Edit1.text);
    Label1.Caption := 'Wieviele Jahre willst du das Auto fahren?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 6 then
  begin
    Dauer := StrToFloat(Edit1.text);
    Edit1.Text := '';
    Kosten := (((Stoff*Verbrauch)/100)*JahresKm)*Dauer +Preis;
 
    Label1.Caption := 'Die Kosten über '
                   + FloatToStr(Dauer)
                   + ' Jahr(e) betragen '
                   + FloatToStr(Kosten)
                   + ' EUR!';
    Button1.caption := 'Neu';
  end;
end;

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: brauche Hilfe mit Programmaufbau

Beitrag von Socke »

Willkommen im Forum!
stefankr77 hat geschrieben:1. Wie kann ich ganz zum Schluss nach der Berechnung mit dem Button wieder zum ersten Schritt zurückspringen, so dass alle Werte wieder abgefragt werden und ich eine neue Berechnung durchführen kann? Ich habe es mal versucht mit "If Nr = 7 then Nr := 1", aber dann stürzte das Programm ab.
Wie ist denn die Fehlermeldung? Was wird angezeigt oder ausgegeben?
stefankr77 hat geschrieben:2. Kann ich das nicht eleganter aufbauen als mit dem Hochzählen der Variablen "Nr"? Ich weiß leider nicht, wie ich sonst erreichen kann, dass Schritt für Schritt über das Label verschiedene Werte abgefragt werden.
Es gibt viele Wege dein Ziel zu erreichen. Die eleganteste Methode wäre, die Zählvariable als einen Teil des Formulars zu machen. Da du genau diesen Teil aus deinem Quelltext herausgelassen hast, gebe ich dir einen kurzen Vorschlag von mir. Damit besitzt dein Formular eine Variable mit dem Namen Nr vom Typ Integer.

Code: Alles auswählen

type
  TForm1 = class(TForm)
    // hier sind die Schaltflächen, Labels, etc.
   // und die Ereignisbehandler (OnClick usw.)
  private
    Nr: Integer;
  end;
Natürlich gibt es noch weitere Möglichkeiten. Die sind aber für solch ein Projekt zu Aufwändig (dabei denke ich an Eigenschaften/"property" oder Aufzählunge/"enumeration"). Zunächst solltest du diesen Absturz beheben und sicherstellen, dass dein Programm nicht abstürzt, wenn man einen fehlerhaften Wert eingibt (zum Beispiel: "5a" Kilometer pro Jahr).

Wenn du noch noch weitere Fragen hast: Frag einfach nach.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

stefankr77
Beiträge: 9
Registriert: Mo 13. Aug 2012, 20:16

Re: brauche Hilfe mit Programmaufbau

Beitrag von stefankr77 »

Vielen Dank für die Hilfe. Ich habe mir auch selbst noch Gedanken gemacht und bin auch dahinter gekommen, wo es hakte. Die von mir genannte Fehlermeldung hieß: ' ' is not a valid float. So, wie ich es es zuerst geschrieben hatte ("If Nr = 7 then Nr := 1"), fehlte etwas, denn das Programm sprang tatsächlich zu Nr = 1 zurück, erwartete dann jedoch einen Wert im Edit-Feld. Da dieses aber leer war, bevor ich den Button erneut anklickte, kam es wegen des leeren Felds durcheinander und gab die Fehlermeldung aus.

Ich habe mein Programm jetzt mal verbessert: Falsche Eingaben wie die von dir genannten "5a" km pro Jahr werden jetzt abgefangen, und es springt immer schön an den Ausgangspunkt zurück. Ich bin jetzt mächtig stolz auf mich, hehe :D

Aber ich habe noch 2 Fragen:

1. Ich habe die Variable "Nr" zusammen mit den anderen unter "var" deklariert. Was ist anders, wenn ich sie wie von dir vorgeschlagen unter "private" deklariere?

2. Wie erreiche ich, dass ich nach Eingabe eines Wertes mit der Enter-Taste weiter komme, anstatt den Button anklicken zu müssen?


Code: Alles auswählen

unit autorechner_unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 
 
var
  Form1: TForm1;
  Stoff, Preis, JahresKm, Verbrauch, Dauer, Kosten: Real;
  Nr: Integer;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Nr:= 0;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
  begin
  try
   Inc (Nr);
  If Nr = 1 then
  begin
    Edit1.Text := '';
    Label1.caption := 'Was ist der Kaufpreis des Autos?';
    Edit1.setfocus;
    Button1.Caption := 'Weiter';
  end;
 
  If Nr = 2 then
  begin
    Preis := StrToFloat(Edit1.text);
    Label1.Caption := 'Wieviel Kraftstoff braucht es auf 100km?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 3 then
  begin
    Verbrauch := StrToFloat(Edit1.text);
    Label1.Caption := 'Wieviele km fährst du im Jahr?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 4 then
  begin
    JahresKm := StrToFloat(Edit1.text);
    Label1.Caption := 'Wie hoch ist der Kraftstoffpreis?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 5 then
  begin
    Stoff := StrToFloat(Edit1.text);
    Label1.Caption := 'Wieviele Jahre willst du das Auto fahren?';
    Edit1.Text := '';
    Edit1.setfocus;
  end;
 
  If Nr = 6 then
  begin
    Dauer := StrToFloat(Edit1.text);
    Edit1.Text := '';
    Kosten := (((Stoff*Verbrauch)/100)*JahresKm)*Dauer +Preis;
 
    Label1.Caption := 'Die Kosten über '
                   + FloatToStr(Dauer)
                   + ' Jahr(e) betragen '
                   + FloatToStr(Kosten)
                   + ' EUR!';
    Button1.caption := 'Neu';
  end;
 
  If Nr = 7 then
  begin
    Nr := 1;
    Label1.caption := 'Was ist der Kaufpreis des Autos?';
    Button1.caption := 'Weiter';
  end;
 
  except
    Label1.caption := 'Falsche Eingabe! Neue Berechnung?';
    Nr := 0;
  end;
 
  end;
 
end.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: brauche Hilfe mit Programmaufbau

Beitrag von Socke »

stefankr77 hat geschrieben:1. Ich habe die Variable "Nr" zusammen mit den anderen unter "var" deklariert. Was ist anders, wenn ich sie wie von dir vorgeschlagen unter "private" deklariere?
Wenn die Variable unter "var" steht, gehört sie zu der Unit (das heißt zu dieser Quelltextdatei) und du kannst von jeder Funktion darauf zugreifen. Sie ist also sozusagen "global" in deinem Programm verfügbar; daher nennt man sie auch globale Variable.

Wenn du sie unter "private" schreibst, gehört sie zu diesem Formular. Das erkennst du daran, dass das "private" seinerseits in der Klasse enthalten ist. Dann kannst du nur auf diese Variable zugreifen, wenn du auch das Formular kennst. Genauer gesagt bestimmt das "private", dass nur Funktionen dieser Klasse auf die Variable zugreifen dürfen.

Code: Alles auswählen

type
  TForm1 = class(TForm) // hier fängt die Klasse TForm1 an
  private // nur diese Klasse kann auf die folgenden Variablen und Funktionen zugreifen
    Nr: Integer;
  public // alle können auf die folgenden Variablen zugreifen
    Nr2: Integer;
  end;  // hier hört die Klasse TForm1 auf
Globale Variablen gehören nicht zu einem guten Programmierstil. Du weißt bei großen Programmen nicht, an welchen Stellen du alles auf die Variable zugreifst und du kannst auch nicht sicherstellen, dass sie sich in einem gültigen Bereich (hier 0 bis 7) befindet. Daher ist es besser, Variablen nur dort hin zu schreiben, wo sie vom Sinn her hingehören oder herkommen.
stefankr77 hat geschrieben:2. Wie erreiche ich, dass ich nach Eingabe eines Wertes mit der Enter-Taste weiter komme, anstatt den Button anklicken zu müssen?
Zuerst musst du deinem Eingabefeld einen Ereignisbehandler (engl. Eventhandler) für Tastenanschläge geben.
  • Wähle im Entwurfsmodus das Eingabefeld aus. Im Objektinspektor wurde das Eingabefeld automatisch ausgewählt.
  • Klicke im Objektinspektor auf den Reiter "Ereignisse"
  • Suche das Ereignis OnKeyPress
  • Klicke in das Eingabefeld neben dem Ereignis-Namen; eine kleine Schaltfläche mit drei Punkten (...) erscheint dort
  • Klicke auf die Schaltfläche; Lazarus wechselt zum Quelltext; dort wurde eine Funktion angelegt, die bei jedem Tastendruck aufgerufen wird
Hier kannst du jetzt den Code hineinschreiben. Du musst nur überprüfen, ob die Taste die Entertaste war; wenn ja sagst du der Schaltfläche, dass sie angeklickt wurde. Hier sind noch ein paar Hilfen:

Code: Alles auswählen

Button1.Click; // jetzt läuft alles ab, als ob die Schaltfläche selbst angeklickt worden wäre
Ord('c') // liefert den Zahlwert eines Buchstabens
Chr(13) // liefert den Buchstaben zu einem Zahlwert
// Die Enter-Taste hat den Zahlwert 13
var
  c: Char; // Im einer Variablen vom Typ Char kannst du genau einen ASCII-Buchstaben (1 Byte) speichern
c := Chr(13);  // In der Variablen c den Buchstaben "Enter" (oder Zeilenumbruch; engl. Carriage Return, CR) speichern
c := #13; // so kannst du auch Buchstaben aus einem Zahlwert festlegen
c := 13; // das geht nicht - 13 ist kein Buchstabe
Viel Spaß damit!
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2813
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: brauche Hilfe mit Programmaufbau

Beitrag von m.fuchs »

Socke hat geschrieben:Wenn du sie unter "private" schreibst, gehört sie zu diesem Formular. Das erkennst du daran, dass das "private" seinerseits in der Klasse enthalten ist. Dann kannst du nur auf diese Variable zugreifen, wenn du auch das Formular kennst. Genauer gesagt bestimmt das "private", dass nur Funktionen dieser Klasse auf die Variable zugreifen dürfen.
Entschuldigung, dass ich hier mal wieder klugschei*e. Aber wenn etwas private deklariert ist, dann kann man darauf von überall in der gleichen Unit zugreifen.
Soll es wirklich nur die Klasse können, ist strict private die richtige Wahl.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

stefankr77
Beiträge: 9
Registriert: Mo 13. Aug 2012, 20:16

Re: brauche Hilfe mit Programmaufbau

Beitrag von stefankr77 »

Vielen Dank für die hilfreiche Antwort, Socke. Du bist spitze!
Ich muss noch viel lernen und werde gleich etwas weiterbasteln... Bis zu meiner nächsten Frage wird es bestimmt nicht all zu lange dauern! ;)
Viele Grüße

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: brauche Hilfe mit Programmaufbau

Beitrag von Socke »

m.fuchs hat geschrieben:Entschuldigung, dass ich hier mal wieder klugschei*e. Aber wenn etwas private deklariert ist, dann kann man darauf von überall in der gleichen Unit zugreifen.
Soll es wirklich nur die Klasse können, ist strict private die richtige Wahl.
Da hast du Recht. In der Praxis wird häufig private genutzt, auch wenn strict private ausreichend wäre. Die Möglichkeiten von private auszunutzen halte ich persönlich für einen nicht ganz so tollen Programmierstil.
stefankr77 hat geschrieben:Vielen Dank für die hilfreiche Antwort, Socke. Du bist spitze!
Ich muss noch viel lernen und werde gleich etwas weiterbasteln... Bis zu meiner nächsten Frage wird es bestimmt nicht all zu lange dauern! ;)
Viele Grüße
Danke. So etwas hört man gerne :D
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten