Delphi / Object-Pascal : Seite 03

Unser Ziel: der Taschenrechner

Was wir bisher geschafft haben, war recht einfach: wir haben die Ressourcen, die Delphi uns freundlicherweise frei Haus bietet, genutzt, um eine schöne Benutzeroberfläche zu bekommen, die zudem noch benutzerfreundlich ist. Unser Ziel dieser Lektion soll sein, nicht nur was für's Auge, sondern auch für die Mathematik zu schaffen: einen Taschenrechner, der sich auf die vier Grundrechenarten Addition, Subtraktion, Multiplikation und Division beschränkt.
Nun kann Delphi von sich aus leider nicht auch das übernehmen, weshalb wir wohl oder übel (hier eher wohl) zum eigentlichen Geschäft, dem Programmieren, kommen.

Der Quelltext

Da Sie ja ein interessierter Programmierer sind, werden Sie gerne wissen wollen, wie alles funktioniert. An dieser Stelle muss ich Sie leider (noch) enttäuschen, wir werden uns vorerst lediglich einen groben Überblick über den bisherigen Quelltext verschaffen und in späteren Lektionen sukzessive auf die einzelnen Bestandteile eingehen. Rufen Sie bitte das gespeicherte Programm auf, indem Sie in den entsprechenden Ordner gehen und die Datei Project1.dpr doppelklicken. Sollten Sie die Datei anders benannt haben, achten Sie bitte darauf, dass Sie die Datei mit der Endung dpr (Delphi Project) öffnen müssen.
Sie sollten jetzt Ihr Programm wieder erkennen. Das sollte aber nur nebensächlich sein. Wenn Sie sich nicht bereits im Quelltext befinden, drücken Sie bitte ein Mal auf [F12], womit sie sofort dahin gelangen. Im Quelltext sollte nun etwa das hier stehen:

Unit1 - Quelltext
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;
type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
end.
Der Quelltext kann sich durchaus zwischen den verschiedenen Versionen von Delphi unterscheiden, allerdings ist der Grundaufbau i.d.R. gleich. Fangen wir oben an: zuerst kommt ein Schlüsselwort: unit. Danach folgt der Name der Unit, also dem Programmteil, der für unser Formular arbeiten soll. Nach dem Namen Unit1 ist - und das können wir uns schon mal merken - ein Semikolon. Das zeigt Delphi an, dass hier ein eingegebener Befehl endet und der nächste kommt.
Weiter geht es mit dem zweiten Schlüsselwort implementation, welches wir später noch klären werden.
Es folgt uses und eine Auflistung aller Dinge, die unser Programm benutzt, auch dazu werden wir später noch kommen müssen. Damit werden wir uns aber noch Zeit lassen, es wird erst erforderlich, wenn wir mal unsere eigenen Units machen.
Als nächstes kommt type und dann alle Elemente, die im Formular auftauchen, einschließlich dem Formular selbst. Wir nehmen an dieser Stelle einfach zur Kenntnis, dass erst der Name der Komponente, dann ein Doppelpunkt und dann der Objekttyp folgt, auch das werden wir uns später zu Gemüte führen.
Auch um private und public werden wir uns nicht hier kümmern, auch wenn wir schon bald die Relevanz dieser beiden Begriffe erkennen werden.
Kommen wir nun - endlich - zu einem Begriff, den wir an dieser Stelle schon besprechen wollen: end;: damit werden wir sehr häufig arbeiten müssen, da es Delphi anzeigt, wo Prozeduren, Funktionen, Schleifen, Abfragen und sogar die gesamte Unit zu Ende sind. Ganz unten steht dann noch mal end., allerdings hier mit einem Punkt statt des Semikolons. Dieser Punkt zeigt an, dass dort die Unit zu Ende ist, und nicht irgendein Teil der Unit. Der Teil dazwischen soll uns - wieder - nicht interessieren, wir nehmen einfach hin, dass er existiert.

Variable in Delphi

Zur Vereinfachung der Programmierung bietet Delphi die Möglichkeit, Werte, die im Programmablauf zustande kommen, auf der Festplatte zwischenzuspeichern und darauf zuzugreifen. Diese gespeicherten Werte nennt man Variable (Singular wie Plural). Wie in der Mathematik verwendet man Variable zum Rechnen, aber in Delphi kann man ihnen auch einen Text oder einen anderen Wert zuweisen, anstatt ausschließlich Zahlen.
Um Fehlern vorzubeugen, weiß Delphi, dass in einem Editfeld nur Texte, so genannte Strings, stehen dürfen. Eine Zahl als solche muss zuerst in einen Text umgewandelt werden. Das verhindert, wie gesagt, dass ungewollt ein Wert in ein Feld geschrieben wird, der da nicht hin gehört.
Zum Rechnen nutzen wir Variable vom Typen Real. Dieser Typus erlaubt uns die Verwendung reeller Zahlen im Bereich von +/-2,9*10-39 bis +/-1,7*1038, also einer Eins, einer Sieben und 37 Nullen. Natürlich gibt es auch die Null als solche.

