planning voor de rest van Datastructuren
datastructuren college 12 klassen & inheritance GUI
1
week
maandag
donderdag
15 mei vandaag
college 12: GUI
dies onderwijsvrij
22 mei
toets 2: backtracking practicum
hemelvaart onderwijsvrij
29 mei
college 13: GUI2
practicum
5 juni
2e pinksterdag onderwijsvrij
practicum
12 juni
??? overzicht/herhaling ???
extra oefenen ?? 2
klassen
Inheritance (late binding)
•klassen zijn de basis voor object oriëntatie •klasse (class) samengesteld datatype met methoden •object
•inheritance of overerving uitbreiding van bestaande klasse met nieuwe members (variabelen en/of methoden) herdefinitie van bestaande methoden
instantie van zo'n klasse (doos met naam, adres en inhoud)
•basisklasse (base class): bestaande klasse •afgeleide klasse (derived class): nieuwe, uitgebreide klasse
•object oriëntatie: wereld bestaat alleen uit objecten •kenmerken object oriëntatie hiding: privite overerving, inheritance: je hebt subtypes object identity: uniek kenmerk van individueel object: this pointer dynamic binding beslis tijdens uitvoeren programma welke versie van een methode gebruikt moet worden: virtual
voor implementatie is-a relatie •student is een speciaal soort persoon •auto is een speciaal soort voertuig
3
mogelijk extra velden mogelijk extra methoden mogelijk herdefinitie van bestaande methoden
4
1
Voorbeeld Inheritance
Inheritance: subtypes
•basis klasse: subklassen kunnen deze class Vehicle functie herdefinieren { public: virtual ostream& info ( ostream& o ) { return o << "A vehicle\n" ; } };
5
meer subklassen van Vehicle
6
implementatie methode info ostream& MotorVehicle :: info ( ostream& o ) { return o << "A motor vehicle with reg no " << license_nr << endl; }
class Bus : public MotorVehicle { protected: int seats; public: Bus ( const string& ln, int s ) : MotorVehicle( ln ), seats( s ) {} ostream& info ( ostream& o ); }; class Bike : public Vehicle { protected: int gears; public: Bike ( int g=1 ) : gears ( g ) {} ostream& info ( ostream& o ); };
class MotorVehicle : public Vehicle dit is een { subklasse protected: zichtbaar hier en string license_nr; in subklassen public: MotorVehicle ( const string& ln ) : license_nr ( ln ) {} const string& kenteken ( ) { return license_nr ; }; ostream& info ( ostream& o ); // geen keyword virtual }; geeft aan dat je class Car : public MotorVehicle gaat herdefinieren { dit is weer een public: sub-klasse Car ( const string& ln ) : MotorVehicle ( ln ) {} }; constructor van de ouder
ostream& Bus :: info ( ostream& o ) { return o << "A bus with reg no " << license_nr << " and " << seats << " seats\n"; } ostream& Bike :: info ( ostream& o ) { return o << "A bike with " << gears << " gears\n"; } 7
8
2
Voorbeeld Gebruik
class diagram Vehicle
void main() { Car car ( "LS-HL-97" ); MotorVehicle mv ( "RV-ZJ-42" ); Bike bike ( 7 ); Bus bus ( "AB-CD-01", 40 ); car.info ( mv.info ( bike.info ( bus.info ( cout )))); }
info
MotorVehicle
geeft (alles statisch te bepalen) A A A A
Bike
license_nr info kenteken
bus with reg no AB-CD-01 and 40 seats bike with 7 gears motor vehicle with reg no RV-ZJ-42 motor vehicle with reg no LS-HL-97
gears info
Car
Bus seats info
9
gebruik inheritance
10
Dynamic binding (late binding)
•alle subklassen erven methoden en attributen van basisklasse je kunt dus met een subklasse minstens het zelfde als met de basisklasse in C++ mag je een instantie van de subklasse gebruiken als men een instantie van de basisklasse verwacht void main ( ) { Vehicle vehicles [ 4 ]; vehicles [ 0 ] = Car ( "LS-HL-97" ); vehicles [ 1 ] = MotorVehicle ( "RV-ZJ-42" ); vehicles [ 2 ] = Bus ( "AB-CD-01", 40 ); vehicles [ 3 ] = Bike ( 7 ); }
void main ( ) { Vehicle vehicles [ 4 ]; vehicles [ 0 ] = Car ( "LS-HL-97" ); vehicles [ 1 ] = MotorVehicle ( "RV-ZJ-42" ); vehicles [ 2 ] = Bus ( "AB-CD-01", 40 ); vehicles [ 3 ] = Bike ( 7 ); for ( int i=0; i<4; i++ ) hier dus 4 keer: vehicles [ i ] . info ( cout ); A vehicle }
•welke info-methode te gebruiken ?? Vehicle of Car, Bus, ..
•afspraak in C++: 11
geen pointer en niet by-reference ⇒ geen dynamic binding
12
3
Dynamic binding (late binding) 2
gebruik subklassen 3 nu gebruik void main() ik pointers { ... Vehicle *vehicles[4]; vehicles[0] = &car; vehicles[1] = &mv; bepaal dynamisch vehicles[2] = &bike; welke info vehicles[3] = &bus; gebruikt wordt for ( int i=0; i<4; i++ ) vehicles [ i ] -> info ( cout ); }
void main ( ) { Vehicle * vehicles [ 4 ]; vehicles [ 0 ] = new Car ( "LS-HL-97" ); vehicles [ 1 ] = new MotorVehicle ( "RV-ZJ-42" ); vehicles [ 2 ] = new Bike ( 7 ); vehicles [ 3 ] = new Bus ( "AB-CD-01", 40 ); for ( int i=0; i<4; i++ ) vehicles [ i ] -> info ( cout ); }
geeft ( pointer: dynamisch bepaald ) A A A A
geeft (pointer: dynamisch bepaald)
motor vehicle with reg no LS-HL-97 motor vehicle with reg no RV-ZJ-42 bike with 7 gears bus with reg no AB-CD-01 and 40 seats
A A A A
motor vehicle with reg no LS-HL-97 motor vehicle with reg no RV-ZJ-42 bike with 7 gears bus with reg no AB-CD-01 and 40 seats
13
dynamic binding
14
OO en events
void print ( Vehicle& v ) // & zorgt voor dynamic binding { v.info ( cout ); }
•de wereld bestaat uit een aantal objecten •objecten zijn tevreden wezens doen zelf niets spontaan
void main ( ) { Bike bike ( 7 ); Vehicle v; v = bike; v.info ( cout ); Vehicle *vp; vp = &bike; vp -> info ( cout ); print ( bike );
•op verzoek van de 'buitenwereld', een event, veranderen ze hun toestand
toekenning subklasse aan basisklasse
eventueel veroorzaken ze events voor andere objecten event afhandelen = methode uitvoeren als methode is uitgevoerd gaan ze weer rusten
// direct gebruik: statisch // pointer: dynamisch // call-by-reference: dynamisch
}
geeft: A vehicle A bike with 7 gears A bike with 7 gears
15
16
4
events for the GUI •een event is iedere voor het programma van buiten komende gebeurtenis toets ingedrukt, nog steeds ingedrukt, toets los muis knop in, nog steeds in, los, bewogen, drag window wordt (weer) zichtbaar, is verschoven wekker loopt af element van menu geselecteerd close box van window geklikt er is helemaal niets gebeurt (null-event) ...
GUI Grafical User Interface 17
18
wat ziet je programma van events
de GUI_kernel
•het GUI-systeem doet veel werk voor je
•waarom een GUI_Kernel
er is een klasse GUI die het basis werk doet
er zijn heelveel details te regelen in een GUI de ervaren programmeur wil dit kunnen er is daarom een ingewikkeld interface
•maak zelf een subklasse van de klasse GUI •jij moet handlers (functies/methoden) schrijven die de events afhandelen •het GUI-systeem zorgt voor koppeling events aan handlers
als beginner wil je niet alle details de GUI_kernel biedt een simpel interface lang niet alles kan, maar wat kan gaat simpel(er)
programma hoeft zich dus nooit af te vragen of er ‘n event is en welke handler dan gebruikt moet worden
19
20
5
ontwerp GUI_kernel
de GUI klasse class GUI { public:
•de class GUI regelt het gedrag van de GUI de event handlers zijn methoden binnen deze class
•een specifieke GUI is een subclass van GUI definieert handlers (opnieuw) dynamic binding van methoden
•beperkingen er is maar een window
void void
GUI Run Run
virtual virtual virtual virtual
void void void void
( GSIZE, char *title ); ( WINARGS winArgs ); ( Menu& menu, WINARGS winArgs ); Window Mouse Keyboard Timer
( ( ( (
friend class Canvas; ... private: ...
const const const const
RECT& area ) {} MOUSEINFO& mouse_info ) {} KEYINFO& key_info ) {} int dt ) {}
handlers die je kunt herdefiniëren
21
22
het canvas
my first GUI program #include "gui_kernel.h"
•al het tekenen binnen het window op het canvas class Canvas { friend class GUI; public: Canvas void setPenColour void setPenPos void toggleXORmode void drawPOINT void drawLineTo void drawRectangle void drawText void drawOval void drawPolygon void fillRectangle void fillOval void fillPolygon private:
const int SreenWidth = 300; const int ScreenHight = 200; ( ( ( ( ( ( ( ( ( ( ( ( (
GUI &gui ); RGBCOLOUR ); GPOINT ); ); ); GPOINT ); GPOINT, GPOINT ); const char *s ); GPOINT, GPOINT ); GPOINT points [], int size ); GPOINT, GPOINT ); GPOINT, GPOINT ); GPOINT points [], int size );
class myGUI : public GUI { public: myGUI () : GUI(GSIZE(SreenWidth,ScreenHight),"my first GUI") {} void Window ( const RECT& area ); }; void myGUI :: Window ( const RECT& area ) { Canvas canvas ( *this ); canvas . setPenColour ( RedRGB ); canvas . setPenPos ( GPOINT ( 30, 30 )); canvas . drawText ( "Hallo Nijmegen" ); 23
}
24
6
my first GUI program 2
my first GUI program slot
•hoe maken we een GUI object
•gebruik exceptions om fouten af te handelen
maak gui-object binnen de try om fouten te vangen dus geen globaal object gebruik functie met static lokaal object schrijf theGUI( ) i.p.v. theGUI
try en catch zorgen hiervoor gebruik copy/paste programming WinMain
i.p.v. main
int WINAPI WinMain (HINSTANCE hi , HINSTANCE hpi, PSTR cmdLine, int cmdShow) { try { theGUI() . Run (WINARGS(hi, hpi, cmdLine, cmdShow)); } catch ( const GUIException& ge ) { ge.report (); alleen gebruikt als er } binnen de try een return 0; exception komt }
myGUI& theGUI() { static myGUI mg; return mg; }
25
window events
26
menu
•de handler voor window events: void myGUI :: Window ( const RECT& area ) { Canvas canvas ( *this ); canvas.setPenColour ( RedRGB ); canvas.setPenPos ( GPOINT ( 30, 30 )); canvas.drawText ( "Hallo Nijmegen" ); }
•wordt aangeroepen bij: maken van window opnieuw zichtbaar worden van window •area geeft deel aan dat zichtbaar wordt •eenvoudige oplossing: herteken alles 27
int WINAPI WinMain (HINSTANCE hi, HINSTANCE hpi , PSTR cmdLine, int cmdShow) { hang handler Menu menu ( "File" ); aan menu menu . add ( "Start", start ) . add ( ) voeg menu . add ("Stop", stop ); toe aan gui try { theGUI().Run ( menu, WINARGS(hi, hpi, cmdLine, cmdShow)); } catch (const GUIException& ge) { ge.report (); } menu geeft dus geen return 0; window events ! }
28
7
menu functies
toetsenbord
•structuur bevat alle informatie over toets
void start ( ) // the event handler { Canvas canvas ( theGUI ( ) ); // wil ook wat tekenen canvas . setPenColour ( BlueRGB ); canvas . setPenPos ( GPOINT ( 30, 60 )); canvas . drawText ( "Nu aan het werk" ); }
struct KEYINFO { bool isASCII; // TRUE iff keyCode is ASCII int keyCode; };
•voeg handler toe aan myGUI class myGUI : public GUI { public: myGUI () : GUI(GSIZE(SreenWidth,ScreenHight),"my first GUI") {} void Window ( const RECT& area ); void Keyboard ( const KEYINFO& info ); };
void stop ( ) { theGUI ( ) . Stop ( ); }
29
een simpele key handler
subklasse kan nieuwe definitie maken
30
tekenen in XOR
•q -> quit •s -> start •alle andere toetsen: doe niets
•voor alle kleuren c en n: •∀ c, n . XOR c n ≠ c •∀ c, n . XOR (XOR c n) n = c •Dat wil zeggen als:
void myGUI :: Keyboard ( const KEYINFO& key ) { if ( key . isASCII ) switch ( key . keyCode ) { case 'q': stop ( ) ; return; case 's': start ( ) ; return; default: return; } }
als je in xor-mode tekent zie je het altijd als je 2 keer het zelfde tekent is het weer weg
•een heel oude ‘truc’ waar Microsoft patent op heeft gekregen natuurlijk trekt niemand zich hier wat van aan
31
32
8
de mouse state
muis void drawLine ( GPOINT& begin, GPOINT& eind, Canvas& canvas ) { canvas . setPenPos ( begin ); canvas . drawLineTo ( eind ); }
•bevat informatie over linker knop en positie enum MouseState { MouseDown , MouseTrack , MouseUp } ;
// The mouse button goes down // The mouse button is still down // The mouse button goes up
void myGUI :: Mouse ( const MOUSEINFO& mouse ) { Canvas canvas ( *this ); GPOINT p = mouse . mousePos; switch ( mouse . mouseState ) gedefinieerd in { case MouseDown: klasse myGUI begin = eind = p; canvas . setPenColour ( BlackRGB ); canvas . toggleXORmode( ); drawLine ( begin, eind, canvas ); canvas . toggleXORmode ( ); break;
struct MOUSEINFO { MouseState mouseState; // State of the mouse GPOINT mousePos; // Current mouse position } ;
33
34
muis part 2
muis part 3 •loslaten van muis knop:
•muis bewegen met knop ingedrukt
oude lijn wegpoetsen (xor tekenen) nieuwe lijn tekenen in rood
oude lijn wegpoetsen (xor tekenen) nieuwe lijn tekenen
case MouseUp: canvas.setPenColour ( BlackRGB ); canvas . toggleXORmode ( ); drawLine ( begin, eind, canvas ); canvas.toggleXORmode ( ); canvas . setPenColour ( RedRGB ); drawLine ( begin, p, canvas ); eind = p; break; }
case MouseTrack: canvas . setPenColour ( BlackRGB ); canvas . toggleXORmode ( ); drawLine ( begin, eind, canvas ); drawLine ( begin, p, canvas ); canvas . toggleXORmode ( ); eind = p; break;
•beter: doe alleen wat als p ≠ eind (muis echt bewogen)
}
•overige events worden al weggefilterd 35
36
9
timer events
voorbeeld timer handler
•zet een wekker (tijd in ms)
void myGUI :: Timer ( const int dt ) { int tpm = 60 * ticks ; // aantal tikken per minuut tikken = ( tikken + dt ) % tpm; GPOINT eind ( mx + r * sin ( pi * 2 * tikken / tpm ), my – r * cos ( pi * 2 * tikken / tpm ));
const int ticks = 1000;
•wekker loopt nooit te vroeg af •wekker kan iets te laat aflopen echt verstreken tijd (in ms) als argument
Canvas canvas ( *this );
class myGUI : public GUI { int tikken; public: void Timer ( const int dt ); ... };
canvas . setPenColour ( RedRGB ); canvas . fillOval ( lo, rb ); canvas . setPenColour ( WhiteRGB ); drawLine ( centrum, eind, canvas ); } 37
timer aanzetten
de GUI valkuil
•standaard staat de wekker uit
•met een GUI zijn er 2 waarheden:
void start ( ) { theGUI ( ) . startTimer ( ticks ); }
wat de gebruiker ziet op het scherm de inwendige toestand van het programma
•gebruik via menu (of toetsenbord, of ...): int WINAPI WinMain (HINSTANCE h, HINSTANCE p, PSTR l, int c) { Menu menu ( "File" ); menu . add ( "Start", start ) . add( ) . add ( "Quit" , stop ); try { theGUI ( ) . Run (menu, WINARGS (h, p, l, c)); } catch ( const GUIException& ge ) { ge . report (); } return 0; }
•eenmaal gestart blijf de timer steeds aflopen
38
39
•het is de taak van de programmeur om dit te laten sporen bij de voorbeelden wordt alleen de eerste tekst getekend bij een window event ! voor een echt programma moet je alle getekende lijnen onthouden je wil ook lijnen kunnen selecteren en weggooien
•meng rekenen en tekenen niet! maak een klein en duidelijk interface tussen de GUI en de logica van het programma (voor spel, database, ..)
40
10
algemeen schema GUI programma
Wat hebben we gedaan
•definieer je eigen subklasse van GUI
• • •
bevat handlers voor:
(maak alleen wat nodig is, rest erf je van GUI ) •window •mouse •toetenbord •timer
dictaat: H 15, bekijk voorbeelden boek: ... GUI is gebaseerd op objecten
state
• • • •
•maak één instantie van die subklasse en start interactie via methode run hier voeg je menu's toe
•handlers doen het werk, aanroepen van handlers gebeurt voor je •zorg dat er maximaal één ( 1 ) canvas is
programmeur schrijft handlers voor events systeem zorgt voor aanroepen handlers systeem zorgt voor standaard dingen
• 41
menus tekenen window resizen window buttons filteren events
maak een Windows Application
geen Console Application ! gebruik winmain i.p.v. main
42
11