Vererbung Helmut Paulus Speyer, 7./8.11.2006 OOP: Vererbung Teil 1 Grafik mit Delphi Zeichenfläche TCanvas Canvas-Objekte dienen als Zeichenfläche für grafische Elemente. Sie kapseln eine Vielzahl von.

Download Report

Transcript Vererbung Helmut Paulus Speyer, 7./8.11.2006 OOP: Vererbung Teil 1 Grafik mit Delphi Zeichenfläche TCanvas Canvas-Objekte dienen als Zeichenfläche für grafische Elemente. Sie kapseln eine Vielzahl von.

Vererbung
Helmut Paulus
Speyer, 7./8.11.2006
OOP: Vererbung
Teil 1
Grafik mit Delphi
2
Zeichenfläche TCanvas
Canvas-Objekte dienen als Zeichenfläche für grafische Elemente.
Sie kapseln eine Vielzahl von Methoden zur Ausgabe von Grafik und Text in einem
OOP: Vererbung
rechteckigen Bereich.
TCanvas
Brush : TBrush
Pen : TPen
Font : TFont
...
moveto(x,y : integer);
TCanvas-Werkzeuge Pen, Brush und Font,
zuständig für bestimmte Teilaufgaben:
Pinsel
Stift
– Füllfarbe, Muster ...
– Linienfarbe, Stil ...
Schriftart – Farbe, Schrifttyp ...
lineto(x, y : integer);
ellipse(x1,y1,x2,y2 : integer)
rectangle(x1,y1,x2,y2 : integer)
polygon(p : array of Tpoint);
TextOut(x, y: Integer; const Text: string);
...
Der Koordinatenursprung (0,0) ist in der
linken oberen Ecke einer Komponenten,
die ein Canvas-Objekt zur Verfügung
stellen.
3
Wie erhält man ein TCanvas-Objekt?
TCanvas-Objekte werden von einigen Delphi-Komponenten als Property
zur Verfügung gestellt: z. B.:
OOP: Vererbung
Formular, Paintbox, Image, Bitmap




Der Koordinatenursprung ist die linke obere Ecke der jeweiligen
Komponente.
Die positive y-Achse zeigt nach unten.
Die Image-Komponente speichert die Graphik zusätzlich in einer
Hintergrundbitmap, so dass das Bild automatisch anzeigt wird, wenn das
Formularfenster, nachdem es verdeckt war, wieder in den Vordergrund
geholt wird.
Das Formular und Paintbox zeichnen das Bild nur einmalig. Damit es
nach dem Verdecken wieder erscheint, muss das Zeichnen der Graphik in
der OnPaint-Ereignismethode der jeweiligen Komponente erfolgen.
Dieses Ereignis wird vom Betriebssystem automatisch ausgelöst.
4
Objekthierarchie
OOP: Vererbung
Das Bild-Objekt Bild vom Typ TImage verwaltet über das Attribut Canvas ein Leinwand-Objekt der
Klasse TCanvas, das wiederum ein Zeichenstift-Objekt der Klasse TPen und ein Malpinsel-Objekt
der Klasse TBrush verwaltet.
Die entsprechenden Attribute Pen und Brush werden als Property zur Verfügung gestellt.
Beispiel: Blaues Rechteck
Bild.Canvas.Brush.Color := clbue;
Pinselfarbe blau
Bild.canvas.rectangle(10,10,100,20);
Rechteck mit der linken oberen Ecke am Punkt
(X1, Y1) und der rechten unteren Ecke am
Punkt (X2, Y2).
5
Aufgaben 1
1. Testen Sie das Beispielprogramm Grafiktest
OOP: Vererbung
2. Variieren Sie verschiedene Modi der Pinsel und Stifte
Testen Sie insbesondere den NotXOR-Füllmodus
3. Das Programm soll wie folgt verbessert werden:
• Nach Wahl Kreise, Rechtecke oder Polygone zeichnen
• Position und Größe der Figur interaktiv durch
Mausklicks bestimmen
- Kreis: Kreismittelpunkt und Radius
- Rechteck/Polygon: Eckpunkte
6
Zustandsbasierte Ablaufmodellierung
Eine Figur soll erzeugt werden:
OOP: Vererbung
Ablauf:
Zustände:
Figur auswählen
Punkte bestimmen
Z0
Bereit
Z1
Figur gewählt
für Punktaufnahme aktiviert
Figur zeichnen
Alter
Zustand
Z0
Z1
Für Auswahl der Figur
Auslösende
Aktion
Ausgelöste Aktion
Neuer
Zustand
AuswahlBoxClick
Punktefeld inizialisieren
Z1
Punkt speichern
Z1
[letzter Punkt] Figur zeichnen
Z0
FormMausDown
7
Zustandsbasierte Ablaufmodellierung
Zustandsautomat:
OOP: Vererbung
FormMouseDown
Punkt aufnehmen
[nicht letzter Punkt]
AuswahlBoxClick
Punktearray inizialieren
Z1:
Z0:
Figur
gewählt
Bereit
FormMouseDown
Figur zeichnen
[letzter Punkt]
Steuerung durch Ereignismethoden:
AuswahlBoxClick :
Figurtyp wählen
FormMouseDown :
Punkte speichern bis alle Punkte aufgenommen
8
Zustandsbasierte Modellierung
OOP: Vererbung
Zustandsbasierte Modellierung ist bei der Entwicklung von Systemen immer dann sinnvoll, wenn
das Verhalten eines Systems nicht nur von äußeren Eingaben oder Ereignissen abhängt,
sondern auch von inneren Zuständen, die das System in Abhängigkeit von den Eingaben bzw.
Ereignissen durchläuft.
Je nach Zustand kann ein Objekt anders auf dasselbe Ereignis reagieren.
Ein Zustandsdiagramm ist immer genau einer Klasse zugeordnet. Es beschreibt das dynamische
Verhalten der Objekte.
In einem Zustandsdiagramm wird festgehalten:
•
auf welche interne und externe Ereignisse ein Objekt reagiert,
•
wie ein Objekt reagiert und welche Aktivitäten ausgelöst werden, wenn es sich in einem
bestimmten Zustand befindet,
•
in welchen Folgezustand ein Objekt übergeht als Reaktion auf ein Ereignis.
9
Implementierung
Die gewählten Punkte werden gespeichert. Sind alle für die Figur notwendigen
Punkte bestimmt, wird sie gezeichnet.
type
OOP: Vererbung
TZustand = (z0,z1);
TGUI = class(TForm)
Typ der Zustandsvariablen mit
den Konstanten z0, z1
procedure AuswahlBoxClick(Sender: TObject);
procedure FormMouseDown(... X, Y: Integer);
private
{ Private-Deklarationen}
Zustand : TZustand;
NMax
Zustandsvariable
: integer;
Punkte : array of TPoint;
procedure zeichneFigur;
public
Anzahl der Eckpunkte
Dynamischer Array als Liste
der Eckpunkte
{ Public-Deklarationen}
end;
10
Implementierung
Figur auswählen im Zustand Z0
procedure TGUI.AuswahlBoxClick(...);
begin
OOP: Vererbung
if Zustand = z0 then
begin
case AusWahlBox.ItemIndex of
0,1 : NMax := 2;
2 : NMax := einlesen
Punkte speichern im Zustand Z1
Procedure TGUI.FormMouseDown(...,X,Y:Integer);
Var nr : integer;
begin
if Zustand = z1 then
begin // neuen Punkt dem Array hinzufügen
nr := length(Punkte);
//Punktzahl feststellen
setLength(Punkte,nr+1); //Arraylänge erhöhen
Punkte[nr] := Point(x,y); //Punkte zuweisen
end;
if nr = NMax-1 then
zustand := z1;
begin
zeichneFigur;
//Zustand z0 wiederherstellen
end;
end;
Punkte := nil;
// letzter Punkt?
//Punkte löschen
Auswahlbox.ItemIndex := -1;
Zustand := z0;
end;
end;
end;
11
OOP: Vererbung
Teil 2
Projekt Minigolf
12
OOP: Vererbung
Minigolfanlage
Ziel
Start
Ziel: Ball ins Loch schlagen
13
Modellierung der Animation
Idee:

