Einführung in die objektbasierteProgrammierung mit Delphi
Klaus Becker
iMedia 2007
2 Orientierung
Der Einstieg in die Programmierung mit Delphi bereitet so mancherlei Schwierigkeiten. Auch einfachste Programme sind zunächst schwer zu durchschauen. Kompliziert ist insbesondere das Zusammenspiel zwischen GUI-Objekten und algorithmischen Elementen.Ziel der folgenden Ausführungen ist es, ein didaktisches Konzept vorzustellen, bei dem von Anfang an objektbasierte Erklärungsmodelle benutzt werden, um das Verständnis der recht komplexen Delphi-Programme zu erleichtern.Diese Vorgehensweise hat zweierlei Vorzüge: Zum wird mit Hilfe der Erklärungsmodelle die "Logik der Programme" vereinfachend dargestellt und somit der Quelltext strukturell geordnet. Zum anderen werden hierdurch bereits wichtige Konzepte der objektorientierten Modellierung und Programmierung für eine später zu erfolgende Vertiefung eingeführt. Letzteres erfordert, dass die Grundideen und die Terminologie der Objektorientierung von Beginn an korrekt und konsistent verwendet werden.
3 Teil 1
"Hallo Welt" -
objektbasierte Benutzungsoberflächen
4 "Hallo Welt"
5 GUI-Objekte
Eine Benutzungsoberfläche wird mit Hilfe von sog. GUI-Objekten aufgebaut. (GUI: Graphical User Interface)
GUI-Objekt
Die Eigenschaften eines Objekts kann man sich mit dem Objektinspektor anzeigen lassen.
GUI-Objekt
GUI-Objekt
GUI-Objekt GUI-Objekt
6 Objekt
Ein Objekt hat (in der Regel) einen Namen und wird einer Klasse zugeordnet. Die Klasse legt dabei den Typ des Objekts fest.
iBaer1: TImage
Im Objektinspektor werden der Name und die zugehörige Klasse des markierten Objekts angezeigt.
iBaer1: TImage
iBaer2: TImage
bTag: TButton
bNacht: TButton
pAnzeige: TPanel
GUI: TGUI
7
iBaer1: TImage
Aufbau und Zustand eines Objekts
iBaer1: TImage
Visible = False...
Klasse
Attribut Attributwert
Der Aufbau eines Objekts wird mit Hilfe von Attributen (Eigenschaften) festgelegt. Die Attributwerte legen den aktuellen Objektzustand fest.
Attribut
Attributwert
Name
Klasse
Name
8 Objektdiagramme
iBaer1: TImage
Visible = False...
Um die Struktur von Objekten zu beschreiben, benutzt man sog. Objektdiagramme.
Objektdiagramm
iBaer2: TImage
Visible = True...
bTag: TButton
Caption = 'Tag'...
bNacht: TButton
Caption = 'Nacht'...
pHinweis: TPanel
Caption = 'Wer ...'Color = clGreen...
GUI: TGUI
Caption = 'Knut ...'Color = clWhite...
9
Ein Blick in die Datei „uTagNacht.dfm“
object GUI: TGUI Left = 307 Top = 360 BorderIcons = [biSystemMenu] BorderStyle = bsSingle Caption = 'Knut tut gut' ClientHeight = 410 ClientWidth = 760 Color = clWhite ... PixelsPerInch = 96 TextHeight = 16 object iBaer1: TImage Left = 392 Top = 48 Width = 334 Height = 255 AutoSize = True Picture.Data = { 0A544A504547... ...} Visible = False end
object iBaer2: TImage Left = 32 Top = 48 ... Visible = False end object bTag: TButton ... Caption = 'Tag' TabOrder = 0 OnClick = bTagClick end object bNacht: TButton .. end object pHinweis: TPanel Left = 280 Top = 320 Width = 201 Height = 41 TabOrder = 2 endend
10
„verwaltet“
Objekthierarchie
FGUI:TFGUI
iBaer1:TImage
iBaer2:TImage
bTag:TButton
bNacht:TButton
pHinweis:TPanel
......
...
object GUI: TGUI Left = 307 Top = 360 BorderIcons = [biSystemMenu] BorderStyle = bsSingle Caption = 'Knut tut gut' ClientHeight = 410 ClientWidth = 760 Color = clWhite ... PixelsPerInch = 96 TextHeight = 16 object iBaer1: TImage Left = 392 Top = 48 Width = 334 Height = 255 AutoSize = True Picture.Data = { 0A544A504547... ...} Visible = False end
11 Veränderung von Objektzuständen
Attributwerte eines Objekts kann man mit Hilfe von Wertzuweisungen verändern.
pHinweis.Caption := 'Pst, ich schlafe!';pHinweis.Color := clRed;
pHinweis: TPanel
Caption = 'Wer ...'Color = clGreen...
pHinweis: TPanel
Caption = 'Pst ...'Color = clRed...
Objektzustand vorher
Objektzustand nachher
Wertzuweisungen
12 Ereignisbasierte Veränderung
Ein Ereignis ist eine Zustandsänderung in einem Objekt, die von Interesse ist und daher mit einer Prozedur zur Ereignisverarbeitung verknüpft werden kann. (K. Merkert)
Ereignis
Mausklick auf den Button mit der Aufschrift "Tag" löst das Ereignis "bTag.onClick" aus
Mausklick auf den Button mit der Aufschrift "Nacht" löst das Ereignis "bNacht.onClick" aus
Ereignisverarbeitung
procedure TGUI.bTagClick(Sender: TObject);begin GUI.Color := clWhite; iBaer1.Visible := false; iBaer2.Visible := true; pHinweis.Caption := 'Wer spielt mit mir?'; pHinweis.Color := clGreen;end;
procedure TGUI.bNachtClick(Sender: TObject);begin GUI.Color := clBlack; iBaer1.Visible := true; iBaer2.Visible := false; pHinweis.Caption := 'Pst, ich schlafe!'; pHinweis.Color := clRed;end;
13 Delphi-Quelltext (uTagNacht.pas)
unit uTagNacht;
interface
uses ...
type TGUI = class(TForm) bTag: TButton; bNacht: TButton; iBaer1: TImage; iBaer2: TImage; pHinweis: TPanel; procedure bTagClick(Sender: TObject); procedure bNachtClick(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end;
var GUI: TGUI;
Deklaration eines Formulars
mit GUI-Objekten
14 Delphi-Quelltext (uTagNacht.pas)
implementation
{$R *.DFM}
procedure TGUI.bTagClick(Sender: TObject);begin GUI.Color := clWhite; iBaer1.Visible := false; iBaer2.Visible := true; pHinweis.Caption := 'Wer spielt mit mir?'; pHinweis.Color := clGreen;end;
procedure TGUI.bNachtClick(Sender: TObject);begin GUI.Color := clBlack; iBaer1.Visible := true; iBaer2.Visible := false; pHinweis.Caption := 'Pst, ich schlafe!'; pHinweis.Color := clRed;end;
end.
Implementierung der
Ereignisverarbeitung
15 Teil 2
Bär auf Wanderschaft-
Datenhaltung mit lokalen Variablen
16 Bär auf Wanderschaft
17 Bär, komm her!procedure TGUI.bAktualisierenClick(Sender: TObject); var xposPfleger, yposPfleger: integer;begin // Eingabe: Übernahme der Anzeige xPosPfleger := StrToInt(eXpos.Text); yPosPfleger := StrToInt(eYpos.Text); // Ausgabe: Aktualisierung der Anzeige iPfleger.Left := xPosPfleger; iPfleger.Top := yPosPfleger;end;
procedure TGUI.bRechtsClick(Sender: TObject); var xPosBaer, yPosBaer: integer;begin // Eingabe: Übernahme der Anzeige xPosBaer := iBaer.Left; yPosBaer := iBaer.Top; // Verarbeitung: Veränderung der Daten xPosBaer := xPosBaer + 10; // Ausgabe: Aktualisierung der Anzeige iBaer.Left := xPosBaer; pXposWertBaer.Caption := IntToStr(xPosBaer); pYposWertBaer.Caption := IntToStr(yPosBaer);end;
lokale Variable
lokale Variable
18
yXposwertBaer: TPanel
Caption = '218'...
Caption = '208'...
pXposwertBaer: TPanel
Doppelte Buchführung
procedure TGUI.bRechtsClick(Sender: TObject); var xPosBaer, yPosBaer: integer;begin // Eingabe: Übernahme der Anzeige xPosBaer := iBaer.Left; yPosBaer := iBaer.Top; // Verarbeitung: Veränderung der Daten xPosBaer := xPosBaer + 10; // Ausgabe: Aktualisierung der Anzeige iBaer.Left := xPosBaer; pXposWertBaer.Caption := IntToStr(xPosBaer); pYposWertBaer.Caption := IntToStr(yPosBaer);end;
xPosBaer: 208
iBaer: TImage
Visible = TrueLeft = 208Top = 176...
yPosBaer: 176
xPosBaer: 218
yPosBaer: 176
yXposwertBaer: TPanel
Caption = '218'...
iBaer: TImage
Visible = TrueLeft = 218Top = 176...
pXposwertBaer: TPanel
Caption = '218'...
19
yXposwertBaer: TPanel
Caption = '218'...
Caption = '208'...
pXposwertBaer: TPanel
EVA-Prinzip
procedure TGUI.bRechtsClick(Sender: TObject); var xPosBaer, yPosBaer: integer;begin // Eingabe: Übernahme der Anzeige xPosBaer := iBaer.Left; yPosBaer := iBaer.Top; // Verarbeitung: Veränderung der Daten xPosBaer := xPosBaer + 10; // Ausgabe: Aktualisierung der Anzeige iBaer.Left := xPosBaer; pXposWertBaer.Caption := IntToStr(xPosBaer); pYposWertBaer.Caption := IntToStr(yPosBaer);end;
xPosBaer: 208
iBaer: TImage
Visible = TrueLeft = 208Top = 176...
yPosBaer: 176
xPosBaer: 218
yPosBaer: 176
yXposwertBaer: TPanel
Caption = '218'...
iBaer: TImage
Visible = TrueLeft = 218Top = 176...
pXposwertBaer: TPanel
Caption = '218'...
Viele Eingabe-Verarbeitung-Ausgabe-Systeme lassen sich mit Hilfe von lokalen Variablen realisieren.
20 Teil 3
Bär auf Wanderschaft-
Datenhaltung mit globalen Variablen
21 Bär, komm her!
Schwierigkeit:Die Ereignisverarbeitung zum Ereignis "bVorwaerts.Click" hängt von der momentanen Bewegungsrichtung des Bären ab. Diese Information könnte man aus den GUI-Objekten gewinnen, indem man nachschaut, welches Bild gerade sichtbar ist. Besser und übersichtlicher wird das Programm, wenn man ein internes Datenmodell mit "globalen Variablen" erstellt, auf die jede Ereignisverarbeitungsprozedur zugreifen und die sie verändern kann.
22 Bär, komm her!
...
type TGUI = class(TForm) bRechts: TButton; ... procedure bRechtsClick(Sender: TObject); ... procedure FormCreate(Sender: TObject); private { Private-Deklarationen } xpos, ypos: integer; oben, unten, links, rechts: boolean; procedure ausgangslage; procedure vorwaerts; procedure rueckwaerts; procedure rechtsdrehen; procedure linksdrehen; procedure baerZeigen; public { Public-Deklarationen } end;
Formular-Attribut als "globale Variable"
Formular-Methode als Hilfsprozedur
23 Trennung: GUI – Datenmodell
type TGUI = class(TForm) bRechts: TButton; ... procedure bVorwaertsClick(Sender: TObject); ... procedure FormCreate(Sender: TObject);
private { Private-Deklarationen } xpos, ypos: integer; oben, unten, links, rechts: boolean; procedure ausgangslage; procedure vorwaerts; procedure rueckwaerts; procedure rechtsdrehen; procedure linksdrehen; procedure baerZeigen; public { Public-Deklarationen } end;
procedure TGUI.vorwaerts;begin if oben = true then ypos := ypos - 10 else if unten = true then ypos := ypos + 10 else if links = true then xpos := xpos - 10 else if rechts = true then xpos := xpos + 10;end;
procedure TGUI.bVorwaertsClick(...);begin // Datenmodell aktualisieren vorwaerts; // Anzeige aktualisieren baerZeigen;end;
Datenmodell
24 Trennung: GUI – Datenmodell
type TGUI = class(TForm) bRechts: TButton; ... procedure bVorwaertsClick(Sender: TObject); ... private { Private-Deklarationen } xpos, ypos: integer; oben, unten, links, rechts: boolean; procedure ausgangslage; procedure vorwaerts; procedure rueckwaerts; procedure rechtsdrehen; procedure linksdrehen; procedure baerZeigen; public { Public-Deklarationen } end;
procedure TGUI.vorwaerts;begin if oben = true then ypos := ypos - 10 else if unten = true then ypos := ypos + 10 else if links = true then xpos := xpos - 10 else if rechts = true then xpos := xpos + 10;end;
Bei komplexeren Systemen ist es günstig, ein von der GUI getrenntes Datenmodell zu entwickeln.
Datenmodell
25 Teil 4
Zusammenfassung: Programmmuster
26
iBaer1: TImage
Visible = False...
iBaer2: TImage
Visible = True...
bTag: TButton
Caption = 'Tag'...
bNacht: TButton
Caption = 'Nacht'...
GUI: TGUI
Caption = 'Knut ...'Color = clWhite...
Muster 1
GUI-Objekte regeln Anzeige und Kontrolle.
procedure TGUI.bTagClick(Sender: TObject);begin GUI.Color := clWhite; iBaer1.Visible := false; iBaer2.Visible := true; pHinweis.Caption := 'Wer spielt mit mir?'; pHinweis.Color := clGreen;end;
pHinweis: TPanel
Caption = 'Wer ...'Color = clGreen...
27 Muster 2
EVA - Verarbeitung mit einem temporären Datenmodell
yXposwertBaer: TPanel
Caption = '218'...
Caption = '208'...
pXposwertBaer: TPanel
procedure TGUI.bRechtsClick(Sender: TObject); var xPosBaer, yPosBaer: integer;begin // Eingabe: Übernahme der Anzeige xPosBaer := iBaer.Left; yPosBaer := iBaer.Top; // Verarbeitung: Veränderung der Daten xPosBaer := xPosBaer + 10; // Ausgabe: Aktualisierung der Anzeige iBaer.Left := xPosBaer; pXposWertBaer.Caption := IntToStr(xPosBaer); pYposWertBaer.Caption := IntToStr(yPosBaer);end;
xPosBaer: 208
iBaer: TImage
Visible = TrueLeft = 208Top = 176...
yPosBaer: 176
xPosBaer: 218
yPosBaer: 176
yXposwertBaer: TPanel
Caption = '218'...
iBaer: TImage
Visible = TrueLeft = 218Top = 176...
pXposwertBaer: TPanel
Caption = '218'...
28 Muster 3
Internes Datenmodell mit "globalen Variablen"
type TGUI = class(TForm) bRechts: TButton; ... procedure bVorwaertsClick(Sender: TObject); ... private { Private-Deklarationen } xpos, ypos: integer; oben, unten, links, rechts: boolean; procedure ausgangslage; procedure vorwaerts; procedure rueckwaerts; procedure rechtsdrehen; procedure linksdrehen; procedure baerZeigen; public { Public-Deklarationen } end;
procedure TGUI.vorwaerts;begin if oben = true then ypos := ypos - 10 else if unten = true then ypos := ypos + 10 else if links = true then xpos := xpos - 10 else if rechts = true then xpos := xpos + 10;end;
Datenmodell
29 Muster 4
Eigenständiges Datenmodell mit neuen Objekten
TRoboter
xPosyPosrichtung...
erzeugeninitialisierenschrittlinksDrehenrechtsDrehenmarkeSetzenmarkeLoeschen...
OstenWesten
Süden
Norden
(4,3)