Ampelprogrammierung, and innerhalb von if Anweisungen

Für Fragen von Einsteigern und Programmieranfängern...
MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Ampelprogrammierung, and innerhalb von if Anweisungen

Beitrag von MAC »

Du hast recht, es ist shape 2...
Naja, der Fehler in deinem Programm ist in diesem Fall die Variable x.
Diese Variable ist als eine sogenannte lokale Variable definiert, das bedeutet diese Variable wird zu begin der Procedure Button1Click erzeugt und danach wieder gelöscht...
Das Würde also bedeutetn, die variable x wird erstellt, sie hat den Wert 0, also Rote Ampel, sie wird um eins erhöht aber sie wird auch wieder gelöscht.
Beim nächsten klick wird sie wieder erstellt, ist wieder 0 und nicht 1...

Wenn man will, dass eine Variable nübergreifend, bei mehreren Proceduren, oder bei verschidenen Aufrufen einer Procedure (dein Fall) noch vorhanden ist, muss man sie Global definieren, das macht man am besten hier:


Code: Alles auswählen

type
  TForm1 = class(TForm)
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
  x:integer; // Hier hinter Form1
 
implementation

Code: Alles auswählen

Signatur := nil;

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Ampelprogrammierung, and innerhalb von if Anweisungen

Beitrag von pluto »

Sinnvoller wäre es diese Variable genauso innerhalb von TForm1 zu deklarieren. Dann gehört sie praktisch zu Klasse dazu.
MFG
Michael Springwald

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Ampelprogrammierung, and innerhalb von if Anweisungen

Beitrag von fliegermichl »

Hallo,

die CASE Version ist meiner Meinung nach auch übersichtlicher. Aber Du wolltest ja eine funktionierende Version mit if then else

Code: Alles auswählen

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  if (Shape1.Brush.Color = clWhite) and (Shape2.Brush.Color = clWhite) and (Shape3.Brush.Color = clWhite) then
   Shape1.Brush.Color := clRed
  else if (Shape1.Brush.Color = clRed) and (Shape2.Brush.Color = clWhite) then
   Shape2.Brush.Color := clYellow
  else if (Shape1.Brush.Color = clRed) and (Shape2.Brush.Color = clYellow) then
  begin
   Shape1.Brush.Color := clWhite;
   Shape2.Brush.Color := clWhite;
   Shape3.Brush.Color := clLime;
  end else if (Shape3.Brush.Color = clLime) then
  begin
   Shape3.Brush.Color := clWhite;
   Shape2.Brush.Color := clYellow;
  end else
  begin
   Shape1.Brush.Color := clRed;
   Shape2.Brush.Color := clWhite;
  end;
end;


Das geht zwar, ist aber nur schwer zu lesen und vor allem zu verstehen.
Spätestens wenn Deine Programme größer werden, wird diese Vorgehensweise schnell unübersichtlich.

Am Anfang etwas schwieriger zu verstehen, aber später ungemein hilfreich ist, Properties zu verwenden.
Als erstes deklarierst Du einen Datentyp, welcher nur die möglichen Ampelzustände definiert.
Am besten oberhalb der Definition des Formulares, weil Du diesen neuen Datentyp dann auch gleich im Formular verwenden kannst.

Code: Alles auswählen

type
  // Typ, welcher die möglichen Ampelstellungen definiert
  TAmpelstatus = (asRot, asRotGelb, asGruen, asGelb);
 
  { TForm1 }
 
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
   ...


Im Formular deklarieren wir ein Feld fAmpelstatus vom Typ TAmpelstatus und zwar im privaten Bereich des Formulares sowie eine Procedure SetAmpelstatus.
Im public Teil des Formulares deklarierst Du eine property Ampelstatus.
Diese Property kannst Du im Programm verwenden wie eine Variable, also einen Wert zuweisen oder den aktuellen Wert abfragen.
Einfach durch eine Zuweisung der Form

Code: Alles auswählen

Form1.Ampelstatus := asGruen;


wird automatisch das richtige Shape mit der richtigen Farbe befüllt.
Das klingt am Anfang vielleicht etwas umständlich, erleichtert aber später das Leben erheblich.

Hier die Definition

Code: Alles auswählen

TForm1 = class (TForm)
   ...
  private
    { private declarations }
    fAmpelstatus : TAmpelstatus;
    procedure SetAmpelstatus(Value : TAmpelstatus);
  public
    { public declarations }
    property  Ampelstatus : TAmpelstatus read fAmpelstatus write SetAmpelstatus;
  end;


