|
|
 |
|
 |
|
|
Delphi Tutorial: Funktionsplotter
|
|
|
 |
|
In diesem Tutorial zeige ich euch, wie man einen einfachen Funktionsplotter mit Delphi realisieren kann. Das Tutorial ist besonders für Einsteiger geeignet, die sich mit Delphi befassen möchten und noch wenig Programmiererfahrung haben.
Als erstes öffnen wir ein neues Projekt des Typs "Anwendung". Wir wechseln mit F12 in den Code Editor und erstellen dort eine neue Funktion:
 |
|
 |
|
|
function f(x: real): real;
begin
end;
|
|
|
 |
|
 |

Dies wird unsere Funktion, um den Funktionswert einer beliebigen Funktion an einer beliebigen Stelle berechnen zu können. Damit wir später keine Probleme bekommen, wenn wir das Projekt mit weiteren Funktionen erweitern, sollten wir die Funktion auch oben im Deklarationsteil angeben:
 |
|
 |
|
|
type
TForm1 = class(TForm)
private
{ private-Deklarationen }
public
{ public-Deklarationen }
end;
function f(x: real): real;
|
|
|
 |
|
 |

Damit weiß Delphi immer, dass diese Funktion existiert und es gibt keine Probleme bei dem Aufruf der Funktion. Würde man die Funktion im Deklarationsteil nicht deklarieren, so müsste die Funktion im Quellcode immer vor dem Quellcode stehen, der die Funktion aufruft.
Der Name dieser Funktion ist f. Sie besitzt einen Übergabeparameter, in diesem Fall die Variable x. Diesen benutzen wir nachher, um anzugeben, an welcher Stelle der Funktionswert berechnet werden soll. Der Rückgabewert dieser Funktion (Prozeduren besitzen einen solchen nicht!) gibt später den berechneten Funktionswert an.
Als Datentyp sowohl für den Übergabeparameter als auch für den Rückgabewert benutzen wir real, ein Format für Gleitkommazahlen. Alternativ könnten wir auch Single, Double oder Extended benutzen, wobei man mit dem Datentyp real im mittleren Bereich liegt, was die maximalen Größen der verschiedenen Datentypen angeht (6 Byte).
Nun müssen wir die Funktion noch programmieren. Dazu müssen wir wissen, welche mathematische Funktion wir ausgeben lassen möchten. Ich habe mich hier für eine einfache Parabel entschieden. Der Sourcecode muss also wie folgt aussehen:
 |
|
 |
|
|
function f(x: real): real;
begin
result := x*x;
end;
|
|
|
 |
|
 |

Die Variable result gibt immer den Rückgabewert der Funktion an. Alternativ könnte man in Delphi auch schreiben:
 |
|
 |
|
|
function f(x: real): real;
begin
f := x*x;
end;
|
|
|
 |
|
 |

Hier wird der Name der Funktion als Rückgabewert benutzt. Welche Variante man wählt ist Geschmackssache und hat keinerlei Unterschiede.
Die Funktion berechnet nun also den Funktionswert der Funktion x^2 von jedem beliebigen Wert x. Dieser wert x wird über den Übergabeparameter angegeben.
Nun können wir uns dem grafischen Darstellen dieser Funktion widmen. Dazu wechseln wir zuerst wieder mit F12 auf das Formular. Wir wählen oben den Reiter "Zusätzlich" und klicken doppelt auf den Eintrag "Image". Das neu erschienene Objekt auf dem Formular passen wir mit der Maus an Größe und Position an, so dass das Formular dann in etwa so aussehen sollte:
|
Wir müssen beachten, dass das Image nun den Namen Image1 trägt. Dies ist aber nicht sehr gut, da man schnell nicht mehr weiß, welches Image das Image1 ist, sobald man mal mehrere Komponenten auf der Form hat. Wir benennen es daher um in imgPlot. Dazu klicken wir das Image an, und suchen rechts im Objektinspektor nach dem Eintrag "Name". Dort nun einfach den neuen Namen eingeben und mit Enter bestätigen. In dieses Image werden wir nun unsere Funktion x^2 zeichnen.
|
Als erstes brauchen wir dazu eine neue Prozedur:
 |
|
 |
|
|
...
procedure drawFunktion();
var
Form1: TForm1;
implementation
procedure drawFunktion();
begin
end;
|
|
|
 |
|
 |

Eine Prozedur hat im Gegensatz zur Funktion keinen Rückgabewert. Zum Zeichnen benötigen wir auch keine Übergabeparameter. Zum Zeichnen benutzen wir die Delphiinternen Grafikfunktionen, die man über Canvas ansprechen kann. Als erstes löschen wir das aktuelle Bild im Image und leeren es mit der Farbe weiß.
 |
|
 |
|
|
form1.imgPlot.Canvas.Brush.Color := clWhite; { Farbe setzen }
form1.imgPlot.Canvas.rectangle(-1,-1,form1.imgPlot.Width+1, form1.imgPlot.Height+1); { Image leeren }
|
|
|
 |
|
 |

Mit dem Brush.Color Befehl setzen wir die aktuelle Farbe zum Zeichnen. Dann zeichnen wir ein Rechteck, das leicht über die Ausmaße des Bildes hinausragt, um die schwarzen Ränder des Rechtecks zu verbergen. Dies geschieht mit dem Rectangle Befehl, dem wir die Koordinaten übergeben. Diese beziehen sich direkt auf das Image und sind in Pixeln angegeben, so dass die Koordinate (0|0) der erste Pixel oben links ist. imgPlot.width und imgPlot.height gibt die Größe des Images in Pixel an, und sind somit gleichzeitig unsere Parameter für die Übergabe an die Rechteckfunktion (+1 Pixel wegen des Rands des Rechtecks).
Nun ist unser Image geleert und bereit für das Koordinatensystem, welches sich natürlich in der Mitte des Images befinden sollte:
 |