Benutzer klickt aufs Spielfeld

OOP: Vererbung


Ball rollt schrittweise in Richtung der Verbindungslinie Maus – Ballmitte
Bei jedem Schritt wird seine Geschwindigkeit geringer
Spielende, wenn Zielpunkt erreicht
Lösung:
- Animationsschritte – timergesteuert (Ereignis: OnTimer)
- Vermeidung von Flimmern durch Doppelte Pufferung
Doppelte Pufferung – Double Buffering:
• Zusätzlich zum Bild auf dem Monitor wird noch ein Bild im Hintergrund gehalten.
Hierzu wird ein zweites Canvas-Objekt für das Bild im Speicher benötigt.
• Alle graphischen Ausgaben erfolgen zunächst im Speicherbild;
anschließend wird dieses auf dem Monitor ausgegeben.
14
OOA: Analyse
Fachkonzept
KStart
OOP: Vererbung
KZiel
Kreisobjekte
Ball
GUI-Schicht
Puffer
Spielfeld
Bitmap-Objekt
Image-Komponente
GUI
Formular
Timer
Animator
Steuerung
15
Beziehungen
GUI-Schicht
TForm
OOP: Vererbung
1
ist ein
1
TGUI
TImage
TTimer
Fachkonzept
TBitmap
TCanvas
2
TKreis
benutzt
1
benutzt
TBall
16
Modellierung der Klassen
Klassen:
OOP: Vererbung
TKreis
TBall
xPos, yPos //Mittelpunkt
FFarbe, FRad
Canvas //Ref. auf Zeichenfläche
create
paint
moveto // an neue Position
Objekte:
instance of
KStart
KZiel
ist ein
vx //Geschw. in x - Richtung
vy //Geschw. in y – Richtung
Zustand (liegt,rollt)
rolle //verschieben um vx,vy
setV
getAbsV
getZustand
setZustand
instance of
Ball
17
Implementierung der Klasse „TKreis“
TKreis
- xPos : integer
- yPos : integer
- FRad : integer
OOP: Vererbung
- FFarbe : TColor
- Canvas : TCanvas
+ Create(CanRef : TCanvas; x,y : integer)
+ paint
+ moveto(x,y : integer)
+ setAttribute(r : integer; f : TColor)
constructor TKreis.create(CanRef : TCanvas; x,y :
integer);
begin
xPos := x; yPos := y;
canvas := CanRef;// Anbindung an GUI
end;
procedure TKreis.paint;
var x1,y1,x2,y2 : integer;
begin
//umgebendes Rechteck
x1 := xPos-Frad; y1 := yPos-Frad;
x2 := xPos+Frad; y2 := yPos+Frad;
Zeichnen im NotXOR-Modus
ermöglicht Löschen der Figur
- nicht bei Doppelter Pufferung
with canvas do
begin
Pen.Mode := pmNotXor;
Pen.Color := clblack;
brush.color:= FFarbe;
ellipse(x1,y1,x2,y2);
end;
end;
18
Implementierung der Klasse „TKreis“
TKreis
- xPos : integer
- yPos : integer
- FRad : integer
OOP: Vererbung
- FFarbe : TColor
- Canvas : TCanvas
+ Create(CanRef : TCanvas; x,y : integer)
+ paint
+ moveto(x,y : integer)
+ setAttribute(r : integer; f : TColor)
procedure TKreis.moveto(x,y : integer);
begin
//paint; //zum Löschen
xPos := x;
yPos := y;
//paint;//erneut zeichnen
end;
procedure TKreis.setAttribute(r : integer;f : TColor);
begin
//paint; //zum Löschen
FRad := r;
FFarbe := f;
//paint; //zum Löschen
end;;
19
Implementierung der Klasse „TBall“
Vererbung:
OOP: Vererbung
• Die Klasse TKreis wird erweitert; dabei werden die Attribute und Operationen an die
abgeleitete Klasse weitergegeben.
TKreis
type
TZustand = (liegt, rollt);
TBall = class(TKreis) //abgeleitet von TKreis
ist ein
TBall
- vx : double
- vy : double;
- Zustand: TZustand
+ rolle;
+ setV(x, y : double);
+ getV : double;
+ getZustand : TZustand
+ getZustand
private
vx,vy : double;
Zustand : TZustand;
public
procedure rolle;
procedure setV(x, y : double);
function getAbsV : double;
function getVx : double;
function getVy : double;
function getZustand : TZustand;
procedure setZustand(z : TZustand);
end;
20
Implementierung der Klasse „TBall“
OOP: Vererbung
TKreis
ist ein
TBall
- vx : double
- vy : double;
- Zustand : TZustand
+ rolle;
+ setV(x, y : double);
+ getAbsV : double;
+ getZustand : TZustand
+ getZustand
procedure TBall.rolle;
begin
if Zustand = rollt then
begin
xPos := round(xPos + vx); yPos := round(yPos + vy);
setV(0.8*vx, 0.8*vy);
end;
end;
procedure TBall.setV(x, y : double);
begin
vx := x; vy := y;
if getAbsV > 0.5 then Zustand := rollt
else Zustand := liegt;
end;
function TBall.getAbsV : double;
begin
result := sqrt(vx*vx + vy*vy);
end;
21
Modellierung des Ballabschlags
Mausklick:
Der liegende Ball, wird er durch Mausklick (x,y)
abgeschlagen.
Ball abschlagen
V
OOP: Vererbung
vy
(x,y)
Animation-OnTimer:
vx
Der Abschlag erfolgt in Richtung des
Verbindungslinie Mauspunkt Ballmitte.
Geschwindigkeitsvektor:
vx = Ball.getx – x
vy = Ball.gety – y
Ball.rolle wird in der Ereignismethode der
Timerkomponente ständig ausgerufen.
Die Position wird neu berechnet und die
Geschwindigkeit verringert.
Eine Zustandsänderung (liegt) erfolgt, wenn
sie zu klein wird.
22
Ball: Zustandsdiagramm
Zustände
des Balls
liegt
OOP: Vererbung
rollt
animiere
rolle
animiere
Rolle
SpielFeldMouseDown
setV(vx,vy)
[|v| > 0,5]
v=0
|v| > 0,5
lieg
t
rollt
animiere
rolle
[|v|< 0,5] v [im Ziel] v [außerhalb]
Alter Zustand
liegt
rollt
Auslösende Aktion
Ausgelöste Aktion
SpielfeldMouseDown
Ball.setV(vx,vy)
rollt
BtnStartPosClick
Startposition einnehmen
liegt
Animiere
Ball.rolle
liegt
Animiere
Ball.rolle -> Bewegung
[|v| > 0,5]/[|v| < 0,5]
[Im Ziel]
[außerhalb]
Neuer Zustand
rollt/liegt
liegt
liegt
23
Modellierung des Spielablaufs
Spielphasen:
OOP: Vererbung
Anforderungen:
• Bei Spielbeginn Ball auf Startposition
Sp0
Bahn vorbereitet
• Kein Abschlag, wenn Ball im Loch oder außerhalb
des Spielfeldes
Sp1
Bahn wird bespielt
Sp2
Bahn beendet
• Bahn/Spiel zu Ende, wenn Ball im Loch
Sp3
Spiel beendet
SpU
unterbrochen
Alter
Zustand
Neuer
Zustand
Auslösende Aktion
Ausgelöste Aktionen
Sp1
BtnStartPosClick
Ball auf Startpunkt
Ball.setZustand(liegt)
Punkte auf 0
Ball auf Startpunkt
Strafpunkte
Sp1
SpielFeldMouseDown
Ball.setV, Punkte erhöhen
Sp1
Sp1
Animiere
Ball.rolle
[Eingelocht]
[außerhalb] [im Locht&[alle Bahnen]
Sp2
BtnNextBahn
Bahn aufbauen/Ball auf Bahn
Sp0
SpU
Sp1
Sp1
Sp0 (Sp2)
SpU (Sp3)
Sp0
24
Zustandsdiagramm
Spielablauf:
animiere
SpielFeldMouseDown
Ball.setV(vx,vy)
animiere
SpU
OOP: Vererbung
[außerhalb]
BtnStartPosClick
Ball an Start
Sp
0
Sp1
animiere
[eingelocht]
BtnNextBahn
Bahn aufbauen
Ball auf Bahn
BtnStartPosClick
Ball an Start
Strafpunkte
Sp2
animiere
[eingelocht
& alle Bahnen]
Sp3
In der einfachen Version (nur eine Spielbahn) entfallen die Zustände Sp2
und Sp3
25
Doppelte Pufferung
Monitorbild
OOP: Vererbung
Spielfeld : TImage
Spielfeld.canvas
Graphikausgabe in zwei Schritten:
1. Zeichnen im Hintergrund:
Puffer.canvas.ellipse(...);
2. Hintergrundbild ins Spielfeld kopieren:
Puffer.canvas
Spielfeld.canvas.draw(0,0,Puffer)
Bei der Animation von bewegten Objekten wird das Hintergrundbild vor jeder Änderung gelöscht, indem die Zeichenfläche mit der Hintergrundfarbe gefüllt wird:
Hintergrundbild
Puffer.Canvas.fillRect(...);
Puffer : TBitmap
26
Implementierung: Doppelte Pufferung
Idee: Alle Graphikausgaben erfolgen zunächst in ein Hintergrundbild, das dann als
Ganzes in eine sichtbare Zeichenfläche kopiert wird.
OOP: Vererbung
Einrichten des Puffers (OnCreate)
var
Puffer : TBitmap; //enthält das Hintergrundbild
procedure TFenster.FormCreate( ... );
begin
Bitmap-Objekt erzeugen
Puffer := TBitmap.Create;
Puffer.Width := SpielFeld.Width;
Puffer.Height := SpielFeld.Height;
...
StartPkt := TKreis.create(Puffer.canvas,StartX,StartY);
ZielPkt := TKreis.create(Puffer.canvas,400,100);
Größe des Puffers anpassen
Zeichenfläche des Puffers an
Graphik-Objekte übergeben
Ball := TBall.create(Puffer.canvas,50,50);
...
end;
27
Implementierung: Doppelte Pufferung
Hintergrundbild aufbauen und auf dem Monitor ausgeben
OOP: Vererbung
procedure TFenster.zeichneSpielFeld;
begin
//altes Bild löschen (mit Hintergrundfarbe füllen)
Puffer.Canvas.Brush.Color := SpielFeld.Canvas.Brush.Color;
Puffer.Canvas.FillRect(rect(0,0,Puffer.width,Puffer.height));
//Graphische Objekte neu zeichnen im Hintergrund
StartPkt.paint;
ZielPkt.paint;
Ball.paint;
//Hintergrundbild in Zeichenfläche des Spielfeldes kopieren
SpielFeld.Canvas.Draw(0,0,Puffer);
end;
Die Formular-Methode zeichneSpielfeld enthält alle Graphikbefehle. Sie wird nach
jeder Aktualisierung eines Graphikobjekts aufgerufen.
Benutzt man das Canvas-Objekt des Formulars als Monitorzeichenfläche, so
kann das Zeichnen durch das OnPaint-Ereignis des Formulars ausgelöst werden.
28
Aufgaben 2
OOP: Vererbung
1. Programm Minigolf testen.
2. Programm so erweitern, dass Spielstände angezeigt werden.
- pro Schlag ein Punkt
- 2 Strafpunkte, wenn Ball von außerhalb zurückgeholt wird
3. Reflexion an den Rändern des Spielfeldes
4. Entwicklung eines magischen Feldes (Objekt), das den Ball
vom Spielfeld schleudert, sobald er es betritt.
29
OOP: Vererbung
Teil 3
Modellierung grafischer Objekte
30
OOP: Vererbung
Anwendungsbeispiel
Aktivitäten: verschieben, drehen, skalieren, editieren
31
Anforderungen
OOP: Vererbung
• Erzeugung und Verwaltung von grafischen Objekten unterschiedlicher Form
• Fähigkeiten der Objekte
- frei verschiebbar (Maus)
- skalierbar
- drehbar
32
OOP: Vererbung
Erste OOA-Analyse
TKreis
TQuadrat
TText
TDreieck
...
TRechteck
TParallel
Problem: Vielfalt der Objekte
Optimierung: Entwicklung einer Klassenhierarchie
33
Klassenhierarchie
OOP: Vererbung
TGrafikElement
TKreis
TRegNEck
TPolygon
TLinie
TText
TParallel
TRechteck
34
Klassenhierarchie
OOP: Vererbung
Optimierung der Klassen durch Entwicklung einer Vererbungsstruktur
Ziele:
• Der gemeinsame Kern aller Elemente wird in einer Basisklasse
modelliert.
• Spezialisierte Klassen werden von der Basisklasse abgeleitet;
sie fügen spezielle Attribute und Operationen hinzu oder
definieren bestimmte Dinge neu.
35
Klassenhierarchie
Vorteile:
OOP: Vererbung
Durch Vererbung werden alle gemeinsamen Eigenschaften und
Operationen an abgeleitete Klassen weitergegeben:
 Grundlegende Attribute und Operationen werden nur einmal
entwickelt
 Möglichkeit zur Anpassung und Erweiterung unter geringem
Aufwand (Wiederverwendbarkeit)
 Einheitlicher Zugriff auf verschiedene Objekttypen wird möglich
(Polymorphismus)
36
OOP: Vererbung
Einfaches Beispiel
Kreise und Rechtecke
37
Kreise und Rechtecke
OOP: Vererbung
TKreis
TRechteck
xPos, yPos //Mittelpunkte
xPos, yPos //Mittelpunkte
FFarbe // Füllfarbe
FFarbe // Füllfarbe
Canvas //Zeichenflächenref.
Canvas //Zeichenflächenref.
Markiert // Markierungsflag
Markiert // Markierungsflag
FRad //Radius
FBreite, FLaenge
Create
paint
Moveto // verschieben
skalieren //vergrößern
Create
paint
Moveto // verschieben
skalieren //vergrößern
Beide Klassen besitzen gleiche Attribute und Methoden gleicher
Funktionalität.
Das Gemeinsame muss nicht mehrmals implementiert werden!
38
Erste Modellierung der Klassen
Die Basisklasse enthält den gemeinsamen Kern aller grafischen Objektklassen.
Basisklasse
Generalisierung
TGrafikElement
xPos, yPos //Mittelpunkte
FFarbe // Füllfarbe
OOP: Vererbung
Canvas //Zeichenflächenref.
Markiert // Markierungsflag
Create //Basiskonstruktor
Moveto // verschieben
ist ein
abgeleitete
Klassen
(Unterklasse)
TKreis
ist ein
TRechteck
FRad //Radius
FBreite, FLaenge
paint
skalieren //vergrößern
paint
skalieren //vergrößern
Spezialisierung
39
Implementierung der Basisklasse
TGrafikElement
OOP: Vererbung
- xPos : integer
- yPos : integer
TGrafikElement = class
private
xPos : integer;
- FFarbe : TColor
yPos : integer;
- Fmarkiert : boolean
FFarbe : TColor;
- Canvas : TCanvas
Fmarkiert : boolean;
+ Create(CanRef : TCanvas; x, y : integer)
+ moveto(x, y : integer);
+ getX : integer
+ getY : integer
Canvas : TCanvas;
public
constructor create(CanRef : TCanvas; x,y : integer);
procedure moveto(x,y : integer);
function getX : integer;
function getY : integer;
getFarbe Farbe : Tcolor;
procedure setFarbe(wert : TColor);
end;
40
Implementierung der Basisklasse
TGrafikElement
OOP: Vererbung
- xPos : integer
- yPos : integer
constructor TGrafikElement.create(CanRef : TCanvas;
x,y : integer);
begin
- FFarbe : TColor
xPos := x;
- Fmarkiert : boolean
yPos := y;
- Canvas : TCanvas
canvas := CanRef;
+ Create(CanRef : TCanvas; x, y : integer)
+ getX : integer
+ getY : integer
End;
Die Objekte erhalten eine Referenz auf das
Zeichenflächenobjekt des GUI-Objekts
procedure TGrafikElement.moveto(x,y : integer);
begin
xPos := x;
yPos := y;
end;
41
„Ist ein“ - Beziehung
TGrafikElement
...
OOP: Vererbung
...
Die Unterklassen beschreiben nur die Abweichungen von
von der Oberklasse. Alles andere kann wiederverwendet
werden, weil es in der Oberklasse vorliegt.
Die Methoden und Attribute der Oberklasse bilden eine
Teilmenge der Methoden und Attribute der Unterklasse.
ist ein
TKreis
- FRad : integer
Ein Objekt der Unterklasse hat somit ein Objekt
der Oberklasse als Teilobjekt.
Umgekehrt sind alle Objekte der Unterklasse eine
Teilmenge der Objekte der Oberklasse.
- setRadius(wert : integer)
+ paint
+ setAttribute( r : integer, f : TColor)
Jeder Kreis ist ein GrafikElement
Konsequenz: Zuweisungskompatibilität
Einer Variablen vom Typ der Oberklasse kann eine Referenz auf ein
Unterklassenobjekt zugewiesen werden.
42
Implementierung der Klasse „TKreis“
TGrafikElement
private
...
Frad : integer;
...
OOP: Vererbung
TKreis = class(TGrafikElement)
public
constructor create(CanRef : TCanvas; x,y : integer);
procedure paint;
ist ein
procedure setAttribute(r : integer;f : TColor);
function getRadius : integer;
TKreis
-FRad : integer
procedure setRadius(wert : integer);
end;
-...
+ paint
+ setAttribute( r : integer, f : TColor)
+ getRadius : ineger
+ setRadius(wert : integer)
43
Implementierung der Klasse „TKreis“
TGrafikElement
begin
...
inherited create(CanRef,x,y); //Konstruktor der Oberklasse
...
OOP: Vererbung
constructor TKreis.create(CanRef : TCanvas; x,y : integer);
FRad := 10;
end;
ist ein
TKreis
- FRad : integer
- setRadius(wert : integer)
+ paint
+ setAttribute( r : integer, f : TColor)
Durch Aufruf des geerbten Konstruktors
werden die Attribute des Basisobjekts
initialisiert.
Das abgeleitete Objekt enthält quasi ein
Basisobjekt als Teilobjekt.
44
Implementierung der Klasse „TKreis“
TGrafikElement
...
OOP: Vererbung
...
ist ein
TKreis
- FRad : integer
+ paint
+ setRadius(wert : integer)
+ setAttribute( r : integer, f : TColor)
procedure TKreis.paint;
var x1,y1,x2,y2 : integer;
begin
//umgebendes Rechteck
x1 := xPos-Frad;
y1 := yPos-Frad;
x2 := xPos+Frad;
y2 := yPos+Frad;
with canvas do
begin
brush.color:= FFarbe;
ellipse(x1,y1,x2,y2);
end;
end;
procedure TKreis.setAttribute(r : integer;f : TColor);
begin
FRad := r;
FFarbe := f;
end;
45
Vererbung und Zugriffrechte
Elemente einer Klasse können in der Klassendeklaration vor dem Zugriff von
außen geschützt werden (Geheimnisprinzip).
Schutzebenen:
OOP: Vererbung



public
keine Zugriffsbeschränkung nach außen
private
Zugriff nur innerhalb einer Klasse
protected
Zugriff auch in abgeleiteten Klassen möglich
Die Schutzebenen private und protected gelten allerdings nur für den Zugriff aus
einer anderen Unit heraus.
Vererbung der Zugriffsrechte
Die Zugriffsrechte einer Klasse werden an abgeleitete Klassen vererbt.
Schutzrechte können in einer abgeleiteten Klasse abgeschwächt, aber nicht
verschärft werden.
46
Zuweisungskompatibilität
Konsequenz der „ist ein“ – Beziehung:
Einer Objektvariablen einer Oberklasse können Objekte aller Unterklassen
OOP: Vererbung
zugewiesen werden. Die Umkehrung gilt nicht.
Beispiel:
Var
Kreis : TKreis;
Rechteck : TRechteck
Grafik : TGrafikElement;
...
Kreis := TKreis.create(...);
Rechteck := TRechteck.create(..);
...
Möglich:
Grafik := Kreis;
Grafik.setFarbe(clred);
Grafik := Rechteck;
Nicht möglich:
Grafik.setAttribute(...)
Grafik.setBreite(100);
Beachte:
Grafik ist eine Referenz auf den Teil des Kreisobjekts, der von TGrafikElement
geerbt wird.
47
Operatoren „is“ und „as“
is - Operator : Typprüfung (Laufzeit)
Beispiel:
Var
OOP: Vererbung
Figur : TGrafikElement;
Kreis : TKreis;
...
if Figur is TKreis then
TKreis(Figur).paint;
Typumwandlung (type cast)
- liefert true , wenn das Objekt Figur eine Instanz der angegebenen Klasse
oder eines ihrer abgeleiteten Klassen ist
as - Operator : Typumwandlung (Laufzeit)
Beispiel:
Kreis := Figur as TKreis;
(Figur as TKreis).paint;
- liefert eine Referenz auf ein Objekt vom des Objektes Kreis
48
Statische Methoden
Die bisher definierten Methoden sind statisch:
OOP: Vererbung
Beim Compilieren ist der Objekttyp bekannt, sodass die Sprungadresse der Methode
festgelegt werden kann (statische Bindung)
Kreis.paint;
//paint - Methode des Kreisobjekts
Rechteck.paint; //paint - Methode des Rechteckobjekts
Der Typ der Referenz auf das Objekt bestimmt, welche Methode aufgerufen wird.
Problem:
Dieses Verhalten ist, wenn Vererbung ins Spiel kommt, oft unerwünscht.
Z. B. wenn sich erst zur Laufzeit entscheidet, welcher Objekttyp angesprochen wird.
49
Statische Methoden
Beispiel:
OOP: Vererbung
Zur Laufzeit werden verschiedene Grafikobjekte erzeugt und ihre Referenzen in
einem Array als Container verwaltet:
Var Figur : array[1..10] of GrafikElement;
Ziel: Einheitlicher Zugriff auf bestimmte Methoden, wie z. B.:
for i := 1 to 10 do
Figur[i].paint;
Da zur Compilierzeit noch nicht feststeht, welche Objekttypen ins Array
aufgenommen werden, entscheidet sich erst zur Laufzeit, welche
Objektmethode aufgerufen werden soll.
Dazu müsste der aktuelle Objekttyp für die Auswahl der Methode maßgebend
sein.
50
Virtuelle Methoden
Lösung des Problems durch virtuelle Methoden:
TGrafikElement = class
private
...
OOP: Vererbung
public
...
procedure paint;virtual;
end;
Die Basisklasse erhält ebenfalls eine Methode paint;
diese wird aber als virtual deklariert.
TKreis = class(TGrafikElement)
private
...
public
procedure paint;override;
...
paint wird in der Unterklasse überschrieben,
d.h. als override deklariert und neu implementiert.
end;
51
Verhalten virtueller Methoden
Die Referenz auf das Objekt enthält Information über den Typ des übergebenen
Objekts. Dadurch kann die zum Objekt passende Methode aufgerufen werden.
OOP: Vererbung
Var Figur : Array[1..10] of GrafikElement;
Figur[5].paint; //Aufruf der virtuellen Methode
Der Typ des aktuellen Objekts bestimmt zur Laufzeit die Methode.
Dynamische Bindung / late binding
Interne Realisierung:
Objekte besitzen einen Zeiger auf eine virtuelle Methodentabelle (VMT), die
Zeiger auf alle virtuellen Methoden der Klasse enthält.
Bei virtuellen Methoden erfolgt der Aufruf über diese Methodenzeiger-Tabelle.
52
Polymorphismus
Das Konzept der dynamischen Bindung heißt in der OOP Polymorphismus
(Vielgestaltigkeit).
OOP: Vererbung
Merkmale
 Bei polymorphen Objektenvariablen entscheidet sich erst zur Laufzeit, welcher
Klasse das Objekt angehört.
 Eine in einer Basisklasse als virtual deklarierte Methode definiert eine Schnittstelle
für alle abgeleiteten Klassen, auch wenn diese noch nicht festgelegt sind.
 Ein Programm, das virtuelle Methoden einer Basisklasse enthält kann sehr leicht um
abgeleitete Klassen erweitert werden, weil sichergestellt ist, dass stets die richtige
Methode aufgerufen wird.
Empfehlung
 Statische Methoden einer Basisklasse sollten nicht überschrieben werden.
 Wenn Überschreiben notwendig erscheint, sollte die Methode als virtual deklariert
werden.
53
Abstrakte Klassen
OOP: Vererbung
Die Basisklasse TGrafikElement muss die Methode paint enthalten, kann sie aber nicht
sinnvoll implementieren, weil diese Klasse zu allgemein ist.
Die Implementation kann also entfallen.
Dazu wird die virtuelle Methode der Basisklasse zusätzlich als abstract deklariert.
TGrafikElement = class
...
procedure paint;virtual;abstract;
...
end;
TGrafikElement als abstrakte Klasse
Merkmale:
 Abstrakte Klassen enthalten mindestens eine abstrakte virtuelle Methode, die
überschrieben werden muss.
 Von abstrakten Klassen können keine Instanzen gebildet werden.
 Abstrakte Klasse bilden eine gemeinsame Schnittstelle für alle Unterklassen.
54
OOP: Vererbung
Aufgaben 3
1.
Programm SimpelObjekt testen
2.
Ergänzung der Objekte um die Funktion „Flaeche“. Der Zugriff soll
polymorph erfolgen.
3.
Ableitung der Klasse TQuadrat von TRechteck und testen
4.
Polymorphismus anwenden:
Eine Bank verfügt über Girokonten und Sparkonten. Während Girokonten
überzogen werden können, dürfen Sparkonten keinen negativen Stand
aufweisen.
Der Auszahlungsaufruf soll für beide Kontotypen einheitlich sein
Entwickeln Sie eine geeignete Vererbungsstruktur (UML)
55
OOP: Vererbung
Teil 4
Objektverwaltung
56
Objektverwaltung
Aufgaben eines Objektverwalters



OOP: Vererbung

Referenzen unterschiedlicher Objekttypen speichern
Einfügen, entfernen von Referenzen
Zugriff auf einzelne Objekte oder alle ermöglichen
Zeichnen aller Objekte
Realisierung

Speicher (lineare Liste)




Array of TGrafikElement (dyn. Array)
Lineare Liste entwickeln
Vorhandene Container – Objekte nutzen oder anpassen (TList)
Methoden





Einfügen
Entfernen
Verschieben (innerhalb der Liste)
Objekt an bestimmter Position ermitteln
Zeichnen
57
Klassendiagramm
TVerwalter
TGUI
SelObjekt : TGrafikElement
Verwalter : TVerwalter
1
- Elemente : TList
+ Count : integer
OOP: Vererbung
+ add(Objekt : TGrafikElement)
FormCreate(...)
FormPaint(...)
FormMouseDown(...)
FormMouseMove(...)
+ getElement( index : integer);
+ getElementAt(x, y : integer) : TGrafikElement
+ entferne(Objekt : TGrafikElement)
+ paintAll
*
Der Verwalter hat ein TlistObjekt zur Aufnahme der Elemente
getElementAt(x,y)
- Element an der Position (x, y) der
Zeichenfläche
TGrafikElement
#F Markiert : boolean;
#Farbe : Tcolor
xPos : integer
yPos : integer
# zeichneMarke
+ paint
58
Problem: Objekt auswählen
Objekt an der Stelle (x, y)
function TVerwalter.getElementAt(x, y : integer):
TGrafikElement;
OOP: Vererbung
var i, dx, dy : integer;
Obj : TGrafikElement;
begin
result := nil;
for i := 0 to Elemente.Count-1 do
begin
Algorithmus:
 Liste der Objekte durchlaufen
und Abstand zum übergebenen
Punkt (x,y) berechnen
 Abstandsbedingung prüfen
 Referenz des letzten gefundenen
Objekts zurückgeben
 evtl. gefundenes Objekt ans Ende
Obj := TGrafikElement(Elemente[i]);
der Liste setzen, damit es als
dx := x-Obj.getx;
letztes gezeichnet wird und damit alle
dy := y-Obj.gety;
anderen überdeckt.
if dx*dx + dy*dy < 100 then
result := Obj;
end;
end;
59
Zusammenfassung
OOD- Klassendiagramm
OOP: Vererbung
1. Optimierung der Klassenstruktur

Verwaltungs - Klassen hinzufügen

Komplexe Klassen zerlegen
2. Optimierung der Attribute
3. Optimierung der Operationen
4. Optimierung der Vererbungsstruktur

Abstrakte Operationen für einheitliche Schnittstellen

Abstrakte Oberklassen bilden

Polymorphismus maximieren

Vererbungshierarchie komprimieren

Existierende Klassen wiederverwenden
60
Aufgaben 4
OOP: Vererbung
Erweiterung des Programms SimpelObjekt
•
Objektverwalter einbinden (Klasse TVerwalter (Unit: uVerwalter)
•
Objekte mit der Maus über den Bildschirm ziehen
•
Farbe oder Größe einer mit Maus gewählten Figur ändern
•
Mit Hilfe der Maus beliebig viele Objekte interaktiv erzeugen
61
OOP: Vererbung
Teil 5
Realisierung des Tangram-Projekts
62
Anforderungen
OOP: Vererbung
 Erzeugung geometrischer Objekte
Beschränkung auf Polygone und Kreise genügt
 Fähigkeiten der Objekte
- verschiebbar (Maus)
- skalierbar
- Drehbar
 Verwaltung der Objekte mit Hilfe eines Verwalter-Objekts
63
Darstellung eines Polygons
Canvas – Methode: procedure Polygon(Points array of TPoint)
OOP: Vererbung
Der Parameter ist ein beliebig langes Array (dyn. Array) von Punkten (TPoint).
Die Punkte enthalten die Bildschirmkoordinaten der Eckepunkte der Figur.
Problem:
- Der Referenzpunkt (xPos,yPos) soll Mittelpunkt der Figur sein.
(erleichtert Drehen und Verschieben)
- Die Figur soll um den Referenzpunkt gedreht werden.
Lösung:
Die aktuellen Bildschirmkoordinaten werden stets aus einem Basispolygon
berechnet, dessen Mittelpunkt der Ursprung (0,0) ist.
Alle Manipulationen (Vergrößerung, Verschiebung, Drehung) werden nur am
Basispolygon durchgeführt und dieses anschließend zum Referenzpunkt
verschoben.
64
Optimierte Klassen
Reduzierung auf die Klassen TKreis und TPolygon
TGrafikElement
TGrafikVerwalter
# Markiert : boolean;
OOP: Vererbung
...
# zeichneMarke
+ paint
+ moveto(x,y :integer)
+ skaliere(k : double)
abstrakt
TKreis
+ paint;
+ skaliere(k : double)
*
1
+ add(Element : TObjekt)
+ getElement( index : integer);
+ getElementAt(x, y : integer)
: TGrafikElement
TPolygon
# SPunkte : Array of TPoint
# BPunkte : array of TPunkt
+ initPolygon(... );
+ paint
+ skaliere(k : double)
+ rotate(alpha : double)
65
Deklaration der Klasse „TPolygon“
TPolygon = class(TGrafikElement)
protected
Fn
: integer;
//Anzahl der Ecken
OOP: Vererbung
SPunkte : array of TPoint; //aktuelle Bildschirmkoordinaten der Eckpunkte
BPunkte : array of TPunkt; //Basispunkte (logische Koordinaten)
procedure setSchwerpunkt(absolut : boolean); //Schwerpunkt als Mittelpunkt
procedure zumRefPunkt; //Bildschirmkoordinaten der EckPunkte aktualisieren
public
procedure initPolygon(p : array of TPunkt; absolut : boolean);virtual;
procedure paint;override;
procedure moveto(x,y : integer);override;
procedure skaliere(k : double);override;
procedure rotate(alpha : double);virtual;
function n : integer;
end;
66
Klasse TPolygon
TPolygon
OOP: Vererbung
# SPunkte : array of TPoint
# BPunkte : array of TPunkt
+ initPolygon(... );
+ paint
+ skaliere(k : double)
+ rotate(alpha : double)
Type
TPoint = record x,y : integer end;
TPunkt = record x,y : double end;
Umwandlungsfunktionen
function Point(x, y : Integer): TPoint;
function Punkt(x, y : double) : TPunkt;
Initialisierung:
initPolygon(p : array of TPunkt; absolut : boolean)
- übernimmt ein Punkte-Array und bildet daraus das Basispolygon.
- absolut : gibt an, ob die Koordinaten absolute Bildschirmkoordinaten sind
67
Initialisieren des Basispolygons
Schritte:
1. Initialisieren der dynamischen Arrays SPunkte und BPunkte
2. Speichern der übergebenen Punkte in Bpunkte
OOP: Vererbung
3. Polygon so verschieben dass der Ursprung zum Schwerpunkt wird
4. Zum Referenzpunkt schieben, d. h. SPunkte bestimmen
procedure TPolygon.setPolygon(p : array of TPunkt; absolut : boolean);
//Basispolygon initialisieren
var i : integer;
begin
Fn := Length(p);
//Anzahl der Punkte ermitteln und speichern
setLength(BPunkte,Fn); //dyn. Array mit Fn Werten initialisieren
setLength(SPunkte,Fn);
for i := 0 to Fn-1 do
// Punkte in BPunkte speichern
BPunkte[i] := p[i];
setSchwerpunkt(absolut);
zumRefPunkt; // SPunkte aktualisieren
end;
68
Schwerpunkt setzen
procedure TPolygon.setSchwerpunkt(absolut : boolean);
var
i : integer;
xs,ys : double;
OOP: Vererbung
begin
//Schwerpunkt des Basispolygons
xs := 0; ys := 0;
for i := 0 to Fn-1 do
begin
xs := xs + BPunkte[i].x; ys := ys + BPunkte[i].y;
end;
xs := xs/n; ys := ys/n;
//Basispolygon so verschieben, dass der Schwerpunkt der Ursprung (0;0) wird
for i := 0 to n-1 do
begin
BPunkte[i].x := BPunkte[i].x - xs; BPunkte[i].y := BPunkte[i].y - ys;
end;
if absolut then
begin //Schwerpunkt wird Referenzpunkt
xPos := round(xs); yPos := round(ys);
end;
end;
69
Verschieben des Basispolygons
Verschiebung des Basispolygons zum Referenzpunkt
OOP: Vererbung
P3
P2
M
P0
BP3
BP2
Für alle Punkte:
P1
P.x := xPos + BP.x;
P.y := yPos + BP.y;
BP : Basispunkte
O
BP0
Procedure TPolygon.ZumRefPkt
P : Bildschirmpunkte
BP1
70
Skalieren des Basispolygons
Zentrische Streckung des Basispolygons
Procedure skaliere(k : double)
OOP: Vererbung
BP3’
BP2’
BP3
BP2
Für alle Punkte:
BP.x := k*BP.x;
BP.y := k*BP.y;
BP0
BP0’
BP : Basispunkte
BP1
k : Streckfaktor
BP1’
71
Drehen des Basispolygons
Drehung eines Punktes um den Ursprung mit Drehwinkel a durch Multiplikation mit der
Drehmatrix
OOP: Vererbung
 x'   cosα  sinα   x 
 
 
y'
sinα

cosα
  
  y
x'  cosa  x  sin a  x
y '  sin a  y  cosa  y
procedure TPolygon.rotate(alpha : double);
Var
i : integer; x,y : double;
begin
alpha := alpha*Pi180;
for i := 0 to Fn-1 do
begin
x := cos(alpha)*BPunkte[i].x-sin(alpha)*BPunkte[i].y;
y := sin(alpha)*BPunkte[i].x+cos(alpha)*BPunkte[i].y;
BPunkte[i].x := x;
BPunkte[i].y := y;
end;
zumRefPunkt;
end;
72
Zeichnen des Polygons
procedure TPolygon.paint;
begin
with canvas do
OOP: Vererbung
begin
Pen.Style := pssolid;
// Pen.Mode
:= pmNotXor;
Pen.Color := clblack;
brush.color := FFarbe;
//Polygon zeichnen
polygon(SPunkte);
if Fmarkiert then
zeichneMarke; //Markierungsrechteck
end;
end;
73
Anbindung an die GUI-Klasse
TForm
Ereignisgesteuerter Ablauf:
OOP: Vererbung
ist ein
TGUI
Figur : array[1..7] of TGrafikElement
- Verwalter
SelObjekt : TPolygon
- ausgewähltes Objekt
FormCreate(...)
- Objekte erzeugen, Referenzen speichern
FormPaint(...)
- Objekte zeichnen
FormMouseDown(...)
- Objekt auswählen, drehen
FormMouseMove(...)
- Objekt verschieben
74
Aufgaben 5
OOP: Vererbung
1. In der Unit uGrafEleCont ist ein Graphikverwalter(Container) als
Ableitung der Klasse TList implementiert.
Binden Sie diesen Verwalter in das Tangram-Projekt ein.
2. Leiten Sie die Klasse TLinie für eine Strecke zwischen zwei Punkten
TPolygon ab und fügen Sie sie ins Projekt A5/GrafikObjTest ein.
75
Ausblicke


OOP: Vererbung

Dialogfensters zum Editieren einzelner Objekte
Listenfenster zur Ansicht aller Objekte
...
76
Dialogfenster
OOP: Vererbung
TForm
TGrafEleDlg
TGrafikElement
Initialisieren()
Aktualisieren()
Speichern()



Das Dialogfenster ist durch eine Referenz mit einem Objekt verbunden
(initialisieren); es somit dessen Operationen aufrufen
Aktualisieren liest die Attribute des Objekts und zeigt sie an
Speichern schreibt die geänderten Attributwerte ins Objekt zurück
77
Implementierung
Initialisieren des Dialogs
Var Grafik : TGrafikElement;
procedure TGrafEleDlg.init(GrafObj : TGrafikElement);
OOP: Vererbung
begin
Grafik := GrafObj;
aktualisiere;
end;
Öffnen des Dialogs im Formular
SelObjekt := getElementAt(x,y); //angeklickte Figur finden
if (SelObjekt <> nil) then
begin //Dialog öffnen und initialisieren
GrafEleDlg.init(SelObjekt);//Referenz übergeben
GrafEleDlg.Show;
end;
78
Aufgabe 6
Entwerfen Sie einen Editier- Dialog für das Projekt SimpelObjekt
2.
Binden Sie den Dialog ins Projekt ein
OOP: Vererbung
1.
79
Literatur und Links


OOP: Vererbung


Helmut Balzert: Lehrbuch der Software-Technik
Eckart Modrow: Informatik mit Delphi Band 1 / 2
Siegfried Spolwig:
www.oszhdl.be.schule.de\gymnasium\faecher\informatik\index.htm
Klaus Merkert
http://hsg.region-kaiserslautern.de/faecher/inf/index.php
80
Lösung: A 3.4
TKonto
OOP: Vererbung
- FKontoNr : integer
- FStand : double
Create (nr : integer)
Auszahlen(Betrag : double)
TSparkonto
+ Auszahlen(...)
TGirokonto
+ Auszahlen(...)
81
Projekt Memory
Zu entwickeln ist ein Programm, das das bekannte Memory-Spiel simuliert.
OOP: Vererbung
Pflichten:
/0/ In einer ersten Version spielt ein Spieler alleine. Durch Mausklick können die Spielkarten
aufgedeckt werden. Der Computer ist dabei der Spielleiter. Der Punktestand des Spieler
wird protokolliert
/1/ In der zweiten Version ist der Computer ein Gegenspieler, der mit einer Gewinnstrategie
ausgestattet ist.
Prototyp:
82
OOP: Vererbung
Projekt Uhr
83
OOP: Vererbung
Ampelsteuerung Fußgängerübergang
Nach:
http://www.kbs.uni-hannover.de/Lehre/Info1/WS98/Projekte/atze/public_html/Presentation/
84
OOP: Vererbung
Ampelsteuerung Baustelle
Nach:
http://www.kbs.uni-hannover.de/Lehre/Info1/WS98/Projekte/atze/public_html/Presentation/
85