- Trennung zwischen Dokument und View
- Der AppWizard
- Der ClassWizard
- Programmieren mit der MFC
- IDE und Editor
- Dies und das
- ODBC-Einbindung (unter Thema Datenbanken)
- Literatur
Visual C++ besitzt zwei Codegeneratoren: den AppWizard und den ClassWizard. AppWizard ist derjenige, der nach File-New- Projects - MFC-AppWizard gestartet wird. Er erstellt das Grundgerüst, nachdem er erfragt hat, ob es eine SDI oder MDI ist.
Trennung zwischen Dokument und View
Das Dokument hält die Daten, während ein View eine Sicht der Daten realisiert. Die Kommunikation findet vom View zum Dokument durch den Aufruf der Funktion GetDocument statt, die einen Zeiger auf die Dokumentklasse liefert. Ein Dokument kann eine Änderung in den Daten durch die Funktion UpdateAllViews auslösen. Ein View erhält eine solche Information durch die Member-Funktion OnUpdate.Auf der Document-View-Architektur setzen verschiedene durch den AppWizard erzeugte Elemente auf.
- Print- und Printpreview
- FormView: das Verwenden eines Forms als Hauptfenster.
- OLE
- MAPI
Der AppWizard
Der AppWizard erstellt für eine normale SDI-Anwendung die vier Klassen:
CxxxApp | public CWinApp |
CxxxDoc | public CDocument |
CxxxView | public CView |
CMainFrame | public CFrameWin |
Er erstellt eine Instanz namens theApp von CxxxApp.
Soll in einer SDI-Anwendung das Hauptfenster ein Formular sein, also mit Steuerungselementen versehen sein, wird im letzten Fenster des AppWizard statt CView die Einstellung CFormView verwendet.
Der ClassWizard
Das Einfügen einer neuen Nachricht erfolgt am einfachsten über View - ClassWizard. Hier wird die Klasse ausgewählt. Anschließend wird unter Message ausgewählt, welches Ereignis bearbeitet werden soll. Der Wizard fügt die Funktion im Header in der Klassendefinition ein, erstellt die Funktionen und trägt die Map nach.Auf diese Weise läßt sich die Funktion OnCreate als Reaktion von WM_CREATE leicht erzeugen.
Erzeugen einer Dialogbox
Zunächst wird im Ressouce-Editor die Box entworfen und eine ID zugeordnet. Die ID sollte nicht nach dem Start des ClassWizard noch geändert werden. Der Wizard wird durch einen Doppelklick auf die Dialogbox erreicht. Es wird der Name der Klasse festgelegt, daraus erstellt der Wizard bereits cpp- und h-Datei.Sollen Elemente in die Dialogbox gesetzt werden, erfolgt dies ebenfalls zunächst im Ressource-Editor. Anschließend kann im Wizard auf die Lasche Member Variables umgeschaltet werden. Dort findet sich in der Listbox eine Liste der Elemente. Daraus wählt man eines aus, wählt den Button Add Variables und kann im folgenden Dialog den Namen der Variablen festlegen. Unter Category kann gewählt werden, ob es eine Control-Variable sein soll (beispielsweise ein CEdit für ein Eingabefeld oder ein Value, in letztem Fall also ein CString.
Von Radio-Buttons lassen sich keine Member-Variablen erzeugen. Um dennoch die Elemente manipulieren zu können, verwendet man die GetDialogItem-Funktion, die zum Setzen der Markierung folgenden wenig eleganten Code ergibt:
((CButton *)(GetDialogItem(RB_NEW)))->SetCheck(true); |
Programmieren mit der MFC
Die Message Map
Die Ereignisverteilung erfolgt über eine Message Map. In der Klasse des Fensters erfolgt der Aufruf DECLARE_MESSAGE_MAP(). Es folgt
BEGIN_MESSAGE_MAP(MeineKlasse, MFCKlasse) ON_COMMAND(WM_XXXXX, UserFunktion) END_MESSAGE_MAP() |
Normalerweise wird diese MAP vom ClassWizard erzeugt.
MDI: Multi Document Interface
Das Framewindow
Der Frame wird von CMDIFrameWnd abgeleitet.
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_COMMAND(IDM_BOUNCE, OnBounce) ON_COMMAND(IDM_HELLO, OnHello) //}}AFX_MSG_MAP END_MESSAGE_MAP() |
Über das Menü wird das Erzeugen der Kindfenster gesteuert. Damit ist auch schon die wichtigste Aufgabe des Rahmens erledigt.
void CMainFrame::OnBounce() { CBounceWnd *pBounceWnd = new CBounceWnd; if (!pBounceWnd->Create(_T("Bounce"), WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, rectDefault, this)) return; } void CMainFrame::OnHello() { CHelloWnd *pHelloWnd = new CHelloWnd; if (!pHelloWnd->Create(_T("Hello"), WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, rectDefault, this)) return; } |
Der PostNcDestroy-Behandlung wird das Objekt löschen, wenn es zerstört wird.
Das Childwindow
Ein Childwindow leitet sich von der Klasse CMDIChildWnd ab. Ansonsten verhält es sich weitgehend wie ein Standardfenster.Menübehandlung
Um Menüpunkte zu enablen oder mit einem Haken zu versehen, benutzt man am einfachsten den ClassWizard.Im ClassWizard wählt man die ID des Menüpunktes. Es erscheinen in der nebenstehenden Dialogbox die Einträge COMMAND und UPDATE_COMMAND_UI. Letzterer wird doppelt angeklickt. Es erscheint das Angebot, eine Funktion zu erstellen mit dem Namen OnUpdateXXXXX. Die entstehende Funktion hat etwa folgendes Aussehen:
void xxxx::OnUpdateXXXXX(CCmdUI *pCmdUI) { pCmdUI->Enable(Bedingung); // schaltet das Item grau oder enable pCmdUI->SetCheck(Bedingung); // setzt bzw. löscht einen Haken } |
Dateiauswahl Dialog
Der Dateiauswahldialog wird in der Klasse CFileDialog gekapselt. Der minimale Konstruktur benötigt lediglich ein Flag, das angibt, ob es ein Open- oder SaveAs-Dialog ist. Beispiel:
CFileDialog DiaOpen(true); CFileDialog DiaSaveAs(false); |
Der Konstruktor lautet vollständig:
CFileDialog( BOOL, // Oeffnen (true) oder Schliessen (false) LPCTSTR, // Default Extension =NULL LPCTSTR, // Initial FileName =NULL DWORD, // Flags wie OPENFILENAME LPCTSTR, // Stringpaare als Filter CWnd *) // Parentwindow |
CFileDialog hat eine Membervariable m_ofn vom Typ OPENFILENAME.
Wichtige Memberfunktionen sind:
- int DoModal()
- startet den Dialog
- CString GetPathName()
- ermittelt den Dateinamen inklusive Pfad
- CString GetFileName()
- ermittelt den reinen Dateinamen (ohne Pfad)
- CString GetFileExt()
- ermittelt die Extension der Datei
Das ListView-Element in der Detaill-Ansicht
Das List-View ist unter MFC vom Typ CListCtrl. Wie jedes Kontrollelement kann es durch Create erzeugt werden oder im Ressource-Editor als Dialogelement.Es kann in der OnCreate-Funktion des Elternfensters angelegt werden durch Aufruf der Memberfunktion Create. Etwa:
Liste.Create(WS_VISIBLE|WS_BORDER|LVS_REPORT, CRect(20,20,120,150),this,LIST_ID); |
In einer Dialogbox ist ein solcher Create nicht erforderlich, da die Liste durch die Ressource beschrieben ist und im Zuge des Aufbaus der Dialogbox entsteht.
Spalten
Das Anlegen der Spalten erfolgt recht simpel durch den Aufruf der Memberfunktion
Liste.InsertColumn(i, char *Titel); |
Wenn Spalten gelöscht werden sollen, betrifft das meist alle Spalten. Dies erfolgt schnell und elegant durch
while (Liste.DeleteColumn(0)); |
Dabei wird immer die erste Spalte gelöscht, bis als Fehlermeldung eine 0 zurückgegeben wird.
Zeilen
Für jede Zeile wird ein Item dem ListView-Element hinzugefügt.
LVITEM Item = {0}; Item.mask = LVIF_TEXT; Item.iItem = 0; // immer oben einhaengen Item.pszText = TextPointer; Liste.InsertItem(&Item); |
Dadurch wird zunächst die linke Spalte gefüllt. Die anderen Spalten sind nur SubItems, die einfach mit
Liste.SetItemText(iItem, iSubItem, TextPointer); |
Dabei ist
iItem | die Zeilennummer |
iSubItem | die Spaltennummer |
TextPointer | der angezeigte Text |
Um alle Zeilen zu löschen, kann
Liste.DeleteAllItems(); |
IDE und Editor
Strg-F2 setzt eine Bookmark an der aktuellen Stelle, die man später mit F2 (vorwärts) und Shift-F2 (zurück) anspringen kann. Bookmarks bleiben nach erneutem Laden nicht erhalten.Dies und das
CWnd hat das HWND in seiner Member-Variablen m_hWnd.
ODBC-Einbindung findet sich unter dem Thema Datenbanken
Literatur
- Kinzler, Andreas: Klassenarbeit - MFC-Programmierung. c't 1-3/1998.
- Fleischhauer, Dr. Cristian: Visual C++ 5.0 - Das große Buch. Data Becker, Düsseldorf, 1997.
- Michael Kofler: Visual Basic 6. Programmiertechniken, Datenbanken, Internet