|
 |
|
|
form1.imgPlot.canvas.Pen.Color := clBlack; { Farbe des Stifts setzen }
form1.imgPlot.canvas.MoveTo(0, form1.imgPlot.Height div 2); { Stift nach Links in der Mitte setzen }
form1.imgPlot.canvas.LineTo(form1.imgPlot.Width, form1.imgPlot.Height div 2); { Horizontale Linie des Koordinatensystems zeichnen }
form1.imgPlot.canvas.MoveTo(form1.imgPlot.Width div 2, 0); { Stift nach Oben in der Mitte setzen }
form1.imgPlot.canvas.LineTo(form1.imgPlot.Width div 2, form1.imgPlot.Height); { Vertikale Linie des Koordinatensystems zeichnen }
|
|
|
 |
|
 |

Wir müssen zum Zeichnen einer Linie immer erst den Startpunkt dieser Linie mit dem Befehl MoveTo angeben, und mit dem Befehl LineTo den Endpunkt angeben. Die Farbe der Linien setzen wir vorher mit dem Pen.Color Befehl. Damit wir das Koordinatensystem in der Mitte unseres Images kriegen, lesen wir die Breite und Höhe des Images aus und teilen diese dann jeweils durch 2, dann haben wir die mittigen Koordinaten. Dies geschieht mit dem Befehl div, der nur Ganzzahldivisionen durchführt und keine Gleitkommazahlen als Ergebnis ausgibt. Dies ist wichtig, da die Befehle MoveTo und LineTo nur Ganzzahlen (Integers) als Parameter annehmen.
Wenn wir nun einen Button auf unser Formular ziehen (zu finden unter "Standard", die Beschriftung für diesen ändern wir im Objektinspektor unter dem Eintrag "Caption") auf diesen doppelklicken und dort die Zeichenfunktion wie folgt eintragen:
 |
|
 |
|
|
procedure TForm1.Button1Click(Sender: TObject);
begin
drawFunktion();
end;
|
|
|
 |
|
 |

Dann können wir mit F9 das Programm starten. Klicken wir nun auf den Button, so sollte das Ganze etwa so aussehen:
Nun müssen wir nur noch die Funktion zeichnen lassen. Hierzu benötigen wir eine For-Schleife, die eine Zählvariable benötigt. Und diese müssen wie zuerst deklarieren:
 |
|
 |
|
|
procedure drawFunktion();
var
i: integer;
begin
...
|
|
|
 |
|
 |

Hier benötigen wir eine Ganzzahl, also einen Integer. Jetzt können wir unsere For-Schleife schon programmieren:
 |
|
 |
|
|
for i := 0 to form1.imgPlot.Width do
begin
end;
|
|
|
 |
|
 |

Da wir jeden Pixel des Bildes einzeln von links nach rechts ansteuern müssen, geht die Schleife von 0 (dem ersten Pixel) bis zum letzten Pixel (der gleich der Breite des Bildes ist). Vorher setzen wir unseren Stift aber aus dem sichtbaren Bereich des Bildes:
 |
|
 |
|
|
|
form1.imgPlot.Canvas.MoveTo(-1,-1);
|
|
|
 |
|
 |

Nun müssen wir noch die Funktion zeichnen. Dazu verbinden wir viele Punkte mit einer Linie. Wir müssen bedenken, dass im Bild der Nullpunkt des Koordinatensystems den Hälften der Ausmaße des Bildes entspricht, bei einem Bild von 600x600 Pixeln Größe liegt der Nullpunkt also z.B. bei 300x300. Deshalb sieht unser Code zum zeichnen der Funktion mit Hilfe der Schleife wie folgt aus:
 |
|
 |
|
|
for i := 0 to form1.imgPlot.Width do
begin
form1.imgPlot.Canvas.LineTo(i, round(f(i-form1.imgPlot.Width div 2))+form1.imgPlot.height div 2);
end;
|
|
|
 |
|
 |

Wenn wir das Ganze nun ausprobieren (F9), werden wir sofort bemerken das so aber etwas nicht stimmt:
Die Parabel steht auf dem Kopf! Woran liegt das? Das liegt daran, dass bei Windows die Y-Koordinaten von oben nach unten laufen, d.h. die Y-Koordiante 0 ist ganz oben, und nicht ganz unten, wie man dies aus der Mathematik gewohnt ist.
Deshalb müssen wir das Ganze noch etwas umrechnen:
 |
|
 |
|
|
var y: integer;
...
y := round(f(i-form1.imgPlot.Width div 2))+form1.imgPlot.height div 2; { Funktionswert ermitteln }
y := form1.imgPlot.Height - y; { Umdrehen }
form1.imgPlot.Canvas.LineTo(i, y); { Zeichnen }
|
|
|
 |
|
 |

Mit dieser Formel drehen wir den Bereich einfach um, und stellen quasi wieder Normalität her. Nun sieht auch alles korrekt aus:
Damit wäre unser Funktionsplotter fertig. Man sollte allerdings noch einige Erweiterungen vornehmen, z.B. um einen anderen Maßstab wählen zu können. Mit obigem Code entspricht 1 Pixel = 1 Längeneinheit, und das ist doch etwas wenig für schöne Funktionsgraphen.
Ich hoffe, das Tutorial war verständlich und hat euch auch ein bisschen Spaß gemacht!

|
|
|
 |
|
 |
|
|