Delphi "lernt" addieren

Wechseln Sie nun bitte wieder zu ihrem Formular (nicht vergessen: [F12]-Taste!). Wir haben nun vor, unseren ersten Button (der mit der Aufschrift "+") funktionsfähig zu machen. Doppelklicken Sie bitte den Button. Sie kommen sofort zurück in den Quelltext, allerdings ist vor dem end. jetzt folgendes hinzugekommen:

neu hinzugekommener Quelltext
procedure TForm1.Button1Click(Sender: TObject);
begin
end;
Delphi ist dem Programmierer gegenüber sehr freundlich. Es ist in der Lage, automatisch eine Routine zu erstellen, wenn man ein Objekt im Formular (oder das Formular selbst, später auch dazu mehr) doppelt anklickt. Im Falle unseres Buttons wird die so genannte OnClick-Routine erstellt, also die Routine, die ausgeführt wird, wenn man auf den Button klickt.
Stellt sich nur eine kleine Frage: was genau ist eine Routine? Eine Routine ist nichts anderes, als ein Algorithmus, der immer dann ausgeführt wird, wenn ein Ereignis eintritt, z.B. der Klick des Benutzers auf den Button. Was ist nun schon wieder ein Algorithmus? Ein Algorithmus ist eine auszuführende Folge von Befehlen, die der Programmierer eingibt.
So weit, so gut. Wir stellen also fest, dass Delphi uns bereits einen (enormen, wenn auch gering scheinenden) Teil unserer Arbeit abgenommen hat. Nun sind wir dran: zunächst brauchen wir drei Variable: eine für die erste Zahl, eine für die Zweite und eine für das Ergebnis. In Delphi müssen wir vor dem Gebrauch einer Variable sie immer erst "anmelden", um genau zu sein, deklarieren (was dasselbe aussagt). Nun hat Delphi keine Rezeption, also werden wir uns helfen müssen. Das ist der ideale Zeitpunkt, ein neues Schlüsselwort einzuführen, das wir bereits weiter oben gesehen haben: var. Geben Sie bitte zwischen procedure TForm1.Button1Click(Sender: TObject); und begin das Wort var ein. Also etwa so:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var
begin
end;
Nach diesem Schlüsselwort kommen nun alle Variable, die wir brauchen. Eine Variable hat neben ihrem Wert auch einen Namen in Delphi. In der Mathematik beschränkt man sich i.d.R. auf einen Buchstaben (meistens x), was in Delphi nicht notwendig ist. Hier können ganze Worte als Variablenname fungieren. Wir wollen unsere Variable z1, z2 und ergebnis nennen, was wir - getrennt durch Kommata - hinter var schreiben:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis
begin
end;
Weiter oben stellten wir bereits fest, dass unsere Objekte immer einen Typ zugewiesen bekommen haben. Genau das muss man auch mit Variablen machen. Hinter die Reihe setzen wir daher einen Doppelpunkt, um anzukündigen, dass der Typ folgt, und dann nennen wir den Typus, in unserem Beispiel real:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
end;
Bitte beachten Sie, dass hinter den Typnamen grundsätzlich immer ein Semikolon steht! Alternativ kann man übrigens auch folgendes schreiben:
Alternative
procedure TForm1.Button1Click(Sender: TObject);
var z1: real;
    z2: real;
    ergebnis: real;