Durch die Angabe write SetAmpelstatus bei der Definition der property Ampelstatus ruft der Compiler automatisch die angegebene Procedure auf, wenn der "Variablen" Ampelstatus ein Wert zugewiesen wird und zwar egal wie oder wo.
Diese Procedure ist die einzige Stelle im Programm, welche sich um die richtigen Farbgebungen kümmert.
Du könntest z.B. in Deinem Formular noch 4 Radiobuttons mit "Rot", "Rot/Gelb", "Grün" und "Gelb" einfügen und in der jeweiligen Ereignisbehandlungsroutine für OnClick
schreiben: Ampelstatus := asRot;

Die Implementierung der Methode (so werden Prozeduren und Funktionen genannt, wenn Sie in einer Klasse verwendet werden) SetAmpelstatus schaut dann so aus.

Code: Alles auswählen

procedure TForm1.SetAmpelstatus(Value: TAmpelstatus);
begin
  if (fAmpelstatus <> Value) then
  begin
    fAmpelstatus := Value;
    Shape1.Brush.Color := clWhite;
    Shape2.Brush.Color := clWhite;
    Shape3.Brush.Color := clWhite;
    case fAmpelstatus of
     asRot     :  Shape1.Brush.Color := clRed;
     asRotGelb : begin
                  Shape1.Brush.Color := clRed;
                  Shape2.Brush.Color := clYellow;
                 end;
     asGelb    : Shape2.Brush.Color := clYellow;
     asGruen   : Shape3.Brush.Color := clLime;
    end;
  end;
end;


Der Einfachheit halber definiert man nun noch eine Methode mit dem Namen "NextStatus", welche dem aktuellen Status der Ampel entsprechend den nächsten richtigen
Schaltzustand einstellt.
Unter public fügst Du einfach

Code: Alles auswählen

procedure NextStatus;
ein und die Implementation sieht so aus:

Code: Alles auswählen

procedure TForm1.NextStatus;
begin
  case Ampelstatus of
   asRot     : Ampelstatus := asRotGelb;
   asRotGelb : Ampelstatus := asGruen;
   asGruen   : Ampelstatus := asGelb;
   asGelb    : Ampelstatus := asRot;
  end;
end;


Im OnClick des Buttons rufst Du diese nun einfach auf:

Code: Alles auswählen

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
 NextStatus;
end;


Im Anhang ist das Projekt nochmal zum Nachvollziehen. Hier ist noch ein zusätzliches Feld fUpdating vorhanden.
Hintergrund ist folgender. Wenn der Button die Ampel auf die nächste Stufe schaltet, soll auch der entsprechende Radiobutton aktiviert werden.
Da dieser aber wiederum in seinem OnClick Event den Status der Ampelschaltung ändert, käme es zu einer Endlosschleife.

Gruß
Michl
Dateianhänge
ampel.zip
Beispielprojekt kleine Ampel mit Properties
(100.46 KiB) 147-mal heruntergeladen

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Ampelprogrammierung, and innerhalb von if Anweisungen

Beitrag von pluto »

@fliegermichl
Gut geschrieben der Code. Vielleicht sollten wir das mal in einem "Tutorial" beschreiben. Außerdem könnten ja noch ein paar Autos herum fahren.
MFG
Michael Springwald

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Ampelprogrammierung, and innerhalb von if Anweisungen

Beitrag von fliegermichl »

Hallo,

eine Ampelsteuerung für eine etwas größere Kreuzung mit Fußgängerampeln, Abbiegerspuren, Kontaktschwellen usw. ist schon eine recht anspruchsvolle Programmieraufgabe.
Ich finde, daß das schon ein recht geeignetes Projekt für ein Tutorial ist.

Man kann Klassenbasierte Programmierung, grafische Elemente, Animationen (fahrende Autos, alte Oma, welche über die Fußgängerampel geht usw.) einbringen.

Da kommt schon einiges zusammen.

Gruß
Michl

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Ampelprogrammierung, and innerhalb von if Anweisungen

Beitrag von pluto »

Da kommt schon einiges zusammen.

habe ich mir auch schon oft überlegt. Aber da tauchen einige Fragen auf. Gerade wenn es nicht nur eine Kreuzung sein soll, sonder nein ganzen Straßen-Netz mit Bussen, Bahn und soweiter. Das wäre eine Prima sache für eine Tutorial Serie. Z.B. würde ich die verschiedenen Überquerungs Arten wie Kreuzungen, T-Stück und soweiter als einzelne Objekte beschreiben. Und dazu gibt es dann Ampeln.

Das Problem dabei ist: Es Visuell zu machen. Wie wird eine Ampel am besten eingezeichnet? Damit meine ich nicht die Technik, sondern allgemein? Werden z.b. neben den Ecken einer Kreuzung einfach kreise gezeichnet? drei Stück pro Ecke? oder eher Sechs Stück?
MFG
Michael Springwald

Antworten