CURSUS VISUAL C++
1
1 Opfrissing c++ 1.1 Kenmerken van c++ C++ C 1- C++ is a. b. c.
betere C Fctie prototyping is verplicht; Fcte overloading is daardoor mogelijk; Referenties; i. is alternatieve naam voor object; ii. we komen ze tegen bij het doorgeven van argumenten; 1. CALL BY VALUE 2. CALL BY ADDRESS 3. CALL BY REFERENCE
#include
void wisselbyvalue(int, int); void wisselbyaddress(int *, int *); void wisselbyref(int &, int &); void main() { int i, j; i=5; j=7; wisselbyvalue(i,j); cout << i << “ “ << j << endl; i=5; j=7; wisselbyaddress(&I, &j); cout << I << “ “ <<< j << endl; i=5; j=7; wisselbyref(I, j); }
//def void wisselbyvalue(int x, int y) { int hulp = x; x=y; y=hulp;
* = de inhoud van & = het adres van
// endline = \n i j 5 7 i
j
5->7
7->5
i 5->7
j 7->5
x
y
hulp
5->7
7->5
5
2
}/*wisselbyvalue*/
void wisselbyaddress(int *x, int *y) { int hulp=*x; *x=*y; *y=hulp; }/*wisselbyaddress*/
x
y
hulp
5->7
7->5
5
void wisselbyref(int &x, int &y) { int hulp = x; x = y; y = hulp; }/*wisselbyref*/
x
y
hulp
5->7
7->5
5
d. dynamisch geheugenbeheer i. alloceren: new of new [ ] ii. vrijgeven: delete of delete[ ] e. datatype bool f. typecasting = expliciet typeconversie i. cast notatie ii. fctie notatie g. plaats van def van variabelen hoeft niet aan het begin van de fctieblok staan h. inline functies (i.p.v. macro’s = #define) 2- Objectgeoriënteerde taalelementen a. OO : i. Encapsulatie ii. Inheritance iii. Polyformisme en dynamic binding
3
1.2 De class 1- Private members a. Default b. Enkel toegankelijk voor memberfcties van die klasse 2- Public members a. Toegankelijk voor gebruikers van die klasse 3- Def van memberfcties a. Binnen de klassedef b. Buiten de klassedef 4- Constructor a. Wordt opgeroepen bij creatie van object b. Kan overload worden c. Default constructor = costructor zonder argumenten 5- Destructor a. Wordt opgeroepen als de levensduur van het object ten einde is b. Zal zorgen voor het vrijgeven van dynamisch gealloceerd geheugen c. Kan niet overload worden 6- Copy-constructor a. Zorgt voor initial van een object met een ander object van dezelfde klasse b. Indien geen copy construct -> lidsgewijze kopiering c. Voorzie een copy-constructor als lidsgewijze kopiering niet voldoet //CLASS Class Telgids{ Private: Char* naam; Int nr; Public: Telgids(); ~Telgids(); void print(); }; Telgids :: Telgids(const Telgids &t) //copy constructor { naam = new char[strlen(t.naam) + 1 ]; strcpy(naam, t.naam); nr = t.nr; } //DEF void Telgids :: print() { cout << naam << “ “ << nr << endl; }
4
Telgids :: Telgids() //default constructor { naam = new char(strlen(“Pol”) + 1]; strcpy(naam, “Pol”); nr = 1; } Telgids :: ~Telgids() { delete[]; } //DRIVER void main(void){ Telgids t1; T1.print(); }/*main*/
//LIDGEWIJZE KOPIEREN void main(void) { Telgids t1; Telgids t2(t1); }
naam Nr 1
Pol/0
Naam Nr 1 Copy constructor wordt opgeroepen: - bij init van een object met ander object van dezelfde klasse - object doorgeven aan functie CALL BY VALUE toonnaam(t1); - object returnt
5
7- Memberobjecten Class string{ Private: Char* p; Int len; Public: String(){ P = new char [strlen(“voorbeeld”) + 1]; Strcpy(P, “voorbeeld”); Len =strlen(“voorbeeld”); } String(const char *ps){ //constructor P = new char[strlen(ps) + 1]; //str meegegeven Strcpy(p, ps); Len = strlen(ps); } String(const string & s){ P = new char[strlen(s.p) + 1]; Strcpy(p, s.p) Len = strlen(s.len); }
//kopieconstructor
}; class Telgids{ String naam; Int nr; Public: Telgids() : naam(“Pol”) { Nr = 1; } Telgids() : naam() { nr=1; }
//initialisatielijst
//default constructor //1 van de 2 kiezen
; //DRIVER void main(void) { Telgids t1; Telgids t2(t1); }
//diepe kopie
6
8- this-pointer = pointer die wordt doorgegeven aan memberfunctie, wanneer deze wijst naar oproepende object Voorbeeld: Class Int{ Private: int a; //moet liggen tussen public: //-1000 en 1000 Int(int val=0){ //stdlib.h -> __max(…, …) a=val; //stdlib.h -> __min(…, …) a=__min(1000,__max(-1000, a)); } //levert min of max af Int & vermeerdermet(int val){ a+=val; a=__min(1000, __max(-1000, a)); return *this; } }; //& is noodzakelijk want anders wordt steeds een kopie opgehoogd en niet de waarde zelf void main(){ Int x; x.vermeerdermet(20); x.vermeerdermet(30).vermeerdermet(40); }/*main*/
7
1.3 Inheritance • • • •
Er ontstaat een hiërarchie van classes Basisklasse(base class) Afgeleide klasse (derived class) Afgeleide klasse kan altijd verder afgeleid worden
Voorbeeld: Persoon <- clublid <- voorzitter //CLASSES class Persoon { String naam; Int geboren; Public: Persoon(char *nr, int g); String getnaam(); Int getgeboren(); Virtual void print(); }; class Clublid : public Persoon{ float donatie; public: clublid(char *n, int g, float d); float getdonatie(); }; class voorzitter : public clublid{ int startjaar; public: voorzitter(char *n, int g, float, d, int s); int getstartjaar(); virtual void print(); }; //DRIVER void main(){ clublid l1(“piet, 25091985, 1000); cout << l1.getdonatie() <<endl; cout << l1.getgeboren() <<endl; (l1.getnaam()).print(); cout << endl; voorzitter v1(“anm”, 24101986, 200, 1998); cout << v1.getstartjaar() << endl; cout << v1.getdonatie() << endl; //is mogelijk dankzij cout << v1.getgeboren() << endl; //inheritance
8
1.4 Polyformisme •
Object polyformisme =een base class object kann geinitialiseerd worden met een derived class object
Clublid l1 (“Piete”, 25091985, 1000); Persoon p1(l1); Voorzitter v1(“Ann”, 26414980, 2000, 1998); Clublid l2(v1); Persoon p2(v1); •
pointer polymorfisme = een base class object kan opgevuld worden met het adres van een derived class object
Persoon *pp = &l1; pp->print(); Clublid *pl = &v1;
//Piet 25091985
1.5 Dynamic Binding (virtual) Standaard: compile-time binding (early binding) Dynamic binding (late binding)
9
2 Basis windowsprogrammatie 2.1 Vergelijking tussen dos-prog en windows-prog 2.1.1 Dos programma’s • •
Wordt van boven naar beneden uitgevoerd Bestaand systeem is ondergeschikt aan programma
2.1.2 Windows programma’s • • •
Event-driven programmatie Windows zal een event als een message in de messagequeue van het programma plaatsen Programma: hier staat de code voor afhandelen van de messages Programma is ondergeschikt aan windows
Schema: Events
Invoer toetsenbord Event
Muisklik Event
Windows Mesg
Code
mesg
Code
2.2 Traditioneel Windowsprogramma =programma met API-functieoproeper Application Programming Interface • API-functies -> vele functies meegeleverd met (SDK-functies) Windows en noodzakelijk voor schrijven van windowsprogramma (software Development Kit) ELK Windowsprogramma gebruikt API-functies API, gekend door DLL’s Traditionele Windowsprogrammatie(met API-functies) ->MOEILIJK
10
•
MFC Microsoft Foundation Class Library =bibliotheek van classes die de API-functies “verpakken” op OO manier -> programmeur
•
Traditioneel Windowsprogramma 2 functies: o Winmain() - start van programma - initialisaties o WindowProc() - afhandeling van de messages - applicatie spef. Code WINDOWS API-functies
WinMain
WindowProc
11
2.3 De functie WinMain() •
Prototype:
Int
WINAPI
WinMain(
Type gedef in returnw windef.h
incl
HINSTANCE hPrevInstance, Steeds NULL 32 – bit appl
HINSTANCE
hInstance,
- gedef in windows.h - 32 –bit handle =identificatie
- handle van lopende programma - unieke identificatie
LPSTR
lpCmdline
int nCmdShow
(32 bit long pointer naar pointer -> string) opdr. regel Start, uitvoeren openen XXX
•
Geef aan hoe prog. Venster moet getoond worden Mogelijk: SW_SHOWMAXIMIZED SW_SHOWMINIMIZED
Body WinMain() 1. Specificatie van programmavenster (karakt. Van programmavenster wordt def) 2. Tonen van programmavenster 3. Messageloop message wordt opgehaald en doorgestuurd naar WindowProc
2.3.1 Def vensterklasse - (struct) WNDCLASS Winclass; opvullen van members
//def vensterklasse
WNDCLASS WindowClass; WindowClass.style = CS_HREDRAW|CS_VREDRAW; WindowClass.lpfnWndProc = WindowProc; //ftie die msg afh WindowClass.cbClsExtra = 0; WindowClass.cbWndExtra = 0; WindowClass.hInstance = hInstance; WindowClass.hIcon = LoadIcon(0,IDI_WINLOGO); WindowClass.hCursor = LoadCursor(0,IDC_WAIT); WindowClass.hbrBackground = (HBRUSH)(COLOR_HIGHLIGHT+ 1); WindowClass.lpszMenuName = 0; char szAppName[] = "TradWin"; WindowClass.lpszClassName = szAppName; 3. Registreren van vensterklasse RegisterClass(&WindowClass);
12
2.3.2 Creatie van programmavenster Creatie van programmavenster: mbv API ftie HWND hWnd; hWnd = CreateWindow(szAppName,"Een traditioneel Windows programma", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0); HWND CreateWindow( LPCTSTR lpClassName, // registered class name LPCTSTR lpWindowName, // window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // menu handle or child identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // window-creation data
);
2.3.3 Tonen van programmavenster mbv API-ftie ShowWindow(hWnd, nCmdShow);
2.3.4 Tonen van client Area mbv API-ftie UpdateWindow(hWnd); -> wordt WM_PAINT-message gestuurd naar WindowProc
2.3.5 Messageloop - haalt message uit messagequeue en stuurt message door naar WindowProc(), waar de afhandeling van de message gebeurt. - hart van elk windowsprogramma -controlestructuur voor de rest van het programma - wordt beëindigd door WM_QUIT CODE: MSG msg; while (getmessage (&msg, 0, 0, 0 ) niet WM_QUIT ){ TranslateMessage(&msg); DispatchMessage(&msg);//stuurt ber nr WindowProc() }
13
GetMessage()
Message?
J get message
J WM_QUIT?
TRUE
FALSE
2.4 De WindowProc()-functie -Prototype long WINAPI
WindowProc
(HWND hwnd, handle vh venster waarin het event zich voordeed.
UINT message, eigenlijke message
WPARAM wParam,
LPARAM lParam);
bijkomstige info ivm message
14
-Body switch(message) { case WM_PAINT: hDC = BeginPaint(hWnd, &PaintSt); GetClientRect(hWnd, &aRect); SetBkMode(hDC, TRANSPARENT); DrawText(hDC, "Hello World!", -1, &aRect, DT_SINGLELINE| DT_CENTER|DT_VCENTER); EndPaint(hWnd, &PaintSt); return 0; case WM_DESTROY: //als prog.venst wordt gesloten PostQuitMessage(0); //stuurt WM_QUITàeinde prog. return 0; default: return DefWindowProc(hWnd, message, wParam, lParam); //stuurt message terug naar windows àzorgt voor default afhandeling. } Visual Studio Programma’tje om messages te bekijken: Microsoft Spy++
15
3 Windowsporgrammatie mbv MFC 3.1 De MFC-bibliotheek -MFC: Microsoft Foundation Classes -Hiërarchie van classes à basis voor windowsprogrammatie in Visual C++ -MFC-classes zijn OO-verpakking van de API-functies -Schrijven van Windowsprogramma’s mbv MFC -zelden: MFC-objecte n creëren en gebruiken -wel: objecten creëren en gebruiken van classes afgeleid van MFCclasses MFC
Zie HELP (hierarchy chart) à zie opl.map, worddoc.
Prog:
16
ENKELE INTERESSANTE CLASSES -CObject: * Basis MFC-bibliotheek * biedt serialisatie è alle klassen afgeleid van CObject àserialisatie -CCmdTarget: * Basis message-map architectuur à link message-functie die message zal afhandelen -CWnd: * Basisfunctionaliteit voor werken met vensters -CFrameWnd: * Representeert programmavenster van SDI-applicaties àSingle Document Interface -CMDIFrameWnd: * Representeert programmavenster van MDI-applicaties àMultiple Document Interface -CDialog: * Basisklasse voor werken met dialoogvensters -CView: * Basisfunctionaliteit voor werken met views een ‘view’ staat in voor visualisatie van een document -CDocument: * Basisfunctionaliteit voor werken met documenten een ‘document’ staat in voor data van een document -CWinApp: * Representeert de applicatie zelf
3.2 Een eenvoudige MFC-applicatie Doelstelling: Tonen van programmavenster met randen, een titelbalk een max-, min- en sluitknop -File, New Win32 appl. EenvMFC -Aangeven dat MFC-classes zullen gebruikt worden àProject à Settings à General tabblad à Use MFC-classes (1 vd 2) -File, New Source File EenvMFC.cpp -headerfile afxwin.h èdefinitie van MFC-classes -CWinApp èelk programma zal een klasse hebben afgeleid van CWinApp Waarvoor dient deze CWinApp: -Opstarten -Initialisatie -Runnen -Beëindigen
17
-CWinApp: èvirtuele functies -InitInstance() à1e functie die wordt opgeroepen àcreatie en tonen van programmavenster àdeze functie zal herdefinieert worden in de afgeleide klasse van onze applicatie (virtual BOOL InitInstance();) -Run() àimplementatie messageloop -ExitInstance() àals programma beëindigd wordt (opkuis) -OnIdle() àwat er gebeurt als het programma wacht -CFrameWnd: Basisfunctionaliteit van programma-venster àklasse afleiden van CFrameWnd #include class COurApp : public CWinApp { public: virtual BOOL InitInstance(); }; class COurWnd : public CFrameWnd { public: COurWnd(){ Create (0, "Testapplicatie Casimir"); } }; COurApp AnApplication;
//Globaal object
BOOL COurApp ::InitInstance() { m_pMainWnd=new COurWnd; m_pMainWnd->ShowWindow(m_nCmdShow); return TRUE; }
18
Werking programma 1. Creatie van object AnApplication 2. WinMain() wordt opgeroepen à roept 3. AnApplication.InitInstance() 4. Creatie + tonen van programmavenster 5. AnApplication.Run() -implementatie messageloop -blijft hier tot programma beëindigt wordt 6. AnApplication.ExitInstance()
3.3 Een SDI-applicatie m.b.v. Applicatie wizard Dit is een tool waarmee men volledige programma’s kan maken 1. File -> New 2. MFC AppWizard(exe) 3. STEP 1 a. SDI b. Taal kiezen 4. STEP 2: Database support a. None 5. STEP 3: Samengestelde documenten a. None 6. STEP 4: Uiterlijk a. Initialisatiewaarden gebruiken(standard) 7. STEP 5: a. MFC Standard commentaar??? b. Yes c. i. DLL? hierbij wordt steeds verwezen naar een extern DLL-bestan ii. Static Linked Library? hierbij wordt steeds verwezen naar een intern DLL-bestand -> exe-file wordt groter iii. Wat kiezen: wanneer we met Static Linked Library werken wil dit zeggen dat het DLL-bestand steeds in het intern geheugen beland: 4 exe-files met zelfde DLL -> 4 x zelfde DLL in intern geheugen. Wij kiezen voor shared DLL, deze is tijds- en ruimtebesparend. 8. STEP 6: Overzicht van gegenereerde klasses a. CEersteSDIApp (afgeleid van CwinApp) Represent de apllicatie b. CmainFrame (afgeleid van CframeWnd) represent van programmavenster 19
c. CEeersteSDIDoc (afgeleid van Document) represent het document: de data van de applicatie d. CEersteSDIView (afgeleid van Cview) represent de view: visualisatie van data Een overzicht •
CObject
Code: o Classview § MFC
CCmdTarget CwinThread CwinApp
CWnd CfranceWad
Cdocument
Cview
CDialog
Applicatie CEersteSDIAppl CmainFrame
§ §
CEersteDSIDoc CEersteSDIView
CAboutDLG
CEersteSDIApp FileView • ReadMe.txt • EersteSDI.h o Def van CEersteSDIApp – klasse § Declaratie van de memberfunctie • Constr CEersteSDIApp() • Herdef van virtuele ftie void InitInstance() • Messagehandler =berichtafhandelfunctie • Void onAppAbout(); § Macro DECLARE.MESSAGE.MAP() § Commentaar • EersteSDI.cpp o 1) Def van memberfuncties o 2) Message map o Creatie van globaal object CEersteSDIApp theApp o 1) A: Constr CEersteSDIApp::CEersteSDIApp() { /} o B: Void CEersteSDIApp::InitInstance() { AfxEnableControlContainer(); //globale functie //ondersteund ActiveX-controls Enable3Dcontrol(); //3D-uitzicht van controls //laadt CTL3D32.DLL SetRegistryKey(_T(“Local…”)
20
//maakt registry sleutel aan (inst van prop) //(regedit>HKEY_CURRENT_USER\software\ //LOCAL…\EersteSDI LoadStdProfileSettings(); //loaadt de meest recent gebruikte files en //prog. Inst Creatie(dynamisch) v. CsingleDocTemplate.object
Aplicatie Object pointer
CSingleDocTemplate Document Template Object pointer creeërt
creeërt
CDocument
FrameWnd
Document Object
Frame Window Object
pointer
pointer creeërt View Object pointer CView ParceCommandLine(cmdInfo) //parsen van de commandolijn processShellCommand(cmdInfo) uitvoeren van de commandolijn + even parameter m_pMainWnd -> ShowWindow(…); m_pMainWnd -> UpdateWindow(…); //prog. Venster word getoond } o C: messagehandler void Ceerste SDIApp::OnAppAbout() { //creatie + tonen(DoModel()) van dialoogvenster }
21
o 2) Message-map link message – messagehandler BEGIN_MESSAGE_MAP(CEersteSDIApp, ON_COMMAND(ID_APP_ABOUT, OnAppAbout) ON_COMMAND(ID_FILE_NEW, WinApp.OnFileNew) END_MESSAGE_MAP() Werking van het programma 1. Creatie van globaal object theApp 2. WinMain wordt uitgevoerd 3. theApp.Initinstance() wordt uitgevoerd 4. theApp.Run() wordt uitgevoerd //messageloop 5. theApp.Exitintance() wordt uitgevoerd
3.4 Een MDI-applicatie mbv AppWizard • • • • • • •
Step 1 o MDI Step 2 o None Step 3 o None Step 4 o Default Step 5 o Default Step 6 o … Class View o CEersteMDIApp (afgeleid van CWinApp) § Stelt app zelf voor o CMainFrame (afgeleid van CMDIFrameWnd) § Stelt programmavenster van app voor o CChildFrame (afgeleid van CMDIChildWnd) § Stelt documentvenster(s) van app voor o CEersteMDIDoc (afgeleid van CDocument) § Bevat de data van app o CEersteMDIView (afgeleid van CView) § Visualisatie van de data o CAboutDialog (afgeleid van CDialog) § About-venster
22
3.5 Een Dialog-based applicatie mbv AppWizard • • • •
•
Step 1 o Dialog Based Step 2 o Default Step 3 o Default Step 4 o CEersteDialogApp (afgeleid van CWinApp) o CEersteDialogDlg (afgeleid van CDialog) § Stelt dialoogvenster voor o CAboutDlg (afgeleid van CDialog) § About-venster InitInstance o Geen CSDIDocTemplate o Geen CMDIDocTemplate o WEL CEersteDialogDlg dlg; dlg.DoModal(); è zorgt ervoor dat venster wordt getoond
23
4 Hoofdstuk 4. Dialoogvensters en besturingselementen 4.1 Dialoogvensters • •
Hebben aantal controls (besturingselementen) Dialoogvenster.resource : bevat visuele van dialoogvenster (mbv resourceeditor) Dialoogvenster.class : bevat de data van dialoogvenster (mbv class-wizard)
4.2 Dialoogvenster.resource maken • •
SDI app maken met AppWizard Resource View o Nieuw dialoogvenster : RK op Dialog-map; insert dialog o Properties dialoogvenster : RK op IDD … ; Properties o Dubbelklik instellen : Tools-Options-Compatibility laatste vakje uitzetten o Controls aanbrengen op dialoogvenster
4.3 Een dialoogvenster-class schrijven •
•
RK op dialoogvenster ; Class Wizard o Membervars • Controls op dialoogvenster • Select control • Add var o Name o Category o Type Class View o CSDIDialog • Datamembers • M_check • M_edit • M_keuze1 • Memberfties • Constructor CSDIDialog ( ) è initialisatie • DoDataExchange ( ) è staat in voor transfer en validatie van data transfer è DDX fties (dialog data exchange) validatie è DDV fties (dialog data validation)
4.4 Een Dialoogvenster-class gebruiken •
Vb: dialoogvenster tonen bij opstarten van applicatie
24
• •
Dialoogvenster – resource – Resource View Dialoogvenster + controls +eig. Dialoogvenster klasse - CDSIDialog à CDialog Mbv ClassWizard a. datamembers b. memberfuncties – constructor - DoDataExchange à transfer variabele <-> control o InitInstance( ) uitbreiden #include “SDIDialog” OPMERKING!! 2 soorten dialoogvensters: § Modal dialoogvenster(moet beantwoordt worden) § Modeless dialoogvenster (moet niet …) o Modal dialoogvenster gebruiken - object creëren van klasse CSDIDialog CSDIDialog dlg; - dialoogvenster tonen dlg.DoModal();
Dialog :: DoModal() à 1) OnInitDialog() wordt opgeroepen - init van van dialoogvenster - UpdateData(FALSE) wordt opgeroepen - DoDataExchange() wordt opgeroepen - transfer var à control 2) tonen van dialoogvenster 3) interactie met gebruiker 4) OK-knop - OnOk() wordt opgeroepen - UpdateData(TRUE) wordt opgeroepen - DoDataExchange() - transfer control à var - dialoogvenster wordt gesloten - returnwaarde: IDOK 4) Cancel-knop - OnCancel() wordt opgeroepen - dialoogvenster wordt gesloten - returnwaarde: IDCANCEL vb: Er wordt een messagebox opgeroepen als men op OK of op Cancel drukt! //dlg.DoModal(); à in commentaar zetten - InitInstance() Cstring msg; If (dlg.DoModel() == IDOK) Msg = “OK werd ingedrukt”; Else 25
Msg = “Cancel werd ingedrukt”; AfxMessageBox(msg); //GLOBALE FUNCTIE
4.5 Een editbox gebruiken Vb1 : • EditBox tekenen in ResourceView controlID : IDC_EDIT • EditBox linken(koppelen) aan variabele van categorie Value ClassWizard – MemberVariables controlID IDC_EDIT varname m_edit category Value (inhoud van control var) type Cstring • Class CSDIDialog 1. membervar Cstring m_edit; 2. constructor 3. DoDataExchange • Init van EditBox 1. constructor m_edit = “Informatica”; 2. OnInitDialog() CSDIDialog – rechtsklik – Add memberftie Add virtual functie Add Message handler WN_INITDIALOG Add en Edit
OnInitDialog() Cdialog :: OnInitDialog(); // TO DO m_edit = „Informatica“; UDATEDATA(FALSE); Var à mldighe(zie Thomas) 3. Tekst van EditBox tonen (in msg) InitInstance Msg += dlg.m_edit; Vb2 : • EditBox tekenen in ResourceView controlID : IDC_EDIT2 • EditBox linken(koppelen) aan variabele van categorie Control ClassWizard – MemberVariables controlID IDC_EDIT2 varname m_edit2
26
•
•
category Control (control zelf wordt gerepresenteerd door var) type CEdit • Class CSDIDialog 1. membervar CEdit m_edit2; 2. constructor / 3. DoDataExchange Init van EditBox m_edit2.SetWindowText(“3TI”); Opm: memberfties van klasse die Constructor control representeert als control kan slechts opgeroepen worden als OnInitDialog() dialoogvenster actief is Tekst van EditBox tonen (in msg) m_edit2.getWindowText(m_edit2tekst); OnOK() toevoegen via CSDIDialog – rechtklik – Add Messagehandler Add en Edit Membervariabele van CSDIDialog (hoe: rechtsklik – Add Membervar) Cstring m_edit2tekst; InitInstance Msg += dlg.m_edit2tekst;
Vb3 : • EditBox tekenen in ResourceView controlID : IDC_EDIT3 • Geen variabele koppelen aan EditBox • Init van EditBox Constructor OnInitDialog() Cedit * pEdit = (Cedit*)GetDlgItem(IDC_EDIT3); à ftie uit CWnd levert een pointer naar control pEdit à SetWindowText(“Middag”); •
Tekst tonen van EditBox (in msg) OnOK()
27
Cedit * pEdit = (Cedit*)GetDlgItem(IDC_EDIT3); pEdit à GetWindowText(m_edit3tekst);
•
è class CSDIDialog à Add Membervar Cstring m_edit3tekst; InitInstance Msg += dlg.m_edit3tekst;
6 Documenten en Views 6.1 De document / view – architectuur • •
•
Document bevat de data vab de applicatie die de gebruiker kan opslaan of ophalen van de schijf. SDI – appl -> steeds doc.klasse MDI i. Voorbeeld: SDI – appl Hfstk6Rechthoeken Cdocument -> bevat de basisfunctionaliteit voor het werken met doc’s ii. CRechthoekenDoc o.a. datamembers(add membervar) OnNewDocument() //init van datamembers Serialize() //opslaan van datamembers op //schijf (ophalen) View zorgt voor de visualisatie van de data int document én zorgt voor opvangen van gebruikersinvoer. i. Cview -> bevat de basisfunctionaliteit voor he werken met views. ii. CRechthoekenView - GetDocument() levert pointer af naar het document (CrechthoekDoc*) - OnDraw() de data uit het doc wordt getoond de data wordt opgeroepen als gevolg van WM_PAINT -Verband tussen Doc / View / FrameWindow InitInstance() CsingleDoxTemplate – obj – wordt aagemaakt Document-obj wordt aangemaakt FrameWindow -obj wordt aangemaakt View-obj worden aangemaakt 28
Werkwijze 1. Def. De datamembers in doc-klasse 2. Init van datamembers in OnNewDocuments() van Docklasse 3. Toon het doc in OnDraw() van viewklasse 4. Plaats memberfunctie in view -klasse zodat de gebruiker het doc kan bewerken 5. Schrijf functie Serialize() uit doc klasse voor opslaan en ophalen van de data
6.2 De toep. Rechthoeken Doelstelling: Bij het klikken wordt een rechthoek geteken op de aanklikplaats (max 100) 1. Def datamembers in CrechthoekenDoc Cpoint m_points[100]; //tabel:: linkerbovenhoeken int m_pointIndex; //index van eerstvolgende lege elementen in array 2. Init van datamembers in OnNewDocument() m_pointIndex = 0; 3. Toon het doc in OnDraw(CDC *pDC) CDC-klasse -> bevat de dive context = interface tussen device onafhankelijke functies en fysieke functies. o.a. Rectangle()- ftie. CRechthoekDoc* pDoc= GetDocument(); for(int i=0; im_pointIndex;i+1) { pDC->Rectangle( pDoc->m_points[i].x, pDoc->m_points[i].y, pDoc->m_points[i].x+20 rechtbenedenhoek pDoc->m_points[i].y+20);
//x-co linkerboven //y-co linkerbovenhoek //x-co
4. Plaats memberfunctie in CrechterhoekenView zodat de gebruiken kan bewerken OnLButtonDown(VINT, mFlags, Cpoint point) { CrechthoekenDoc*pDoc = GetDocument(); pDoc ->m_points[pDoc ->[m_pointIndex]=point; pDoc ->m_pointIndex ++; pDoc->SetModifiedFlag(); 29
//het doc is gewijzigd // bij het sluiten van de apllicatie wordt gevraagd om te saven Invalidate(); //maakt client-area ongeldig MW_PAINT-bericht ->OnDraw() } Werkwijze: 1. definitie in Doc. Klasse 2. datamembers initialiseren in OnNewDocument() 3. Toon het document in OnDraw() 4. Zorg dat de gebruiker het document kan wijzigen 5. Serialize
6.3 De Array-klassen (bijlage F: F1-F2) •
MFC: CbyteArray CDWordArray COBArray CptrArray CstringArray CuintArray CwordArray
•
Objecten van Array-klassen zijn bijna = arrays in C à array is een aaneengesloten blok maar kunnen dynamisch groeien of inkrimpen
•
Memberfuncties 1. default constructor: 2. GetSize(): 3. GetUpperBound(): 4. SetSize(): 5. RemoveAll(): 6. GetAt(): 7. SetAt(): 8. ElementAt() 9. SetAtGrow(): 10. Add(): 11. InsertAt(): 12. RemoveAt(): 13. operator[ ]
: : : : : : :
array van Bytes array van double words (32 bit) array van Cobject * array van void * array van Cstring.obj array van unsigned int array van 16-bit woorden
maakt lege array geeft aantal el. In array geeft grootste index stelt aanvangsgrootte in verwijdert alle elementen geeft waarde op index zet waarde op index geeft referentie vr pointer naar arrayelement zet waarde op index (+ ev. Vergroting vd array) zet waarde op einde (+ ev. Vergroting vd array) zet waarde op einde (rest schuift door) verwijdert element op index
30
•
Toepassing Rechthoeken2 (SDI) Idem Rechthoeken zonder beperking in aantal rechthoeken 1. Definitie datamembers in Crechthoeken2Doc COBArray tabel; Tabel CObject*
CObject*
CPoint CPoint Pointer polymorfisme = een base class pointer kan opgevuld worden met het adres van een derived class object CObject *
CObject
CPoint
CPoint CPtrArray tabel; Tabel Void * CPoint
Void * CPoint
Void * CPoint
2. Init van datamembers 3. Toon het document in CRechtHoeken2View :: OnDraw(CDC* pDC) CRechtHoeken2Doc* pDoc = getDocument(); for (int i=0; i< (pDoc -> tabel).GetSize(); i++){ CPoint* pPoint = (CPoint*)pDoc -> tabel[i] pDC -> Rectangle( pPoint -> x, //x-coord. Van LBovenhoek pPoint -> y, //y-coord. Van Lbovenhoek pPoint -> x+20, //y-coord. v Rbenedenhoek pPoint -> y+20, //y-coord. v Rbenedenhoek ); } 4. Zorg dat de gebruiker het document kan aanpassen CRechtHoeken2View; OnLButtonDown(Uint nFlags, CPoint point) { CPoint* pPoint = new CPoint(point); CRechtHoeken2Doc* pDoc = GetDocument(); (pDoc -> tabel).Add(pPoint); pDoc -> SetModifiedFlag(); 31
Invalidate(); //WM_PAINT --> onDraw() } 5. Vrijgeven van dynamisch gealloceerde ruimte ~ CRechtHoeken2Doc() { for(i=0; i < tabel.GetSize(); i++){ CPoint* pPoint = (CPoint*) tabel[i]; delete pPoint; } tabel.RemoveAll(); }
6.4 De lijst-klassen
•
•
MFC:
• • •
Dubbel gelinkte lijst Variabele van het type POSITION Memberfuncties 1. default constr maakt lege lijst 2. GetHead() geeft head-node 3. GetTail() geeft tail-node 4. RemoveHead() verwijdert head-node 5. RemoveTail() verwijdert tail-node 6. AddHead voegt node toe aan begin van de lijst 7. AddTail voegt node toe aan einde van de lijst 8. RemoveAll() verwijdert alle elementen 9. GetHeadPosition() levert POSITION van head-node 10. GetTailPosition() levert POSITION van tail-node 11. GetNext() geeft element op POSITION en zet POSITION op volgende node 12. GetPrev() geeft element op POSITION en zet POSITION op vorige node 13. GetAt() geeft element op bepaalde POSITION 14. SetAt() zet element op bepaalde POSITION 15. RemoveAt() verwijdert element op bepaalde POSITION 16. InsertBefore() voegt element toe vóór POSITION 17. InsertAfter() voegt element toe ná POSITION 18. Find() geeft POSITION van el. gespec. dr pointer 19. FindIndex() geeft POSITION van el. gespec. dr index 20. GetCount() geeft aantal elementen in lijst 21. IsEmpty() leeg?
CPtrList: lijst van void* CObList: lijst van CObject* CstringList: lijst van String-objecten
Toepassing: RechtHoeken3 (SDI) 1. Definitie van datamembers in CRechthoeken3Doc CPtrList lijst;
32
2. Initialiseren 3. Teken de rehthoeken in CRechthoeken3View :: OnDraw(CDC* pDC) //AppWizard: CRechthoeken3Doc *pDoc = getDocument(); //zelf: POSITION pos = (pDoc -> lijst).GetHeadPosition(); while( pos != NULL){ CPoint* pPoint = (CPoint*) (pDoc -> lijst).GetNext(pos); pDC -> Rectangle(pPoint -> x, pPoint -> y, pPoint -> x+20, pPoint -> y+20); } 4. Zorg dat de gebruiker het document kan aanpassen OnLButtonDown( Uint nFlags, CPoint point) { CPoint* pPoint = new CPoint(point); CRechtHoeken3Doc *pDoc = GetDocument(); (pDoc -> lijst).AddTail(pPoint); pDoc -> SetModifiedFlag(); Invalidate(); } 5. Vrijgeven van dynamisch gealloc. Ruimte ~RechtHoeken3Doc() { POSITION pos = lijst.GetHeadPosition(); while( pos != NULL){ CPoint* pPoint = (CPoint*)lijst.GetNext(pos); delete pPoint; } lijst.RemoveAll(); }
6.5 De map-klassen (F.5) -MFC:
CMapWordToPtr CMapPtrToWord CMapPtrToPtr CMapWordToOb CMapStringToPtr CMapStringToOb CMapStringToString
map: void* sleutel: 16-bit word map: 16 bit waarden, sleutel: void* map: void*, sleutel: void* map: CObject*, sleutel: 16 bit word map: void*, sleutel: CString-object map: CObject*, sleutel: CString-object map: CString-object, sleutel: CString-object
-Object van map-klasse = verzameling van elementen Key
Data
33
-variabele van type POSITION (volgorde is onbepaald) -Memberfuncties default constructor Lookup() SetAt() RemoveKey() RemoveAll() GetStartPosition() GetNextAssoc() GetCount() IsEmpty()
maakt lege map geeft de date terug van element met bepaalde sleutel voegt element toe aan map met bepaalde sleutel verwijdert element met bepaalde sleutel verwijdert alle elementen levert POSITION van startelement geeft element terug van element op POSITION en plaatst die POSITION één verder geeft aantal elementen terug map leeg?
Voorbeeld: Rechthoeken4 1. Definitie datamember in CRechthoekn4Doc Key
Data
CPoint x y
2. /
CMapWordToPtr map; Initialisatie
34
3.
void CRechthoeken4View::OnDraw(CDC* pDC) { CRechthoeken4Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here WORD key; void* pPoint; POSITION pos = pDoc->map.GetStartPosition(); while (pos != NULL){ pDoc->map.GetNextAssoc(pos, key, pPoint); pDC->Rectangle(((CPoint*)pPoint)->x, ((CPoint*)pPoint)->y, ((CPoint*)pPoint)->x + 25, ((CPoint*)pPoint)->y + 25); } } 4. void CRechthoeken4View::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CPoint* pPoint = new CPoint(point); CRechthoeken4Doc* pDoc = GetDocument(); WORD key = pDoc->map.GetCount(); pDoc->map.SetAt(key, pPoint); pDoc->SetModifiedFlag(); Invalidate();
5.
CView::OnLButtonDown(nFlags, point); } CRechthoeken4Doc::~CRechthoeken4Doc() { WORD key; void* pPoint; POSITION pos = map.GetStartPosition(); while (pos != NULL){ map.GetNextAssoc(pos, key, pPoint); delete (CPoint*)pPoint; } map.RemoveAll(); }
35
Hoofdstuk 7: Naar het scherm schrijven 5 Device Context Windows OS: • Kernel servics • User services • GDI services(Grafical Device interface) - functies voor apparaatonafhankelijke uitvoer Windowsprogramma: GDI-functies -> gebruiken een device context ->struct: co stelsel pen lettertype brush Driver van apparaat MFC prog: GDI-functie wordt ingekapseld in CDC-klasse
6 WMPAINT Wordt gestuurd • Door windows aan prog: bij start prog – resize van programmavenster • Door programma aan programma: Invalid van prog. Venster WM-PAINT wordt afgehandeld in void Cview::OnPaint() CpaintDC dc(this); OnPrepareDc(&dc); OnDraw(&dc); }
7 De toepassing Paint1 -SDI paint1 Doelstelling: na na na na
klik tekst in# lettertypes klik lijnen met # pennen klik rechthoeken met # bruches klik
36
8 Werken met lettertypes Werkwijze: 1. creeer object van klasse Cpoint 2. Initialisaite van Cpoint-object 3. Selecteer het font-object in device context 4. schrijf in device context 5. selecteer de oude font opnieuw in device context 1. Cfont font; 2. #mogelijkheden i.v.m. intitialisati a. createFontIndirect(LOGFONT) b. CreateFont(-,-,-,-,-) c. LogFont.lfHeigt= //Hoogte van lettert ype //in logische eenhden y //afh. van Mapping Mode //default: WM_TEXT x //->logische eenheid = pixel //ook: MW_LOENGLISH //->logische eenheid= 0,01 inch d. LogFont.lfWidth = 0; //breedte va lettertype in logische eenheden //indien= 0 ->passende breedte e. LogFont.lfEscapement=0; //hoek f. LogFont.orientation=0; g. LogFont.lfWeight FW_NORMAL //tekenstijl vb. FW_NORMAL / FW_BOLD h. LogFont.lfItalic = FALSE; i. LogFont.lfUnderline=FALSE; j. LogFont.lfStrikeOut = FALSE; //Doorhalen k. LogFont.dfCharSet = ANSI_CHARSET; //tekenset l. LogFont.lfClipPrecision = OUT_TT_PRECIS; m. LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; //tekens afgebroken n. LogFont.lfQuality = DEFAULT_QUALITY //Afdruk o. LogFont.lfPitchAndFamily = VARIABLE_PITCH //letterafstand Strcpy(logFont.lfFaceNAme, “Times New Roman”); //naam lettertype font.CreateFontIndirect(logFont); 3. Prototype CDC Cfont* SelectObject(Cfont *pFont); Cfont* SelectObject -> SelectObject(& font) ; 4. pDC -> Textout (0, 0, « Naar het scherm schrijven ») 5. pDC->SelectObject(oldFont);
Void ShowFonts(CDC* pDC)
37
{ Cfont font; LOGFONT logFont; logFont. … font.CreateFontIndirect(&logFont); Cfont* oldFont = pDC -> SelectObject(&font); //font wordt current font pDC -> TextOut(0,0, » Naar het scherm»); pDC -> SelectObject(oldFont); } // uitbreiding: 10 lijnen tekst à variatie in lettertype (nog in de vorige functie…) // alleen LOGFONT logFont; en alle initialistaties daaronder worden behouden // de rest moet in commentaar… char* lettertypes[3] = {“Arial”, “Times New Roman”, “Comic Sans MS” }; for( int i = 0; i<10; i++){ logFont.lfHeight = 16 + (i * 8); logFont.lfItalic = i % 2; // ene keer italic, de andere keer niet enz… strcpy( logFont.lfFaceName, lettertypes[ i % 3]); // is char-array dus strcpy Cfont font; Font.CreateFontIndirect(&logFont); Cfont* oldFont = pDC -> SelectObject(&font); // font is curent font pDC -> TextOut( 0, pos, « Naar het scherm » ); pos += logFont.lfHeight; pDC -> SelectObject(oldFont); }
8.1 7.5 Werken met pennen = Tekenen van lijnen en figuren Werkwijze: 1. Creëren object van klasse Cpen 2. Initialiseren van dit CPen-object 3. Selecteer dir Cpen-object in DC 4. Tekenen in DC 5. Selecteer de oude pen terug in DC In Cpaint1View à bij switch à case 1 à vervangen mess-box in ShowPen(pDC);
38
Void ShowPen( CDC* pDC){ Cpen pen; // init CreatePen( - , - , - ); à we kiezen voor deze! // CreatePenIndirect ( - ); è via LOGPEN – variabele pen.CreatePen(
PS_SOLID
penstijl: vbn: -
,
4
,
RGB( 255, 0, 0) );
PS_SOLID -PS_DOT . . . PS_DASHDOT -- . PS_DASH -- -PS_DASHDOTDOT -- . .
Pendikte, in logische eenheden(pixel) Penkleur: RGB( 255, 0, 0)
8.2 CPen* oldPen = pDC -> SelectObject( &pen); // pen wordt current pen //Tekenen in DC CPoint CDC :: MoveTo( int x, int y); CPoint CDC :: MoveTo(CPoint point); // oude punt
// dit punt wordt current punt
BOOL CDC :: LineTo(int x, int y); BOOL CDC :: LineTo(CPoint point); // tekent lijn vanaf current punt tot eindpunt, eindpunt wordt current punt pDC -> MoveTo( 20, 20); pDC -> LineTo( 200, 20); pDC -> SelectObject( oldPen); } Uibreiding: 10 lijnen tekenen à pen varieert For ( int i=0; i<10; i++){ CPen pen ( PS_SOLID, ( i * 3) +1 , RGB(( i * 20 ) % 256, (i * 40 ) % 256, (i * 60 ) % 256)); // pen wordt current pen pDC -> MoveTo( 20, pos); pDC -> LineTo( 200, pos); pos += ( i * 3) +1 +5; pDC -> Select object( oldpen); }
39
8.3 7.6 Werken met kwasten = opvullen van gesloten figuur Werkwijze: analoog In Cpaint1View à bij switch à case 2 à vervangen mess-box in ShowBrush(pDC); Void ShowBrush( CDC* pDC) { Cbrush brush; // init CreateSolidBrush() // egale kleur // CreateHatchBrush() // patroon + kleur // CreateBrushIndirect() // via LOGBRUSH – variabele brush.CreateHatchBrush( patroon: 0 1 2 3 4 5
HS_CROSS ,
RGB (255, 0, 0) );
à HS_HORIZONTAL à HS_VERTICAL ||| à HS_BDIAGONAL \\\ à HS_FDIAGONAL /// à HS_CROSS ### à HSDIAGCROSS XXX
Cbrush* oldBrush = pDC -> SelectObject( &brush); // current brush pDC -> Rectangle( 20, 20, 200, 60); pDC -> SelectObject( oldBrush); } Uitbreiding: 10 rechthoeken à brush varieert à patroon en kleur int pos = 0; for (int i=0; i<10; i++){ CBrush brush(i%6, RGB((i*10)%256, (i*50)%256, (i*90)%256)); CBrush* oldBrush = pDC->SelectObject(&brush); pDC->Rectangle(pos, pos , pos+100, pos+100); pos+= (i+10)+1+5; pDC->SelectObject(oldBrush); }
40
OEFENING LETTERTYPES CLettertypesDialog -datamembers CString m_keuzelettertype; CListBox m_lettertype; CString m_tekst;
//bevat naan van het gekozen lettertype //gekoppeld aan Listbox //gekoppeld aan editbox
-OnInitDialog() m_lettertype.AddString("Arial"); m_lettertype.AddString("Times New Roman"); m_lettertype.AddString("Comic Sans MS"); m_lettertype.SetCurSel(0); -OnOK() int index = m_lettertype.GetCurSel(); m_lettertype.GetText(index, m_keuzelettertype); CLettertypesDoc -datamembers CString lettertype; CString tekst; CLettertypeView -OnLButtonDown(-,-) CLettertypesDialog dlg; CLettertypesDoc* pDoc = GetDocument(); if(dlg.DoModal() == IDOK){ pDoc->tekst = dlg.m_tekst; pDoc->lettertype = dlg.m_keuzelettertype; pDoc->SetModifiedFlag(); Invalidate(); } NIET VERGETEN: #include "LettertypesDialog.h" -OnDraw() CFont font; LOGFONT logFont; strcpy(logFont.lfFaceName, pDoc->lettertype); font.CreateFontIndirect(&logFont); CFont* oldFont = pDC->SelectObject(&font); pDC->TextOut(0,0,pDoc->tekst); pDC->SelectObject(oldFont);
41
Persis2 • Cpersis2Doc: Datamember(s): CStringList lijst; • OnNewDocument() Lijst.AddHead(“Default message”); • CPersis2View: - OnDraw(CDC* pDC) Cstring tekst; int y = 0; POSITION pos = pDoc -> lijst.GetHeadPosition(); While(pos != NULL){ tekst = pDoc -> lijst.GetNext(pos); pDC -> TextOut( 0, y, tekst); // y += 20; CFont* pFont = pDC -> GetCurrentFont(); LOGFONT logFont ; pFont -> GetLogFont( & logFont) ; y += logFont.lfHeight ; - OnLButtonDown(--,--) CTime now = CTime :: GetCurrentTime() ; Cstring teksttijd = now.Format(« %H %M %S« ) ; Cstring tekst = “Message changed at ” + teksttijd; CPersis2Doc* pDoc -> GetDocument(); pDoc -> lijst.AddTail(tekst); pDoc -> SetModifiedFlag(); Invalidate(); - CPersis2Doc: void Serialize(Carchive &ar){ lijst.Serialize(ar); // serialiseert alle nodes(CString) if()…… //staat al ingevuld! } Ø Vaststelling: - Default message blablablablabla blablablablabla - File, New Default message Default message blablablablabla blablablablabla - Default message - File, open Default message Default message blablablablabla blablablablabla
42
Ø Oorzaak: SDI-applicatie => slechts 1 document-object wordt aangemaakt en steeds hergebruikt File, New à OnNewDocument() File, Open à OnOpenDocument Het document moet gewist worden ð oproepen DeleteContents() => voeg DeleteContents toe aan Doc-klasse CPersis2Doc à Add Virtual Function à DeleteContents() à lijst.RemoveAll();
8.4 8.4 Een serialiseerbare klasse maken à voor een lijst te kunen maken van complexere objecten (ipv CString of CPoint –obj) 1. Leid de klasse af van CObject 2. Definieer de Serialize()-functie in de klasse -roep eerst de Serialize()-functie op van CObject -schrijf datamembers in archief mbv << -lees datamembers uit archief mbv >> 3. Macro DECLARE_SERIAL(classname) ; // ZONDER PUNT-KOMMA !!(is macro) in klassedefinitie 4. Macro IMPLEMENT_SERIAL(classname, baseclass, 0) ; in .cpp-file met definitie van memberfuncties 5. Voorzie default constructor
8.5 8.4 De Toepassing Persis3 -Doelstelling:
na starten: na klik : na klik :
0. Default message 1. Message ……… 2. Message …………
Refnr msg => klasse CMessage -> int refnr; -> CString msg;
43
-Werkwijze: ð AppWizard Persis3 SDI ð Maak nieuwe (serialiseerbare) klasse CMessage -CPersis3 classes -> Add New Class -> Class type : generic class Name : CMessage Derived from : CObject -datamembers: int refnr; //private maken CString msg; // private maken -memberfuncties: void Set_Message(int n, CString m){ refnr = n; msg = m; } int Get_Refnr(){ return refnr; } CString Get_Msg(){ Return msg; } void Serialize(Carchive & ar){ CObject :: Serialize(ar); If( ar.IsStoring() ){ ar << refnr << msg ; }else{ ar >> refnr >> msg ; } } -Macro’s toevoegen -class CMessage : public CObject{ DECLARE_SERIAL(CMessage) … }; -message.cpp IMPLEMENT_SERIAL(CMessage, CObject, 0) CMessage :: CMessage(){ … }
versienr
ð CPersis3Doc -datamember(s): CobList lijst; -OnNewDocument(){ //CMessage m;
dit zal niet gaan: is lokaal->w vrijgegeven bij verlaten van de ftie //m.Set_Message( 0, “blabla”); //lijst.AddHead( &m);
44
CMessage* pMessage = new CMessage ; pMessage -> Set_Message( 0, “Default message”) ; lijst.AddHead(pMessage) ; } ð CPersis3View -OnDraw( CDC* pDC) CString tekst; POSITION pos = pDoc -> lijst.GetHeadPosition(); While(pos != NULL){ CMessage* pMessage = (CMessage*)pDoc-> lijst.GetNext(pos) ; tekst.Format(“%d”, pMessage -> Get_Refnr() ); tekst += pMessage -> Get_Msg(); pDC -> TextOut( 0, y, tekst); y += 20; } -OnLButtonDown(--,--) CTime now = CTime :: GetCurrentTime() ; CString teksttijd = now.Format(“%H %M %S”); CString tekst = “Message changed at ” + teksttijd ; CPersis3Doc* pDoc = GetDocument() ; int nr = pDoc -> lijst.GetCount() ; CMessage* pMessage = new CMessage() //dynamisch! pMessage -> Set_Message(nr, tekst) ; //nu nog opnemen in lijst pDoc -> lijst.AddTail(pMessage) ; pDoc -> SetModifiedFlag(); Invalidate(); ð CPersis3Doc Serialize( CArchive & ar){ lijst.Serialize(ar); //serialisatie van CMessages } ~CPersis3Doc() DeleteContents()
45
Oefening Teken Doelstelling: Bij een klik wordt een lijn getekend tot de muisknop losgelaten wordt. Hoe coderen: Probleem: -lijst van CPoint-objecten -> niet serialiseerbaar Oplossing: -Maak zelf serialiseerbare klasse CPunt. ->Doc: lijst van CPunt van Cpunt-objecten COBList
Cobject*
Cobject*
x y
46
9 9 EEN COMPLETE TOEPASSING MAKEN 9.1 9.1 werken met menu’s – Deel 1 -SDI-applicatie ToonTekst è Doelstelling: menu: Invoer Tekst, kunnen selecteren of er horizontaal of verticaal moet gecentreerd worden. Bij ok wordt alles op het scherm getoond. Alles moet kunnen bewaard worden -AppWizard à SDI : 1 menu IDR_MAINFRAME (File Edit View Help) à MDI : 2 menu’s : -geen doc open: IDR_MAINFRAME (File View Help) -doc open: IDR_TOONTETYPE (File Edit View Window Help) (de eerste 6 letters van de applicatienaam wordt genomen) -Menu uitbreiden Recource View IDR_MAINFRAME
à “Invoer” toevoegen (“&Invoer” v r sneltoets Alt-I) à “&Tekst” toevoegen (Alt-T) properties menu-item -ID ID_INVOER_TEKST -prompt tekst in statusbalk
-Dialoogvenster tekenen -editbox -IDC_TEKST -2 checkboxes -IDC_HORIZCENT -IDC_VERTCENT -Dialoogvensterklasse definieren ClassWizard -CTekstDialog datamembers: CString m_tekst; //gekoppeld a editbox BOOL m_horizcent; BOOL m_vertcent; -Definieren datamembers in doc-klasse CToonTekstDoc à CString tekst; BOOL horizcent; BOOL vertcent; int kleur; //0=zwart, 1=rood, 2=blauw -Initialisatie van datamembers in OnNewDocument( ) tekst = “”; horizcent = FALSE; vertcent = FALSE; kleur = 0;
47
-toon document in de functie OnDraw (CDC* PDC) int DTflags = 0; if (pDoc -> horizcent == TRUE) DTflags |= DT_CENTER; if (pDoc -> vertcent == TRUE) DTflags |= (DT_VCENTER | DT_SINGLELINE); CRect rect; GetClientRect(& rect); if (pDoc -> kleur == 0) pDC-> SetTextColor(RGB(0,0,0)); if (pDoc -> kleur == 1) pDC-> SetTextColor(RGB(255,0,0)); if (pDoc -> kleur == 2) pDC-> SetTextColor(RGB(0,0,255)); pDC->DrawText(pDoc->tekst, &rect, DTflags); logische OR || bitsgewijze OR | int flags = 0; 0 0 0 0 0 01 flags = flags | 1; 0 0 0 0 0 1 flags |= 1; flags = flags + 1;
-Voorzie memberfuncties zodat de gebruiker het doc kan aanpassen menu à invoer tekst à WM_COMMAND –message à menu-messagehandler à waar? -in View-klasse (tot nu toe) -in Doc-klasse CToonTekstDoc à Add messagehandler ID_INVOER_TEKST – COMMAND OnInvoerTekst () CTekstDialog dlg; dlg.m_tekst = tekst; dlg.m_horizcent = horizcent; dlg.m_vertcent = vertcent; if (dlg.DoModal () == IDOK){ tekst = dlg.m_tekst; horizcent = dlg.m_horizcent; vertcent = dlg.m_vertcent;
Je zou kunnen zeggen dat deze initialisatie in de OnInitDialog van de dialoogvenster-klasse kan geplaatst worden, maar DIT KAN NIET!!!
48
SetModifiedFlag (); UpdateAllViews(NULL);
//OnDraw () wordt opgeroepen
} -Zorg dat het document kan bewaard worden CToonTekstDoc Serialize(CArchive &ar) ar << tekst << horizcent << vertcent; ar >> tekst >> horizcent >> vertcent;
9.2 Werken met menu’s – DEEL 2 -SDI-applicatie : ToonTekst uitbreiden -Doelstelling: menu -> Kleur zwart rood blauw -Menu uitbreiden à ZIE RODE KLEUR IN VORIG DEEL -CToonTekstDoc à 3 menu messagehandlers -ID_KLEUR_ZWART à WM_COMMAND OnKleurZwart(){ kleur = 0; } -ID_KLEUR_ROOD à WM_COMMAND OnKleurZwart(){ kleur = 1; } -ID_KLEUR_BLAUW à WM_COMMAND OnKleurZwart(){ kleur = 2; } -menu à Kleur Er wordt een UPDATE_COMMAND_UI – message gestuurd voor elke menu-item Daarna worden de menu-items getoond. -CToonTekstDoc ID_KLEUR_ZWART à UPDATE_COMMAND_UI messagehandler OnUpdateKleurZwart(CCmdUI* pCmdUI){ pCmdUI -> SetCheck (kleur == 0); } OnUpdateKleurRood(CCmdUI* pCmdUI){ pCmdUI -> SetCheck (kleur == 1); 49
} OnUpdateKleurBlauw (CCmdUI* pCmdUI){ pCmdUI -> SetCheck (kleur == 2); } -Serialize (CArchive &ar) ar << … << kleur ar >> … >> kleur
9.3 Werken met werkbalken -SDI-applicatie: Toontekst Toolbar vier knoppen… 1 voor tekst… 3 voor kleuren -Toolbar uitbreiden Resource View Toolbar -Teken de knop à properties ID vd KNOP = ID van corresponderende menuoptie
10 STANDAARDBESTURINGSELEMENTEN 10.1 Werken met Spin-Control -SDI-applicatie: Controls -Doelstelling: -Standaard à
rechthoek 0,0 afmetingen 200x200 pendikte 1
-menu: Tools Options Dialoogvenster waar pendikte kan aangepast worden -rechthoekàbewaren -Maak de serialiseerbare klasse CRechthoek -CRechthoek :: public Cobject -Datamembers: -Private: int x, y, pendikte; -Memberfuncties:
int Get_X(), Get_Y(), Get_Pendikte(); void Set_Rechthoek(int, int, int); void Serialize(CArchive &ar);
-Macro:
DECLARE_SERIAL(CRechthoek) IMPLEMENT_SERIAL(CRechthoek, CObject, 0)
50
-CControlDoc -Datamembers: CRechthoek rechthoek; -init in OnNewDocument() rechthoek.Set_Rechthoek(0,0,1); -Serialisatie in Seriable(-) rechthoek.Serialize(ar); -CControlView -Teken doc in OnDraw(-) CPen pen(PS_SOLID, pDoc->rechthoek.Get_Pendikte(), RGB(255,0,0)); CPen* OldPen = pDC->SelectObject(&pen); pDC->Rectangle(pDoc->rechthoek.Get_X(), pDoc->rechthoek.Get_Y(), pDoc->rechthoek.Get_X() + 200, pDoc->rechthoek.Get_Y() + 200); pDC->SelectObject(OldPen); -Menu uitbreiden Resource View Tools -Dialoogvenster tekenen Resource View editbox IDC_PENDIKTE spin IDC_SPIN_PENDIKTE -> properties Styles Arrow key -> spin te bedienen met up / down Set buddy integer -> in editbox enkel integers Autobuddy -> de editbox die juist voor de spin komt in tabvolgorde is dan de buddy -Dialoogvensterklasse maken mbv ClassView COptionDlg -Datamembers int m_pendikte; // gekoppeld aan editbox (MIN 1, MAX 10) -OnInitDialog() //init editbox m_pendikte = 1; UpdateData (FALSE); //var->Control CSpinButtonCtrl* pSpin; pSpin= (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN_PENDIKTE); pSpin->SetRange(1,10); Menu - messagehandler schrijven in View in Doc
51
OnToolsOptions(){ COptionsDlg Dlg; if(dlg.DoModal() == IDOK){ rechthoek.SetRechthoek(0,0,dlg.m_pendikte); SetModifiedFlag(); UpdateAllViews(NULL); } }
10.2 Slider -SDI-appl Controls uitbreiden Tools – Options > De pendikte van x- en y-as kunnen veranderen. COptionsDlg -datamembers int m_x; // gekoppeld aan IDC_x int m_y; // gekoppeld aan IDC_y
MIN = 0 MAX = 400
eign voor EditBox
-OnInitDialog() CSliderCtrl* pSliderX = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_X); pSliderX -> SetRange(0,400); pSliderX -> SetPos(m_x); CSliderCtrl* pSliderY = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_Y); pSliderY -> SetRange(0,400); pSliderY -> SetPos(m_y); // slider verschuift à editbox aanpassen à WM_HSCROLL-message wordt gestuurd naar dialogbox -OnHScroll(-,-,CScrollBar* pScrollBar) { CSliderCtrl* pSliderX = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_X); if( (CSliderCtrl*)pScrollBar == pSliderX){ m_x = pSliderX -> GetPos(); } CSliderCtrl* pSliderY = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_Y); if( (CSliderCtrl*)pScrollBar == pSliderY){ m_y = pSliderY -> GetPos(); } UpdateData(FALSE); // var à control à Editbox } // editbox invullen à slider moet ook verschuiven // à EN_CHANGE wordt gestuurd(onmiddellijk w slider aangepast) // à EN_KILLFOCUS-message (wanneer je editbox verlaat zal de slider aangepast w) // à OnChangeX() eq. met OnKillFocusX()
52
-OnChangeX() { UpdateData(TRUE); // control à var (m_x) CSliderCtrl* pSliderX = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_X); pSliderX -> SetPos(m_x); } -OnChangeY() à idem + moet nog ergens UpdateData(FALSE) ergens zetten à want als men pendikte verandert en slider verschuift, dan is pendikte terug 1… en dit mag niet!!
11 Eigenschappen vensters en tabbladen 11.1 De Toepassing Controls2 map Controls à Controls2 à alle verwijzingen ivm dialoogvenster verwijderen -FileView verwijder
OptionsDlg.h OptionsDlg.cpp
-ResourceView IDD_DIALOG1 verwijderen -CControlsDoc-klasse #include “OptionsDlg.h” OnToolsOptions() à body verwijderen(alles wat je zelf hebt bijgeschreven) -Menu-optie View Resource Symbols IDC_... IDC_... Verwijderen -Windows Verkenner files OptionsDlg.h OptionsDlg.cpp -Start ClassWizard COptionsDlg –class
verwijderen
REMOVE
-File, Close WorkSpace -File, Open WorkSpace
53
-CControlsDoc à CRechthoek rechthoek; à OnNewDocument(); à Serialize(); à OnToolsOptions(); -CControlView à OnDraw(); -Tools Optionsàeigenschappenvenster(propertysheet) -Resource View Dialog à Property Page 1 = dialogbox Style: Child Border: Thin à IDD_PAGE1 à editbox IDC_PENDIKTE à spin IDC_SPIN_PENDIKTE -Klasse CPAGE1: public CPropertyPage - int m_pendikte; - OnInitDialog() à Property Page 2 Style: Child Border: Thin à IDD_PAGE2 à editbox IDC_X à slider IDC_SLIDER_X à editbox IDC_Y à slider IDC_SLIDER_Y -Klasse CPAGE2: public CPropertyPage - int m_x; - int m_y; - OnInitDialog() - OnHScroll() à slider beweegt, editbox verandert - OnKillFocusX() à als editbox wordt aangepast, verandert slider - OnKillFocusY() -EERST: -DAARNA:
tabbladen tekenen en klasse definiëren(mbv ClassWizard) afgeleid van CPropertyPage (niet vergeten van OK en CANCEL-button weg te doen eigenschappenvenster-klasse definiëren mbv ClassWizard àCPropSheet: public CPropertySheet datamembers: 54
CPage1 m_page1; CPage2 m_page2; àconstructors AddPage(&m_page1); AddPage(&m_page2); -OnToolsOptions() CPropSheet propSheet(“Titel”); if (propSheet.DoModal() == IDOK){ rechthoek.Set_Rechthoek(propSheet.m_page2.m_x, propSheet.m_page2.m_y, propSheet.m_page1.m_pendikte); SetModifiedFlag(); UpdateAllViews(NULL); } Oefening 1 ipv PropertySheet met tabbladen à Wizard -Voor DoModal() SetWizardMode() -OnSetActive() (welke knoppen staan bij welke stap) -OnWizardNext (Foutcontrole) -OnWizardBack (Foutcontrole) Oefening 2 (herhalingsoefening) SDI-applicatie Vierkant Teken Vierkant (eigenschappenvenster met 3 tabbladen) e 1 tabblad Bovenhoek X en Y (Spin) e 2 tabblad Kleur Rood Groen en Blauw (Slider) e 3 tabblad Zijde van het vierkant (listbox) OK à vierkant bijgetekend +Serialize
55
Oefening 3 SDI – applicatie : Infobalie menu: gegevens Invoer Tonen op naam op postcode Zoeken Gegevens:Invoeren Wizard met 3 stappen Stap 1 Stap 2 Stap 3 naam postcode e-mailadres Bij OK worden gegevens bijgevoegd onderaan een lijst Gegevens: Tonen: op naam lijst wordt getoond op naam Gegevens: Tonen : op postcode lijst wordt getoond op postcode Gegevens Zoeken: lijst doorlopen
Intermezzo: Wanneer je een class wil verwijderen moet je 1. verwijder header + cpp 2. afsluiten workspace 3. verwijder alle header en cpp in verkenner 4. open workspace 5. classwizard -> remove 6. clean 7. iedereen is gelukkig
56