begin
end;
Das ist aber nicht so effektiv bzw. zu viel Aufwand für dasselbe Ergebnis. Wir merken uns: Variable vom gleichen Typ kann man, durch Kommata getrennt, zusammenfassen.
Nach dieser Erkenntnis kommen wir nun zum nächsten Schritt: wir weisen unseren Variablen Werte zu. Wir begeben uns dafür zwischen begin und end;. Man kann sich diese beiden Begriffe wie eine Art Klammer vorstellen, die vorgibt, wo (in diesem Falle) die Prozedur anfängt und wo sie aufhört. Daher stehen meistens beide Begriffe zusammen (wobei wir später feststellen werden, dass man nicht immer beide Begriffe zusammen hat). Zuerst wollen wir den Wert aus unserem Editfeld mit dem Namen Edit1 in die Variable z1 schreiben. Dabei müssen wir aber etwas Wichtiges beachten: im Editfeld selbst steht ein String, die Variable ist eine vom Typen Real. Das ergibt für Delphi einen Widerspruch. Delphi kann keine Texte in eine Zahlenvariable speichern, auch wenn der Text eine Zahl ist. Es ist daher nötig, den Inhalt des Feldes in einen anderen Typen zu wandeln.
Bevor wir das tun, müssen wir uns aber erst einmal anschauen, wie wir einer Variable einen Wert zuweisen. Zuerst schreiben wir den Namen der Variable, damit Delphi weiß, wessen Wert verändert werden soll. Dann schreiben wir den so genannten Zuweisungsoperator := (Doppelpunkt Gleich) und dann den Wert, der zugewiesen werden soll. Wir werden uns daran gewöhnen müssen, dass eine Zuweisung stets durch := erfolgt, und nie durch = alleine.
Wie lesen wir nun den Wert des Editfeldes aus? Das ist denkbar einfach. Wir sprechen erst das Objekt an, und zwar - wie beim Menschen - mit dem Namen. In unserem Beispiel ist dies Edit1. Das sehen wir im Objektinspektor, wenn wir das Feld markiert haben, unter der Eigenschaft Name. Danach kommt die Eigenschaft, getrennt durch einen Punkt, die wir ansprechen wollen. Bei uns geht es um den Inhalt des Feldes, also die Eigenschaft Text. Es ergibt sich für uns also folgende Zuweisung:
z1 := Edit1.Text;
Wie bereits gesagt ist das noch ein Widerspruch in sich, denn dort steht nichts anderes als:
Reelle Zahl := Text
Also wird einer reellen Zahl ein Text zugewiesen, was nicht geht. Wir müssen den Text also umwandeln in eine reelle Zahl. Und auch dafür haben die Entwickler von Delphi uns etwas bereit gestellt: StrToFloat(). Ausgeschrieben bedeutet das String to Float, also Text zu Fließkommazahl. In den Klammern wird angegeben, was umgewandelt werden soll. In unserem Beispiel muss Edit1.Text zum Fließkommawert gemacht werden, also ergibt sich folgende Zuweisung:
z1 := StrToFloat(Edit1.Text);
Unser Programm sieht jetzt also schon so aus:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
end;
Genau dasselbe machen wir nun wieder mit z2 und Edit2.Text:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
end;
Wie erhalten wir nun die Summe? Ganz einfach: der Variablen ergebnis weisen wir einfach den Wert z1 + z2 zu, denn Delphi kann auch durchaus rechnen. Also:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 + z2;
end;
Sie können ja jetzt mal spaßeshalber Ihr Programm mit [F9] starten, seien Sie aber bitte nicht enttäuscht, wenn Sie zwei Zahlen ausgeben und trotz Klick auf den entsprechenden Button nichts passiert. Das liegt daran, dass Delphi zwar genau das macht, was da steht, aber nicht, was Sie wollen. Wir haben noch keine Ausgabe des Ergebnisses einprogrammiert, was wir jetzt nachholen wollen. Wir wollen also dem Editfeld Edit3 den Wert der Variablen ergebnis zuweisen. Das geht analog zur Wertezuweisung bei Variablen so:
Edit3.Text := ergebnis;
Aber wir haben etwas Wichtiges vergessen: dort steht:
Text := Reelle Zahl;
also ein Widerspruch in sich! Wir müssen unsere reelle Zahl diesmal in einen Text umwandeln, und zwar mit dem Befehl FloatToStr(), also der genauen Umkehrung von StrToFloat:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 + z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
So, jetzt kommt der Augenblick der Wahrheit: wir haben den Variablen Werte zugewiesen, wir haben sie addiert und gespeichert, dann haben wir den gespeicherten Wert ausgegeben. Werden wir unser erstes kleines Erfolgserlebnis haben? Drücken Sie [F9] und geben zwei Zahlen ein. Und jetzt auf den "+"-Button klicken...
Taschenrechner
Wunderbar, er funktioniert. Belegen wir nun analog zur Addition alle anderen Buttons:
erweiterter Quelltext
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 + z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button2Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 - z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button3Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 * z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button4Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 / z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
Nicht vergessen: um die Routine für einen Button zu machen, immer den Button doppelklicken!!! Reines Quelltext-Schreiben bringt leider nichts.

Programm beenden

So, alle Buttons funktionieren. Wirklich alle? Nein! Einer widersetzt sich noch wacker: der mit der Aufschrift "Ende". Da werden wir aber auch noch was ändern. Da dieser Button nur das Programm beenden soll, ist sein Quelltext denkbar einfach:

Programm beenden
procedure TForm1.Button5Click(Sender: TObject);
begin
  close;
end;
Der Befehl close; beendet das Programm, und das war es auch schon. Da wir hier weder Variable brauchen noch sonst etwas damit zu tun haben, lassen wir hier einfach das Schlüsselwort var weg.
Für die Interessierten hier noch der gesamte Quelltext:
gesamter Quelltext
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;
type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 + z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button2Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 - z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button3Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 * z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button4Click(Sender: TObject);
var z1, z2, ergebnis: real;
begin
  z1 := StrToFloat(Edit1.Text);
  z2 := StrToFloat(Edit2.Text);
  ergebnis := z1 / z2;
  Edit3.Text := FloatToStr(ergebnis);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
  close;
end;
end.

Aufgaben

3.1 Grundlegende Rechenoperationen

Lektion 02 | Lektion 04