planning voor de rest van Datastructuren week maandag donderdag datastructuren college 12 15 mei vandaag 22 mei college 12: GUI toets 2: backtracking practicum dies onderwijsvrij hemelvaart onderwijsvrij klassen & inheritance GUI 29 mei 5 juni college 13: GUI2 2 e pinksterdag onderwijsvrij practicum practicum 1 12 juni??? overzicht/herhaling??? extra oefenen?? 2 klassen klassen zijn de basis voor object oriëntatie klasse (class) samengesteld datatype met methoden object instantie van zo'n klasse (doos met naam, adres en inhoud) 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 Inheritance (late binding) inheritance of overerving uitbreiding van bestaande klasse met nieuwe members (variabelen en/of methoden) herdefinitie van bestaande methoden basisklasse (base class): bestaande klasse afgeleide klasse (derived class): nieuwe, uitgebreide klasse voor implementatie is-a relatie student is een speciaal soort persoon auto is een speciaal soort voertuig mogelijk extra velden mogelijk extra methoden mogelijk herdefinitie van bestaande methoden een methode gebruikt moet worden: virtual 3 4 1
Voorbeeld Inheritance Inheritance: subtypes basis klasse: subklassen kunnen deze class Vehicle functie herdefinieren virtual ostream& info ( ostream& o ) return o << "A vehicle\n" ; ; 5 class MotorVehicle : public Vehicle protected: string license_nr; zichtbaar hier en in subklassen MotorVehicle ( const string& ln ) : license_nr ( ln ) const string& kenteken ( ) return license_nr ; ; ostream& info ( ostream& o ); // geen keyword virtual ; class Car : public MotorVehicle dit is weer een sub-klasse dit is een subklasse geeft aan dat je gaat herdefinieren Car ( const string& ln ) : MotorVehicle ( ln ) ; constructor van de ouder 6 meer subklassen van Vehicle class Bus : public MotorVehicle protected: int seats; Bus ( const string& ln, int s ) : MotorVehicle( ln ), seats( s ) ostream& info ( ostream& o ); ; class Bike : public Vehicle protected: int gears; Bike ( int g=1 ) : gears ( g ) ostream& info ( ostream& o ); implementatie methode info ostream& MotorVehicle :: info ( ostream& o ) return o << "A motor vehicle with reg no " << license_nr << endl; 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 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 )))); geeft (alles statisch te bepalen) class diagram info MotorVehicle license_nr info kenteken Vehicle gears info Bike A bus with reg no AB-CD-01 and 40 seats A bike with 7 gears A motor vehicle with reg no RV-ZJ-42 A motor vehicle with reg no LS-HL-97 Car seats info Bus 9 10 gebruik inheritance 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 ); 11 Dynamic binding (late binding) 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++ ) vehicles [ i ]. info ( cout ); hier dus 4 keer: A vehicle welke info-methode te gebruiken?? Vehicle of Car, Bus,.. afspraak in C++: geen pointer en niet by-reference geen dynamic binding 12 3
Dynamic binding (late binding) 2 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 motor vehicle with reg no LS-HL-97 A motor vehicle with reg no RV-ZJ-42 A bike with 7 gears A bus with reg no AB-CD-01 and 40 seats 13 gebruik subklassen 3 void main() nu gebruik... ik pointers Vehicle *vehicles[4]; vehicles[0] = &car; vehicles[1] = &mv; vehicles[2] = &bike; bepaal dynamisch vehicles[3] = &bus; welke info for ( int i=0; i<4; i++ ) gebruikt wordt vehicles [ i ] -> info ( cout ); geeft (pointer: dynamisch bepaald) A motor vehicle with reg no LS-HL-97 A motor vehicle with reg no RV-ZJ-42 A bike with 7 gears A bus with reg no AB-CD-01 and 40 seats 14 dynamic binding void print ( Vehicle& v ) // & zorgt voor dynamic binding v.info ( cout ); void main ( ) Bike bike ( 7 ); Vehicle v; v = bike; v.info ( cout ); Vehicle *vp; vp = &bike; vp -> info ( cout ); print ( bike ); geeft: A vehicle A bike with 7 gears A bike with 7 gears toekenning subklasse aan basisklasse // direct gebruik: statisch // pointer: dynamisch // call-by-reference: dynamisch 15 OO en events de wereld bestaat uit een aantal objecten objecten zijn tevreden wezens doen zelf niets spontaan op verzoek van de 'buitenwereld', een event, veranderen ze hun toestand eventueel veroorzaken ze events voor andere objecten event afhandelen = methode uitvoeren als methode is uitgevoerd gaan ze weer rusten 16 4
GUI Grafical User Interface 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)... 17 18 wat ziet je programma van events het GUI-systeem doet veel werk voor je er is een klasse GUI die het basis werk doet 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 programma hoeft zich dus nooit af te vragen of er n event is en welke handler dan gebruikt moet worden de GUI_kernel waarom een GUI_Kernel er zijn heelveel details te regelen in een GUI de ervaren programmeur wil dit kunnen er is daarom een ingewikkeld interface als beginner wil je niet alle details de GUI_kernel biedt een simpel interface lang niet alles kan, maar wat kan gaat simpel(er) 19 20 5
ontwerp GUI_kernel 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 de GUI klasse class GUI GUI ( GSIZE, char *title ); void Run ( WINARGS winargs ); void Run ( Menu& menu, WINARGS winargs ); virtual void Window ( const RECT& area ) virtual void Mouse ( const MOUSEINFO& mouse_info ) virtual void Keyboard ( const KEYINFO& key_info ) virtual void Timer ( const int dt ) friend class Canvas;... private:... handlers die je kunt herdefiniëren 21 22 het canvas al het tekenen binnen het window op het canvas class Canvas friend class GUI; Canvas ( GUI &gui ); void setpencolour ( RGBCOLOUR ); void setpenpos ( GPOINT ); void togglexormode ( ); void drawpoint ( ); void drawlineto ( GPOINT ); void drawrectangle ( GPOINT, GPOINT ); void drawtext ( const char *s ); void drawoval ( GPOINT, GPOINT ); void drawpolygon ( GPOINT points [], int size ); void fillrectangle ( GPOINT, GPOINT ); void filloval ( GPOINT, GPOINT ); void fillpolygon ( GPOINT points [], int size ); #include "gui_kernel.h" const int SreenWidth = 300; const int ScreenHight = 200; my first GUI program class mygui : public GUI 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" ); private: 23 24 6
my first GUI program 2 my first GUI program slot hoe maken we een GUI object 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 mygui& thegui() static mygui mg; return mg; 25 gebruik exceptions om fouten af te handelen try en catch zorgen hiervoor gebruik copy/paste programming 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 (); return 0; WinMain i.p.v. main alleen gebruikt als er binnen de try een exception komt 26 window events 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) Menu menu ( "File" ); menu. add ( "Start", start ). add ( ). add ("Stop", stop ); try thegui().run ( menu, catch (const GUIException& ge) ge.report (); return 0; hang handler aan menu voeg menu toe aan gui WINARGS(hi, hpi, cmdline, cmdshow)); menu geeft dus geen window events! 28 7
void start ( ) menu functies // the event handler Canvas canvas ( thegui ( ) ); // wil ook wat tekenen canvas. setpencolour ( BlueRGB ); canvas. setpenpos ( GPOINT ( 30, 60 )); canvas. drawtext ( "Nu aan het werk" ); void stop ( ) thegui ( ). Stop ( ); 29 toetsenbord structuur bevat alle informatie over toets struct KEYINFO bool isascii; // TRUE iff keycode is ASCII int keycode; ; voeg handler toe aan mygui class mygui : public GUI mygui () : GUI(GSIZE(SreenWidth,ScreenHight),"my first GUI") void Window ( const RECT& area ); void Keyboard ( const KEYINFO& info ); ; subklasse kan nieuwe definitie maken 30 een simpele key handler tekenen in XOR q -> quit s -> start alle andere toetsen: doe niets void mygui :: Keyboard ( const KEYINFO& key ) if ( key. isascii ) switch ( key. keycode ) case 'q': stop ( ) ; return; case 's': start ( ) ; return; default: return; voor alle kleuren c en n: c, n. XOR c n c c, n. XOR (XOR c n) n = c Dat wil zeggen als: 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 bevat informatie over linker knop en positie enum MouseState MouseDown // The mouse button goes down, MouseTrack // The mouse button is still down, MouseUp // The mouse button goes up ; struct MOUSEINFO MouseState mousestate; // State of the mouse GPOINT mousepos; // Current mouse position ; 33 muis void drawline ( GPOINT& begin, GPOINT& eind, Canvas& canvas ) canvas. setpenpos ( begin ); canvas. drawlineto ( eind ); 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; 34 muis part 2 muis part 3 muis bewegen met knop ingedrukt oude lijn wegpoetsen (xor tekenen) nieuwe lijn tekenen 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) 35 loslaten van muis knop: oude lijn wegpoetsen (xor tekenen) nieuwe lijn tekenen in rood case MouseUp: canvas.setpencolour ( BlackRGB ); canvas. togglexormode ( ); drawline ( begin, eind, canvas ); canvas.togglexormode ( ); canvas. setpencolour ( RedRGB ); drawline ( begin, p, canvas ); eind = p; break; overige events worden al weggefilterd 36 9
timer events zet een wekker (tijd in ms) const int ticks = 1000; wekker loopt nooit te vroeg af wekker kan iets te laat aflopen echt verstreken tijd (in ms) als argument voorbeeld timer handler 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 )); class mygui : public GUI int tikken; void Timer ( const int dt );... ; 37 Canvas canvas ( *this ); canvas. setpencolour ( RedRGB ); canvas. filloval ( lo, rb ); canvas. setpencolour ( WhiteRGB ); drawline ( centrum, eind, canvas ); 38 timer aanzetten standaard staat de wekker uit void start ( ) thegui ( ). starttimer ( ticks ); 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 39 de GUI valkuil met een GUI zijn er 2 waarheden: wat de gebruiker ziet op het scherm de inwendige toestand van het programma 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 definieer je eigen subklasse van GUI bevat handlers voor: (maak alleen wat nodig is, rest erf je van GUI ) window mouse toetenbord timer 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 Wat hebben we gedaan dictaat: H 15, bekijk voorbeelden boek:... GUI is gebaseerd op objecten programmeur schrijft handlers voor events systeem zorgt voor aanroepen handlers systeem zorgt voor standaard dingen menus tekenen window resizen window buttons filteren events maak een Windows Application geen Console Application! gebruik winmain i.p.v. main zorg dat er maximaal één ( 1 ) canvas is 41 42 11