1. Markieren Sie im Dialog-Editor die zu ändernde Schaltfläche. Klicken Sie mit der rechten Maustaste, und wählen Sie Eigenschaften aus dem Kontextmenü. Ändern Sie den Wert im Feld Titel.
2. Mit dem Anwendungs-Assistenten erstellen Sie das Gerüst Ihrer Anwendung basierend auf dem Typ der Anwendung und der geplanten Funktionalität. Das Gerüst unterstützt dann die in den Dialogfeldern des Assistenten spezifizierte Funktionalität.
3. Mit dem Klassen-Assistenten erzeugen Sie eine Funktion und verbinden sie mit einem Objekt, das eine bestimmte Windows-Nachricht behandelt. Der Klassen-Assistent erzeugt die Funktion und öffnet die zugehörige Quelldatei bereits an der richtigen Stelle, so daß Sie sofort mit der Eingabe des eigenen Codes beginnen können.
Führen Sie die folgenden Schritte aus:
1. Gehen Sie im Arbeitsbereich auf die Registerkarte Ressourcen.
2. Erweitern Sie den Zweig Dialog
, und doppelklicken Sie auf das Dialogfeld
IDD_ABOUTBOX
. Dieses Dialogfeld wird daraufhin im Editor des Visual Studios zur
Bearbeitung angezeigt.
3. Klicken Sie in der Werkzeugleiste auf das Symbol für Schaltfläche.
4. Klicken und ziehen Sie die Maus an die Stelle im Dialogfeld, wo Sie die Schaltfläche plazieren möchten.
5. Öffnen Sie den Eigenschaftsdialog für die neue Schaltfläche. Ändern Sie die ID und den Titel, um den Text auf der Schaltfläche festzulegen. Schließen Sie das Eigenschaftsdialogfeld.
6. Öffnen Sie den Klassen-Assistenten, und fügen Sie eine neue Funktion für die
Klicknachricht (BN_CLICKED
) für Ihre neue Schaltfläche hinzu.
7. Klicken Sie im Klassen-Assistenten auf die Schaltfläche Code bearbeiten. Der Klassen-Assistent öffnet daraufhin die Quelldatei und zeigt die neue Funktion zur Bearbeitung an.
8. Fügen Sie die Funktion MessageBox
hinzu, um die Nachricht für den Benutzer auszugeben.
9. Kompilieren und starten Sie die Anwendung, um die neue Schaltfläche zu testen.
1. Indem Sie die Tabulator-Reihenfolge der Steuerelemente in Ihrem Anwendungsfenster festlegen, können Sie bestimmen, auf welchem Weg der Benutzer durch das Anwendungsfenster navigiert. Wenn der Benutzer mit der Tastatur arbeitet, kann er mit der <Tab>-Taste von einem Steuerelement zum nächsten wechseln und über die Zugriffstasten ein bestimmtes Steuerelement direkt anspringen. Die Tabulator-Reihenfolge bietet dem Benutzer ein einheitliches und vorhersagbares Verhalten, wenn er im Anwendungsfenster navigiert.
2. Wenn man eine Zugriffstaste für ein Textfeld vorsieht und dann sicherstellt, daß sich das Textfeld unmittelbar vor dem zugeordneten Eingabefeld befindet, kann der Benutzer die Zugriffstaste des Textfelds wählen, um direkt zum Eingabefeld zu gelangen.
3. Die eindeutigen Objekt-IDs für die beiden statischen Textfelder sind erforderlich, da diese beiden Steuerelemente in Abhängigkeit vom Zustand der Kontrollkästchen, die bestimmte Gruppen von Steuerelementen aktivieren oder deaktivieren, manipuliert werden sollen.
4. Wenn der Benutzer den Wert des Steuerelements auf dem Bildschirm ändert, ist
die Funktion UpdateData
mit dem Argument TRUE
aufzurufen, um die Werte aus
den Steuerelementen im Fenster in die Variablen, die mit diesen Steuerelementen
verbunden sind, zu übertragen. Ruft man UpdateData
nicht auf, spiegeln die Variablen
nicht die aktuellen Änderungen wider, die der Benutzer in den Steuerelementen
auf dem Bildschirm vorgenommen hat.
1. Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Klicknachricht der
Schaltfläche Standardnachricht (IDC_DFLTMSG
) hinzu. In die Funktion schreiben
Sie den Code gemäß Listing B.1.
Listing B.1: Tag2Dlg.cpp - Dieser Code plaziert eine Standardnachricht im Eingabefeld.
1: void CTag2Dlg::OnDfltmsg()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Nachricht auf Standardnachricht setzen
10: m_strMessage = "Nachricht hier eingeben";
11:
12: // Bildschirm aktualisieren
13: UpdateData(FALSE);
14:
15: ///////////////////////
16: // EIGENER CODE, ENDE
17: ///////////////////////
18: }
2. Fügen Sie Funktionen für die Kontrollkästchen Programmaktion aktivieren und Programmaktion zeigen hinzu. In diese Funktionen übernehmen Sie den Code aus Listing B.2.
Listing B.2: Tag2Dlg.cpp - Die zur Ausführung von Programmen relevanten Steuerelemente werden mit diesem Code aktiviert/deaktiviert und angezeigt/ausgeblendet.
1: void CTag2Dlg::OnCkenblpgm()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuelle Werte vom Bildschirm holen
10: UpdateData(TRUE);
11:
12: // Kontrollkästchen 'Programmaktion aktivieren' eingeschaltet?
13: if (m_bEnablePgm == TRUE)
14: {
15: // Ja, dann alle Steuerelemente aktivieren, die
16: // für den Start eines Programms relevant sind.
17: GetDlgItem(IDC_PROGTORUN)->EnableWindow(TRUE);
18: GetDlgItem(IDC_RUNPGM)->EnableWindow(TRUE);
19: GetDlgItem(IDC_STATICPGM)->EnableWindow(TRUE);
20: }
21: else
22: {
23: // Nein, dann alle Steuerelemente deaktivieren, die
24: // für den Start eines Programms relevant sind.
25: GetDlgItem(IDC_PROGTORUN)->EnableWindow(FALSE);
26: GetDlgItem(IDC_RUNPGM)->EnableWindow(FALSE);
27: GetDlgItem(IDC_STATICPGM)->EnableWindow(FALSE);
28: }
29:
30: ///////////////////////
31: // EIGENER CODE, ENDE
32: ///////////////////////
33: }
34:
35: void CTag2Dlg::OnCkshwpgm()
36: {
37: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
38:
39: ///////////////////////
40: // EIGENER CODE, ANFANG
41: ///////////////////////
42:
43: // Aktuelle Werte vom Bildschirm holen
44: UpdateData(TRUE);
45:
46: // Kontrollkästchen 'Programmaktion zeigen' eingeschaltet?
47: if (m_bShowPgm == TRUE)
48: {
49: // Ja, dann alle Steuerelemente anzeigen, die
50: // für den Start eines Programms relevant sind.
51: GetDlgItem(IDC_PROGTORUN)->ShowWindow(TRUE);
52: GetDlgItem(IDC_RUNPGM)->ShowWindow(TRUE);
53: GetDlgItem(IDC_STATICPGM)->ShowWindow(TRUE);
54: }
55: else
56: {
57: // Nein, dann alle Steuerelemente ausblenden, die
58: // für den Start eines Programms relevant sind.
59: GetDlgItem(IDC_PROGTORUN)->ShowWindow(FALSE);
60: GetDlgItem(IDC_RUNPGM)->ShowWindow(FALSE);
61: GetDlgItem(IDC_STATICPGM)->ShowWindow(FALSE);
62: }
63:
64: ///////////////////////
65: // EIGENER CODE, ENDE
66: ///////////////////////
67: }
3. Modifizieren Sie die Funktion OnRunpgm
gemäß Listing B.3.
Listing B.3: Tag2Dlg.cpp - Dieser Code startet das Programm, dessen Name der Benutzer in das Kombinationsfeld Programm starten eingibt.
1: void CTag2Dlg::OnRunpgm()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuelle Werte vom Bildschirm holen
10: UpdateData(TRUE);
11:
12: // Lokale Variable zur Aufnahme des Programmnamens deklarieren
13: CString strPgmName;
14:
15: // Programmname in die lokale Variable kopieren
16: strPgmName = m_strProgToRun;
17:
18: // Programmname in Großbuchstaben umwandeln
19: strPgmName.MakeUpper();
20:
21: // Programm Paint gewählt?
22: if (strPgmName == "PAINT")
23: // Ja, Paint starten
24: WinExec("pbrush.exe", SW_SHOW);
25:
26: // Editor (Notepad) gewählt?
27: if (strPgmName == "EDITOR")
28: // Ja, Editor starten
29: WinExec("notepad.exe", SW_SHOW);
30:
31: // Solitär gewählt?
32: if (strPgmName == "SOLITÄR")
33: // Ja, Solitär starten
34: WinExec("sol.exe", SW_SHOW);
35:
36: // Programm zu eingegebenem Namen in das Kombinationsfeld starten
37: if ((strPgmName != "PAINT") && (strPgmName != "EDITOR") &&
38: (strPgmName != "SOLITÄR"))
39: // Ja, eingegebenen Programmnamen aufrufen
40: WinExec(strPgmName, SW_SHOW);
41:
42: ///////////////////////
43: // EIGENER CODE, ENDE
44: ///////////////////////
45: }
1. WM_LBUTTONDOWN
, WM_LBUTTONUP
, WM_LBUTTONDBLCLK
, WM_RBUTTONDOWN
,
WM_RBUTTONUP
, WM_RBUTTONDBLCLK
, WM_MOUSEMOVE
und WM_MOUSEWHEEL
.
2. Man kann die Flags, die an die Funktion OnMouseMove
übergeben werden, mit dem
Flag MK_LBUTTON
wie folgt maskieren:
((nFlags & MK_LBUTTON) == MK_LBUTTON)
3. Geben Sie in der Behandlungsroutine OnSetCursor
den Wert TRUE
zurück. Damit
verhindern Sie, daß die Funktion OnSetCursor
der Basisklasse aufgerufen wird.
1. Fügen Sie eine Funktion für die Nachricht WM_RBUTTONDOWN
hinzu, und schreiben
Sie in die Funktion den Code aus Listing B.4.
Listing B.4: MausDlg.cpp - Die Funktion OnRButtonDown
1: void CMausDlg::OnRButtonDown(UINT nFlags, CPoint point)
2: {
3: // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen
und/oder Standard aufrufen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuellen Punkt als Startpunkt setzen
10: m_iPrevX = point.x;
11: m_iPrevY = point.y;
12:
13: ///////////////////////
14: // EIGENER CODE, ENDE
15: ///////////////////////
16:
17: CDialog::OnRButtonDown(nFlags, point);
18: }
Erweitern Sie die Funktion OnMouseMove
gemäß Listing B.5.
Listing B.5: MausDlg.cpp - Die modifizierte Funktion OnMouseMove
1: void CMausDlg::OnMouseMove(UINT nFlags, CPoint point)
2: {
3: // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen
und/oder Standard aufrufen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Linke Maustaste gedrückt?
10: if ((nFlags & MK_LBUTTON) == MK_LBUTTON)
11: {
12: // Gerätekontext holen
13: CClientDC dc(this);
14:
15: // Neuen Stift erzeugen
16: CPen lpen(PS_SOLID, 16, RGB(255, 0, 0));
17:
18: // Den neuen Stift verwenden
19: dc.SelectObject(&lpen);
20:
21: // Linie vom letzten zum aktuellen Punkt zeichnen
22: dc.MoveTo(m_iPrevX, m_iPrevY);
23: dc.LineTo(point.x, point.y);
24:
25: // Aktuellen Punkt als letzten Punkt speichern
26: m_iPrevX = point.x;
27: m_iPrevY = point.y;
28: }
29:
30: // Rechte Maustaste gedrückt?
31: if ((nFlags & MK_RBUTTON) == MK_RBUTTON)
32: {
33: // Gerätekontext holen
34: CClientDC rdc(this);
35:
36: // Neuen Stift erzeugen
37: CPen rpen(PS_SOLID, 16, RGB(0, 0, 255));
38:
39: // Den neuen Stift verwenden
40: rdc.SelectObject(&rpen);
41:
42: // Linie vom letzten zum aktuellen Punkt zeichnen
43: rdc.MoveTo(m_iPrevX, m_iPrevY);
44: rdc.LineTo(point.x, point.y);
45:
46: // Aktuellen Punkt als letzten Punkt speichern
47: m_iPrevX = point.x;
48: m_iPrevY = point.y;
49: }
50:
51: ///////////////////////
52: // EIGENER CODE, ENDE
53: ///////////////////////
54:
55: CDialog::OnMouseMove(nFlags, point);
56: }
2. Die modifizierte Funktion OnKeyDown
kann etwa folgendermaßen aussehen:
void CMausDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen und/
oder Standard aufrufen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
char lsChar; // Zeichen der gedrückten Taste
HCURSOR lhCursor; // Handle zum anzuzeigenden Cursor
// Code der gedrückten Taste in Zeichen umwandeln
lsChar = char(nChar);
// Ist Zeichen ein "A"
if (lsChar == 'A')
{
// Pfeilcursor laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "B"
if (lsChar == 'B')
{
// Balkencursor laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "C"
if (lsChar == 'C')
{
// Sanduhrzeiger laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_WAIT);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "D"
if (lsChar == 'D')
{
// Fadenkreuz-Cursor laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_CROSS);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "E"
if (lsChar == 'E')
{
// Cursor mit Pfeil nach oben laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_UPARROW);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "F"
if (lsChar == 'F')
{
// Cursor zur Größenveränderung laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEALL);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "G"
if (lsChar == 'G')
{
// Cursor zur Größenveränderung, von Nordwest nach Südost, laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "H"
if (lsChar == 'H')
{
// Cursor zur Größenveränderung, von Nordost nach Südwest, laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENESW);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "I"
if (lsChar == 'I')
{
// Cursor zur Größenveränderung, von West nach Ost, laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "J"
if (lsChar == 'J')
{
// Cursor zur Größenveränderung, von Nord nach Süd, laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENS);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
if (lsChar == 'K')
{
// "Kein" Cursor laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_NO);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
if (lsChar == 'L')
{
// Cursor beim Starten der Anwendung (Pfeil und Sanduhr) laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_APPSTARTING);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
if (lsChar == 'M')
{
// Hilfe-Cursor (Pfeil und Fragezeichen) laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_HELP);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
}
// Ist Zeichen ein "X"
if (lsChar == 'X')
{
// Pfeilcursor laden
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
// Cursorflag setzen
m_bCursor = TRUE;
// Bildschirmcursor setzen
SetCursor(lhCursor);
// Anwendung beenden
OnOK();
}
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
1. Durch die Definition der beiden IDs sind diese als Konstanten durch die gesamte Anwendung hindurch verfügbar.
2. Fügen Sie sie als #define
-Konstanten in die Header-Datei der Klasse (TimerDlg.h
)
wie folgt ein:
///////////////////////////////////////////////////////////////////////
CTimerDlg Dialogfeld
#define ID_CLOCK_TIMER 1
#define ID_COUNT_TIMER 2
class CTimerDlg : public CDialog
{
.
.
.
3. Anhand der Timer-ID läßt sich bestimmen, welcher Timer das Ereignis ausgelöst hat.
Um das Intervall zu ändern, mit dem ein Timer läuft, müssen Sie zuerst den Timer stoppen und dann erneut starten, wie es aus Listing B.6 hervorgeht.
Listing B.6: Die überarbeiteten Funktionen OnStarttime und OnStoptimer
1: void CTimerDlg::OnStarttime()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Variablen aktualisieren
10: UpdateData(TRUE);
11:
12: // Zähler aktualisieren
13: m_iCount = 0;
14: // Zähler für Anzeige formatieren
15: m_sCount.Format("%d", m_iCount);
16:
17: // Dialogfeld aktualisieren
18: UpdateData(FALSE);
19: // Timer starten
20: SetTimer(ID_COUNT_TIMER, m_iInterval, NULL);
21:
22: // Uhren-Timer anhalten
23: KillTimer(ID_CLOCK_TIMER);
24: // Uhren-Timer mit dem Intervall des Zählers neu starten
25: SetTimer(ID_CLOCK_TIMER, m_iInterval, NULL);
26:
27: // Schaltfläche Timer anhalten aktivieren
28: m_cStopTime.EnableWindow(TRUE);
29: // Schaltfläche Timer starten deaktivieren
30: m_cStartTime.EnableWindow(FALSE);
31:
32: ///////////////////////
33: // EIGENER CODE, ENDE
34: ///////////////////////
35: }
36:
37: void CTimerDlg::OnStoptimer()
38: {
39: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
40:
41: ///////////////////////
42: // EIGENER CODE, ANFANG
43: ///////////////////////
44:
45: // Timer anhalten
46: KillTimer(ID_COUNT_TIMER);
47:
48: // Uhren-Timer anhalten
49: KillTimer(ID_CLOCK_TIMER);
50: // Uhren-Timer mit Intervall 1 Sekunde neu starten
51: SetTimer(ID_CLOCK_TIMER, 1000, NULL);
52:
53: // Schaltfläche Timer anhalten deaktivieren
54: m_cStopTime.EnableWindow(FALSE);
55: // Schaltfläche Timer starten aktivieren
56: m_cStartTime.EnableWindow(TRUE);
57:
58: ///////////////////////
59: // EIGENER CODE, ENDE
60: ///////////////////////
61: }
2. Als MFC-Klassen sind die folgenden allgemeinen Windows-Dialogfelder definiert:
3. Ein modales Dialogfeld stoppt alle Programmabläufe in der Anwendung, bis der Benutzer auf das Dialogfeld antwortet. Ein nichtmodales Dialogfeld gestattet dem Benutzer, mit der übrigen Anwendung weiterzuarbeiten, während das Dialogfeld geöffnet bleibt und Eingaben entgegennehmen kann.
4. In der Variablendeklaration der Klasseninstanz übergeben Sie FALSE
statt TRUE
.
Damit sieht die Variablendeklaration folgendermaßen aus:
CFileDialog m_ldFile(FALSE);
5. Im benutzerdefinierten Dialogfeld ist lediglich die Funktion UpdateData
aufzurufen,
bevor das Dialogfeld geschlossen wird. Da Sie die Schaltflächen OK und Abbrechen
nicht aus dem Dialogfeld gelöscht haben, führt die Schaltfläche OK automatisch
diese Funktion aus.
1. Modifizieren Sie die Funktion OnFileopen
wie folgt:
void CDialogeDlg::OnFileopen()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
CFileDialog m_ldFile(TRUE);
// Dialogfeld Öffnen zeigen und Ergebnis auffangen
if (m_ldFile.DoModal() == IDOK)
{
// Gewählten Dateinamen ermitteln
m_sResults = m_ldFile.GetPathName();
// Dialogfeld aktualisieren
UpdateData(FALSE);
}
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
Die Funktion GetPathName
gibt den Pfad und Dateinamen zurück, so daß bei Änderung
des Funktionsaufrufs von GetFileName
in GetPathName
der Pfad zusammen
mit dem Dateinamen in der Anzeige erscheint.
2. Führen Sie die folgenden Schritte aus:
1. Fügen Sie über den Klassen-Assistenten eine Member-Variable in die Klasse
CMsgDlg
ein. Legen Sie den Variablentyp als int
, den Namen mit m_iYesNo
und den Zugriff als Public
fest.
2. Gehen Sie auf die Registerkarte Ressourcen, und öffnen Sie das benutzerdefinierte
Dialogfeld zur Bearbeitung. Ziehen Sie eine Schaltfläche auf das Dialogfeld,
tragen Sie IDC_YESNO
als ID und &Ja oder Nein
als Titel ein.
3. Fügen Sie mit dem Klassen-Assistenten eine Funktion für die neue Schaltfläche hinzu, und schreiben Sie in diese Funktion den folgenden Code:
void CMsgDlg::OnYesno()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Benutzer fragen
m_iYesNo = MessageBox("Ja oder Nein wählen",
"Ja oder Nein",
MB_YESNO);
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
4. Nehmen Sie in das Hauptdialogfeld eine Schaltfläche mit der ID IDC_YESNO
und dem Titel Ja oder &Nein
auf.
5. Fügen Sie mit dem Klassen-Assistenten eine Funktion für die neue Schaltfläche hinzu, und schreiben Sie den folgenden Code in diese Funktion:
void CDialogeDlg::OnYesno()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Was hat Benutzer geantwortet?
switch (m_dMsgDlg.m_iYesNo)
{
case IDYES: // Mit Ja geantwortet?
m_sResults = "Ja!";
break;
case IDNO: // Mit Nein geantwortet?
m_sResults = "Nein!";
break;
}
// Dialogfeld aktualisieren
UpdateData(FALSE);
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
2. Öffnen Sie im Dialog-Editor den Eigenschaftsdialog für das Fenster, und wählen Sie das Menü aus der Dropdown-Liste der Menüs aus.
3. Die Dialogklasse für das Fenster, in dem das Menü erscheint.
4. Durch das Ereignis WM_CONTEXTMENU
.
1. Führen Sie die folgenden Schritte aus:
1. Nehmen Sie eine Schaltfläche in das Dialogfeld auf. Tragen Sie für diese
Schaltfläche die ID IDC_HELLO
und den Titel &Hello
ein.
2. Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Schaltfläche hinzu.
Verwenden Sie OnHello
als Funktionsname.
2. Führen Sie die folgenden Schritte aus:
1. Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Nachricht
WM_CONTEXTMENU
in Ihr Dialogfeld ein.
2. Schreiben Sie den folgenden Code in die Funktion:
void CMenusDlg:: OnContextMenu(CWnd* pWnd, CPoint point)
{
// TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Lokale Variablen deklarieren
CMenu *m_lMenu; // Zeiger auf Menü
CPoint m_pPoint; // Kopie der Mausposition
// Mausposition in lokale Variable kopieren
m_pPoint = point;
// Position in Bildschirmkoordinaten konvertieren
ClientToScreen(&m_pPoint);
// Zeiger auf Fenstermenü holen
m_lMenu = GetMenu();
// Zeiger auf zweites Untermenü holen
m_lMenu = m_lMenu->GetSubMenu(1);
// Popup-Menü anzeigen
m_lMenu->TrackPopupMenu(TPM_CENTERALIGN + TPM_LEFTBUTTON,
m_pPoint.x, m_pPoint.y, this, NULL);
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
1. Übergeben Sie für das Argument bUnderline
an die Funktion CreateFont
den
Wert 1
.
2. Übergeben Sie für das Argument nEscapement
an die Funktion CreateFont
den
Wert 1800
.
3. Diese Funktion wird für jede im System verfügbare Schrift je einmal aufgerufen,
außer wenn die Callback-Funktion den Wert 0
zurückgibt und die Auflistung der
Schriften stoppt.
1. Nehmen Sie das Kontrollkästchen in das Dialogfeld auf. Legen Sie für die Eigenschaft
ID
den Wert IDC_CBUSETEXT
und als Titel Text &verwenden
fest.
Weisen Sie dem Steuerelement mit dem Klassen-Assistenten eine Variable zu. Legen
Sie den Variablentyp als BOOL
und den Namen mit m_bUseText
fest.
Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Nachricht
BN_CLICKED
des Kontrollkästchens hinzu. In die Funktion schreiben Sie den folgenden
Code:
void CTag7Dlg::OnCbusetext()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Variablen mit den Steuerelementen des Dialogfelds aktualisieren
UpdateData(TRUE);
// Schriftname für Schriftprobe verwenden?
if (!m_bUseText)
// Schriftname verwenden
m_strDisplayText = m_strFontName;
else
// Eingegebenen Text verwenden
m_strDisplayText = m_strSampText;
// Dialogfeld mit Variablen aktualisieren
UpdateData(FALSE);
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
Um das Kontrollkästchen zu initialisieren, modifizieren Sie die Funktion OnInitDialog
wie folgt:
BOOL CTag7Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
.
.
.
// ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Listenfeld für Schriften füllen
FillFontList();
// Einzugebenden Text initialisieren
m_strSampText = "Testen";
// Text in Feld für Schriftbeispiel kopieren
m_strDisplayText = m_strSampText;
// Kontrollkästchen initialisieren
m_bUseText = TRUE;
// Dialogfeld aktualisieren
UpdateData(FALSE);
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll den
Fokus erhalten
}
Modifizieren Sie die Funktion OnSelchangeLfonts
wie folgt:
void CTag7Dlg::OnSelchangeLfonts()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Variablen mit Steuerelementen des Dialogfelds aktualisieren
UpdateData(TRUE);
// Schriftname für Schriftprobe verwenden?
if (!m_bUseText)
{
// Schriftname in Feld für Schriftbeispiel kopieren
m_strDisplayText = m_strFontName;
// Dialogfeld mit Variablen aktualisieren
UpdateData(FALSE);
}
// Schrift für Beispiel festlegen
SetMyFont();
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
Schließlich ändern Sie noch die Funktion OnChangeEsamptext
folgendermaßen ab:
void CTag7Dlg::OnChangeEsamptext()
{
// TODO: Wenn dies ein RICHEDIT-Steuerelement ist, sendet das
Steuerelement diese
// Benachrichtigung nicht, bevor Sie nicht die Funktion
CDialog::OnInitDialog()
// überschreiben und CRichEditCrtl().SetEventMask() aufrufen, wobei
// eine ODER-Operation mit dem Attribut ENM_CHANGE und der Maske erfolgt.
// TODO: Fügen Sie hier Ihren Code für die
Benachrichtigungsbehandlungsroutine des Steuerelements hinzu
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Variablen mit Steuerelementen des Dialogfelds aktualisieren
UpdateData(TRUE);
// Text für Schriftprobe verwenden?
if (m_bUseText)
{
// Aktuellen Text in Schriftprobe kopieren
m_strDisplayText = m_strSampText;
// Dialogfeld mit Variablen aktualisieren
UpdateData(FALSE);
}
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
2. Nehmen Sie das Kontrollkästchen in das Dialogfeld auf. Legen Sie für die Eigenschaft
ID
den Wert IDC_CBITALIC
und als Titel &Kursiv
fest.
Weisen Sie dem Steuerelement mit dem Klassen-Assistenten eine Variable zu. Legen
Sie den Variablentyp als BOOL
und den Namen mit m_bItalic
fest.
Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Nachricht
BN_CLICKED
des Kontrollkästchens hinzu. In die Funktion schreiben Sie den folgenden
Code:
void CTag7Dlg::OnCbitalic()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Variablen mit Steuerelementen des Dialogfelds aktualisieren
UpdateData(TRUE);
// Schrift für Beispiel festlegen
SetMyFont();
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
}
Ändern Sie die Funktion SetMyFont
entsprechend dem nachstehenden Listing ab:
void CTag7Dlg::SetMyFont()
{
CRect rRect; // Rechteck des Anzeigebereichs
int iHeight; // Höhe des Anzeigebereichs
int iItalic = 0; // Schrift kursiv ausgeben?
// Wurde eine Schrift ausgewählt?
if (m_strFontName != "")
{
// Abmessungen des Feldes für Schriftbeispiel ermitteln
m_ctlDisplayText.GetWindowRect(&rRect);
// Höhe des Feldes berechnen
iHeight = rRect.top - rRect.bottom;
// Sicherstellen, daß Höhe positiv
if (iHeight < 0)
iHeight = 0 - iHeight;
// Schrift kursiv ausgeben?
if (m_bItalic)
iItalic = 1;
// Zu verwendende Schrift erzeugen
m_fSampFont.CreateFont((iHeight - 5), 0, 0, 0,
FW_NORMAL, iItalic, 0, 0, DEFAULT_CHARSET,
OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH |
FF_DONTCARE, m_strFontName);
// Schrift für Anzeigefeld der Schriftprobe festlegen
m_ctlDisplayText.SetFont(&m_fSampFont);
}
}
5. Rufen Sie die Funktion Invalidate
auf diesem Fenster auf.
1. Öffnen Sie das zweite Dialogfeld im Dialog-Editor. Öffnen Sie das Eigenschaftsdialogfeld
für das Fenster. Gehen Sie auf die Registerkarte Formate. Wählen Sie
im Dropdown-Listenfeld Rand den Eintrag Größe ändern. Öffnen Sie den Klassen-Assistenten,
und fügen Sie eine Behandlungsroutine für die Nachricht
WM_SIZE
hinzu. In der eben erzeugten Funktion rufen Sie die Funktion Invalidate
auf, wie es Listing B.7 zeigt.
Listing B.7: Die Funktion OnSize
1: void CPaintDlg::OnSize(UINT nType, int cx, int cy)
2: {
3: CDialog::OnSize(nType, cx, cy);
4:
5: // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen
6: // Fenster neu zeichnen
7: Invalidate();
8:}
2. Gehen Sie im Arbeitsbereich auf die Registerkarte Ressourcen. Klicken Sie mit
der rechten Maustaste auf den obersten Ordner des Ressourcenbaumes. Aus dem
Kontextmenü wählen Sie den Befehl Einfügen. Im Dialogfeld Ressource einfügen
markieren Sie in der Liste Ressourcentyp den Eintrag Bitmap. Zeichnen Sie
ein Muster in das gerade erstellte Bitmap. Klicken Sie mit der rechten Maustaste
auf die Bitmap-ID im Arbeitsbereich. Öffnen Sie den Eigenschaftsdialog, und ändern
Sie die Objekt-ID in IDB_BITMAPBRUSH
. Öffnen Sie den Quellcode für die
Funktion DrawRegion
. Fügen Sie in diese Funktion die Zeilen 22 bis 24 und 105
bis 112 von Listing B.8 ein. Vergrößern Sie die Anzahl der Schleifen in der for
-
Anweisung in Zeile 39.
Listing B.8: Die Funktion DrawRegion
1: void CPaintDlg::DrawRegion(CPaintDC *pdc, int iColor, int iTool, int iShape)
2: {
3: // Stifte deklarieren und erzeugen
.
.
.
19: CBrush lVertBrush(HS_VERTICAL, m_crColors[iColor]);
20: CBrush lNullBrush(RGB(192, 192, 192));
21:
22: CBitmap lBitmap;
23: lBitmap.LoadBitmap(IDB_BITMAPBRUSH);
24: CBrush lBitmapBrush(&lBitmap);
25:
26: // Größe der Zeichenbereiche berechnen
27: CRect lRect;
28: GetClientRect(lRect);
.
.
.
37: int i;
38: // Schleife durch alle Pinsel und Stifte
39: for (i = 0; i < 8; i++)
40: {
41: switch (i)
42: {
.
.
.
103: pdc->SelectObject(&lVertBrush);
104: break;
105: case 7: // Null - Bitmap
106: // Position für diese Figur bestimmen.
107: lDrawRect.left = lDrawRect.left + liHorz;
108: lDrawRect.right = lDrawRect.left + liWidth;
109: // Passenden Stift und Pinsel auswählen
110: pdc->SelectObject(&lNullPen);
111: pdc->SelectObject(&lBitmapBrush);
112: break;
113: }
114: // Welches Werkzeug wird verwendet?
.
.
.
126: pdc->SelectObject(lOldBrush);
127: pdc->SelectObject(lOldPen);
128:}
1. Über die IDispatch
-Schnittstelle kann der Container die Methode Invoke
aufrufen.
An diese Methode übergibt er die DISPID derjenigen Steuerelementmethode,
die der Container aufrufen möchte.
2. Die Containeranwendung hat ihre eigene IDispatch
-Schnittstelle, über die das
Steuerelement Ereignisse auslösen kann.
3. Schalten Sie im zweiten Dialogfeld des MFC-Anwendungs-Assistenten das Kontrollkästchen ActiveX-Steuerelemente ein.
4. Visual C++ erzeugt C++-Klassen, die die Funktionalität des Steuerelements verkapseln.
5. Ältere Steuerelemente liefern möglicherweise nicht die Informationen, die Visual C++ braucht, um C++-Klassen zu generieren und damit die Funktionalität des Steuerelements zu verkapseln.
Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Nachricht DblClick
des
Grid-Steuerelements (IDC_MSFGRID
) hinzu. In die Funktion schreiben Sie den folgenden
Code:
void CActiveXDlg::OnDblClickMsfgrid()
{
// TODO: Code für die Behandlungsroutine der Steuerelement-Benachrichtigung
hier einfügen
///////////////////////
// EIGENER CODE, ANFANG
///////////////////////
// Hat Benutzer auf eine Datenzeile und nicht die
// Kopfzeile geklickt?
if (m_ctlFGrid.GetMouseRow() != 0)
{
// Wenn ja, dann Spaltenvariable auf 0 setzen
// und beenden
m_iMouseCol = 0;
return;
}
// Angeklickte Spalte sichern
m_iMouseCol = m_ctlFGrid.GetMouseCol();
// Wenn es die erste Spalte war, dann
// ist nichts zu tun.
if (m_iMouseCol == 0)
return;
// Neuzeichnen des Steuerelements abschalten
m_ctlFGrid.SetRedraw(FALSE);
// Gewählte Spaltenposition ändern
m_ctlFGrid.SetColPosition(m_iMouseCol, 0);
// Tabelle neu sortieren
DoSort();
// Neuzeichnen wieder einschalten
m_ctlFGrid.SetRedraw(TRUE);
///////////////////////
// EIGENER CODE, ENDE
///////////////////////
1. Single Document Interface - Einzeldokumentschnittstelle.
2. Die Ansichtsklasse ist für die Anzeige des Dokuments verantwortlich.
3. Um das Dokument neu zu zeichnen, wird die Funktion OnDraw
in der Ansichtsklasse
aufgerufen.
4. Um das aktuelle Dokument zu löschen, schreibt man den entsprechenden Code in
die Funktion DeleteContents
der Dokumentklasse.
5. Die Dokumentklasse verwaltet und manipuliert die Daten. Sie verwaltet die abstrakte Repräsentation des zu bearbeitenden Dokuments.
Führen Sie die folgenden Schritte aus:
1. Markieren Sie im Arbeitsbereich auf der Registerkarte Klassen die Klasse CLine
.
Klicken Sie mit der rechten Maustaste, und wählen Sie aus dem Kontextmenü den
Befehl Member-Variable hinzufügen.
2. Legen Sie den Variablentyp mit UINT
, die Deklaration mit m_nWidth
und den Zugriffsstatus
mit Privat fest. Klicken Sie auf OK, um die Variable hinzuzufügen.
3. Klicken Sie mit der rechten Maustaste im Baum der Registerkarte Klassen auf
den Konstruktor von CLine
. Wählen Sie aus dem Kontextmenü den Befehl Gehe
zu Deklaration.
4. Fügen Sie UINT nWidth
als viertes Argument in die Konstruktordeklaration ein.
5. Klicken Sie mit der rechten Maustaste im Baum der Registerkarte Klassen auf
den Konstruktor von CLine
. Wählen Sie aus dem Kontextmenü den Befehl Gehe
zu Definition.
6. Fügen Sie im Konstruktor das vierte Argument hinzu, und setzen Sie das Element
m_nWidth
auf das neue Argument, wie es Listing B.9 zeigt.
Listing B.9: Der modifizierte Konstruktor von CLine
1: CLine::CLine(CPoint ptFrom, CPoint ptTo, COLORREF crColor, UINT nWidth)
2: {
3: // Anfangs- und Endpunkte initialisieren
4: m_ptFrom = ptFrom;
5: m_ptTo = ptTo;
6: m_crColor = crColor;
7: m_nWidth = nWidth;
8: }
7. Gehen Sie nach unten zur Funktion Draw
, und nehmen Sie die Änderungen gemäß
Listing B.10 vor.
Listing B.10: Die modifizierte Funktion Draw
1: void CLine::Draw(CDC * pDC)
2: {
3: // Stift erzeugen
4: CPen lpen (PS_SOLID, m_nWidth, m_crColor);
5:
6: // Neuen Stift als Zeichenobjekt festlegen
7: CPen* pOldPen = pDC->SelectObject(&lpen);
8: // Linie zeichnen
9: pDC->MoveTo(m_ptFrom);
10: pDC->LineTo(m_ptTo);
11: // Vorherigen Stift zurücksetzen
12: pDC->SelectObject(pOldPen);
13: }
8. Gehen Sie nach unten zur Funktion Serialize
, und modifizieren Sie die Funktion
gemäß Listing B.11.
Listing B.11: Die modifizierte Funktion Serialize
1: void CLine::Serialize(CArchive &ar)
2: {
3: CObject::Serialize(ar);
4:
5: if (ar.IsStoring())
6: ar << m_ptFrom << m_ptTo << (DWORD) m_crColor << m_nWidth;
7: else
8: ar >> m_ptFrom >> m_ptTo >> (DWORD) m_crColor >> m_nWidth;
9: }
9. Markieren Sie im Arbeitsbereich auf der Registerkarte Klassen die Klasse
CTag10Doc
. Klicken Sie mit der rechten Maustaste, und wählen Sie aus dem Kontextmenü
den Befehl Member-Variable hinzufügen.
10. Legen Sie den Variablentyp mit UINT
, die Deklaration mit m_nWidth
und den Zugriffsstatus
als Privat fest. Klicken Sie auf OK, um die Variable hinzuzufügen.
11. Öffnen Sie den Quellcode von CTag10Doc
(Tag10.Doc.cpp
). Gehen Sie nach unten
zur Funktion OnNewDocument
, und bearbeiten Sie die Funktion entsprechend Listing
B.12.
Listing B.12: Die modifizierte Funktion OnNewDocument
1: BOOL CTag10Doc::OnNewDocument()
2: {
3: if (!CDocument::OnNewDocument())
4: return FALSE;
5:
6: // ZU ERLEDIGEN: Hier Code zur Reinitialisierung einfügen
7: // (SDI-Dokumente verwenden dieses Dokument)
8:
9: ///////////////////////
10: // EIGENER CODE, ANFANG
11: ///////////////////////
12:
13: // Farbe mit Schwarz initialisieren
14: m_nColor = ID_COLOR_BLACK - ID_COLOR_BLACK;
15: // Breite mit Dünn initialisieren
16: m_nWidth = ID_WIDTH_VTHIN - ID_WIDTH_VTHIN;
17:
18: ///////////////////////
19: // EIGENER CODE, ENDE
20: ///////////////////////
21:
22: return TRUE;
23: }
12. Gehen Sie nach unten zur Funktion AddLine
, und nehmen Sie die Änderungen
gemäß Listing B.13 vor.
Listing B.13: Die modifizierte Funktion AddLine
1: CLine * CTag10Doc::AddLine(CPoint ptFrom, CPoint ptTo)
2: {
3: static UINT nWidths[5] = { 1, 8, 16, 24, 32};
4:
5: // Ein neues CLine-Objekt erzeugen
6: CLine *pLine = new CLine(ptFrom, ptTo, m_crColors[m_nColor],
nWidths[m_nWidth]);
7: try
8: {
9: // Die neue Linie in das Objektarray einfügen
10: m_oaLines.Add(pLine);
11: // Dokument als bearbeitet markieren
12: SetModifiedFlag();
13: }
14: // Ist Speicherausnahme aufgetreten?
15: catch (CMemoryException* perr)
16: {
17: // Meldung für Benutzer, schlechte Neuigkeiten
18: // mitteilen
19: AfxMessageBox("Speichermangel", MB_ICONSTOP | MB_OK);
20: // Wurde Linienobjekt erzeugt?
21: if (pLine)
22: {
23: // Objekt löschen
24: delete pLine;
25: pLine = NULL;
26: }
27: // Ausnahmeobjekt löschen
28: perr->Delete();
29: }
30: return pLine;
31: }
13. Fügen Sie eine neue Member-Funktion in die Klasse CTag10Doc
ein. Legen Sie
den Funktionstyp als UINT
, die Deklaration als GetWidth
und den Zugriffsstatus als
Public fest.
14. Fügen Sie den Code aus Listing B.14 in die Funktion GetWidth
ein.
Listing B.14: Die Funktion GetWidth
1: UINT CTag10Doc::GetWidth()
2: {
3: // Aktuelle Breite zurückgeben
4: return ID_WIDTH_VTHIN + m_nWidth;
5: }
15. Gehen Sie im Arbeitsbereich auf die Registerkarte Ressourcen. Erweitern Sie
den Baum, so daß Sie den Inhalt des Ordners Menu
sehen. Doppelklicken Sie auf
die Menüressource.
16. Ziehen Sie den leeren Menübefehl der obersten Ebene (am rechten Ende der Menüleiste) nach links, und legen Sie ihn vor dem Menü Ansicht ab.
17. Öffnen Sie den Eigenschaftsdialog für den leeren Menübefehl. Legen Sie den Titel
mit Brei&te
fest. Schließen Sie das Eigenschaftsdialogfeld.
18. Fügen Sie die Menübefehle für das Menü Breite in der Reihenfolge und mit den Eigenschaften gemäß Tabelle B.1 hinzu.
19. Öffnen Sie den Klassen-Assistenten. Wählen Sie CTag10Doc
im Kombinationsfeld
Klassenname.
20. Fügen Sie Funktionen für die Nachrichten COMMAND
und UPDATE_COMMAND_UI
für
alle Menübefehle des Menüs Breite hinzu.
21. Nachdem Sie den letzten Menübefehl hinzugefügt haben, klicken Sie auf die Schaltfläche Code bearbeiten.
22. Bearbeiten Sie die Funktionen des Menübefehls Sehr dünn entsprechend Listing B.15.
Listing B.15: Die Funktionen des Menübefehls Sehr dünn
1: void CTag10Doc::OnWidthVthin()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuelle Breite auf Sehr dünn setzen
10: m_nWidth = ID_WIDTH_VTHIN - ID_WIDTH_VTHIN;
11:
12: ///////////////////////
13: // EIGENER CODE, ENDE
14: ///////////////////////
15: }
16:
17: void CTag10Doc::OnUpdateWidthVthin(CCmdUI* pCmdUI)
18: {
19: // TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren der
Benutzeroberfläche hier einfügen
20:
21: ///////////////////////
22: // EIGENER CODE, ANFANG
23: ///////////////////////
24:
25: // Prüfen, ob Menübefehl Sehr dünn mit Kontrollhäkchen zu versehen ist
26: pCmdUI->SetCheck(GetWidth() == ID_WIDTH_VTHIN ? 1 : 0);
27:
28: ///////////////////////
29: // EIGENER CODE, ENDE
30: ///////////////////////
31: }
23. Bearbeiten Sie die Funktionen des Menübefehls Dünn entsprechend Listing B.16.
Gehen Sie bei den restlichen Menüfunktionen in der gleichen Weise vor, wobei
Sie die jeweiligen Menü-IDs anstelle von ID_WIDTH_THIN
einsetzen.
Listing B.16: Die Funktionen des Menüs Dünn
1: void CTag10Doc::OnWidthThin()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuelle Breite auf Dünn setzen
10: m_nWidth = ID_WIDTH_THIN - ID_WIDTH_VTHIN;
11:
12: ///////////////////////
13: // EIGENER CODE, ENDE
14: ///////////////////////
15: }
16:
17: void CTag10Doc::OnUpdateWidthThin(CCmdUI* pCmdUI)
18: {
19: // TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren der
Benutzeroberfläche hier einfügen
20:
21: ///////////////////////
22: // EIGENER CODE, ANFANG
23: ///////////////////////
24:
25: // Prüfen, ob Menübefehl Dünn mit Kontrollhäkchen zu versehen ist
26: pCmdUI->SetCheck(GetWidth() == ID_WIDTH_THIN ? 1 : 0);
27:
28: ///////////////////////
29: // MY CODE ENDS HERE
30: ///////////////////////
31: }
1. Die fünf Basisklassen in MDI-Anwendungen sind die von CWinApp
abgeleitete Klasse,
die von CMDIFrameWnd
abgeleitete Klasse, die von CMDIChildWnd
abgeleitete
Klasse, die von CDocument
abgeleitete Klasse und die von CView
abgeleitete Klasse.
2. Der Klassen-Assistent versteht den Eintrag ON_COMMAND_RANGE
in der Nachrichtenzuordnungstabelle
nicht und wird ihn demzufolge entweder entfernen oder verfälschen.
Führen Sie die folgenden Schritte aus:
1. Fügen Sie den Behandlungscode für die Breite wie in der gestrigen Übung hinzu.
2. Fügen Sie die Menübefehle für das Menü Breite mit den gleichen Einstellungen wie gestern hinzu.
3. Öffnen Sie die Header-Datei Tag11Doc.h
.
4. Gehen Sie in der Header-Datei nach unten bis zum geschützten Abschnitt, in dem
die Nachrichtenzuordnungstabelle AFX_MSG
deklariert ist (suchen Sie nach //
{{AFX_MSG(CTag11Doc)
).
5. Fügen Sie die Funktionsdeklarationen aus Listing B.17 vor der gesuchten Zeile
ein. (Der gesuchte String markiert den Beginn der vom Klassen-Assistenten verwalteten
Nachrichtenzuordnungstabelle. Alles zwischen dieser Markierung und der
Endemarkierung //}}AFX_MSG
wird vom Klassen-Assistenten möglicherweise entfernt
oder verfälscht.)
Listing B.17: Die Deklarationen der Behandlungsroutinen in Tag11Doc.h
.
.
.
1: #ifdef _DEBUG
2: virtual void AssertValid() const;
3: virtual void Dump(CDumpContext& dc) const;
4: #endif
5:
6: protected:
7:
8: // Generierte Message-Map-Funktionen
9: protected:
10: afx_msg void OnColorCommand(UINT nID);
11: afx_msg void OnWidthCommand(UINT nID);
12: afx_msg void OnUpdateColorUI(CCmdUI* pCmdUI);
13: afx_msg void OnUpdateWidthUI(CCmdUI* pCmdUI);
14: //{{AFX_MSG(CTag11Doc)
15: ...
16: //}}AFX_MSG
17: DECLARE_MESSAGE_MAP()
18: private:
19: UINT m_nColor;
20: UINT m_nWidth;
21: CObArray m_oaLines;
22: };
6. Öffnen Sie die Quellcodedatei Tag11Doc.cpp
.
7. Suchen Sie nach der Zeile BEGIN_MESSAGE_MAP
, und fügen Sie unmittelbar danach
die Zeilen aus Listing B.18 ein. Es ist wichtig, daß dieser Code zwischen der Zeile
BEGIN_MESSAGE_MAP
und der Zeile //{{AFX_MSG_MAP
steht. Wenn Sie diese Befehle
zwischen die Zeilen //{{AFX_MSG_MAP
und //}}AFX_MSG_MAP
schreiben, entfernt
oder verstümmelt sie der Klassen-Assistent.
Listing B.18: Die Einträge der Behandlungsroutinen in der Nachrichtenzuordnungstabelle in Tag11Doc.cpp
1:///////////////////////////////////////////////////////////////////////
2: // CTag11Doc
3:
4: IMPLEMENT_DYNCREATE(CTag11Doc, CDocument)
5:
6: BEGIN_MESSAGE_MAP(CTag11Doc, CDocument)
7: ON_COMMAND_RANGE(ID_COLOR_BLACK, ID_COLOR_WHITE, OnColorCommand)
8: ON_COMMAND_RANGE(ID_WIDTH_VTHIN, ID_WIDTH_VTHICK, OnWidthCommand)
9: ON_UPDATE_COMMAND_UI_RANGE(ID_COLOR_BLACK, ID_COLOR_WHITE,
OnUpdateColorUI)
10: ON_UPDATE_COMMAND_UI_RANGE(ID_WIDTH_VTHIN, ID_WIDTH_VTHICK,
OnUpdateWidthUI)
11: //{{AFX_MSG_MAP(CTag11Doc)
12: ...
13: //}}AFX_MSG_MAP
14: END_MESSAGE_MAP()
15:
16: const COLORREF CTag11Doc::m_crColors[8] = {
17: RGB( 0, 0, 0), // Schwarz
18: RGB( 0, 0, 255), // Blau
.
.
.
8. Gehen Sie ans Ende der Datei, und fügen Sie die beiden Behandlungsroutinen aus Listing B.19 ein.
Listing B.19: Die Behandlungsroutinen für die Nachrichten des Menüs Breite
1: void CTag11Doc::OnWidthCommand(UINT nID)
2: {
3: // Aktuelle Breite setzen
4: m_nWidth = nID - ID_WIDTH_VTHIN;
5: }
6:
7: void CTag11Doc::OnUpdateWidthUI(CCmdUI* pCmdUI)
8: {
9: // Prüfen, ob Menübefehl mit Kontrollhäkchen zu versehen ist
10: pCmdUI->SetCheck(GetWidth() == pCmdUI->m_nID ? 1 : 0);
11: }
9. Öffnen Sie IDR_CONTEXTMENU
im Menü-Editor.
10. Fügen Sie in das überlappende Menü Breite die Menübefehle genau wie beim
Menü IDR_TAG11TYPE
und mit den gleichen Eigenschaftseinstellungen hinzu. Die
ID können Sie aus der Dropdown-Liste der IDs auswählen, wenn Sie lieber danach
suchen als sie einzutippen.
1. Vergeben Sie für die Schaltfläche der Symbolleiste dieselbe Objekt-ID wie für den Menübefehl.
2. Bei beiden muß das Andocken auf den gleichen Seiten in der Funktion OnCreate
der Rahmenklasse aktiviert sein (mit Hilfe der Funktion EnableDocking
).
3. Löschen Sie den Eintrag ID_INDICATOR_NUM
aus der Tabelle für die Statusleistenanzeige
am Anfang der Quellcodedatei des Hauptrahmens.
4. In die Symbolleiste ist eine Trennlinie als Platzhalter einzufügen. Der Symbolleisten-Editor hindert Sie in gut gemeinter Absicht daran, Trennlinien einzufügen, weil er hier einen Fehler vermutet.
1. Fügen Sie einen Eintrag in die Zeichenfolgentabelle mit der ID
ID_INDICATOR_WIDTH
und dem Titel SEHR DICK
ein.
Nehmen Sie einen weiteren Eintrag in die Tabelle der Statusleistenanzeige am
Anfang der Datei CMainFrame.cpp
auf:
static UINT indicators[] =
{
ID_SEPARATOR, // Statusleistenanzeige
ID_INDICATOR_WIDTH,
ID_INDICATOR_COLOR,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
Fügen Sie der Klasse CToolbarDoc
eine neue Member-Funktion hinzu. Legen Sie
den Funktionstyp als afx_msg void
, die Funktionsdeklaration als OnUpdateIndicatorWidth
(CCmdUI *pCmdUI)
und den Zugriffsstatus als Protected fest. In die
Funktion übernehmen Sie den folgenden Code:
void CToolbarDoc::OnUpdateIndicatorWidth(CCmdUI *pCmdUI)
{
CString strWidth;
// Aktuelle Breite?
switch (m_nWidth)
{
case 0: // Sehr dünn
strWidth = "SEHR DÜNN";
break;
case 1: // Dünn
strWidth = "DÜNN";
break;
case 2: // Mittel
strWidth = "MITTEL";
break;
case 3: // Dick
strWidth = "DICK";
break;
case 4: // Sehr dick
strWidth = "SEHR DICK";
break;
}
// Statusleistenausschnitt aktivieren
pCmdUI->Enable(TRUE);
// Test des Statusleistenausschnitts auf aktuelle
// Breite festlegen
pCmdUI->SetText(strWidth);
}
Fügen Sie der Nachrichtenzuordnungstabelle von CToolbarDoc
einen Eintrag für
die Behandlungsroutine der Nachricht ON_UPDATE_COMMAND_UI
wie folgt hinzu:
/////////////////////////////////////////////////////////////////////////////
// CToolbarDoc
IMPLEMENT_DYNCREATE(CToolbarDoc, CDocument)
BEGIN_MESSAGE_MAP(CToolbarDoc, CDocument)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_WIDTH, OnUpdateIndicatorWidth)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_COLOR, OnUpdateIndicatorColor)
//{{AFX_MSG_MAP(CToolbarDoc)
ON_COMMAND(ID_COLOR_BLACK, OnColorBlack)
ON_UPDATE_COMMAND_UI(ID_COLOR_BLACK, OnUpdateColorBlack)
...
ON_COMMAND(ID_WIDTH_VTHIN, OnWidthVthin)
ON_UPDATE_COMMAND_UI(ID_WIDTH_VTHIN, OnUpdateWidthVthin)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
2. Öffnen Sie die Symbolleiste IDR_MAINFRAME
im Symbolleisten-Editor. Zeichnen Sie
ein Symbol für die leere Schaltfläche am Ende der Symbolleiste. Doppelklicken
Sie auf die Schaltfläche, um das zugehörige Eigenschaftsdialogfeld zu öffnen. Legen
Sie die ID mit ID_VIEW_COLORBAR
fest, und geben Sie einen passenden Statuszeilentext
ein. Kompilieren Sie die Anwendung erneut, und führen Sie sie aus. Auf
der Hauptsymbolleiste sollte nun die Umschaltung der Farbsymbolleiste funktionieren.
1. DECLARE_SERIAL
und IMPLEMENT_SERIAL
.
2. Rufen Sie dazu die Funktion IsStoring
oder IsLoading
auf.
3. Den Klassennamen, den Namen der Basisklasse und die Versionsnummer.
Im Dialog-Editor fügen Sie zwei Optionsfelder und das Textfeld mit der Aufforderung hinzu. Legen Sie die Eigenschaften der Steuerelemente gemäß Tabelle B.2 fest.
Verbinden Sie mit den neuen Optionsfeldern eine Variable laut Tabelle B.3.
Inkrementieren Sie die Versionsnummer im Makro IMPLEMENT_SERIAL
in der Klasse
CPerson
. Fügen Sie eine neue Member-Variable in die Klasse CPerson
ein. Legen Sie
den Typ als int
, den Namen als m_iSex
und den Zugriffsstatus als Privat fest. Aktualisieren
Sie die Konstruktorfunktion von CPerson
, indem Sie die Variable m_iSex
in die
Initialisierungen wie in Zeile 8 von Listing B.20 einfügen.
Listing B.20: Der modifizierte Konstruktor von CPerson
1: CPerson::CPerson()
2: {
3: // Klassenvariablen initialisieren
4: m_iMaritalStatus = 0;
5: m_iAge = 0;
6: m_bEmployed = FALSE;
7: m_sName = "";
8: m_iSex = 0;
9: }
Fügen Sie entsprechend der Zeilen 10 und 16 von Listing B.21 die Inline-Funktionen
in die Klassendeklaration von CPerson
ein, um den Wert der neuen Variablen zu setzen
und abzurufen.
Listing B.21: Die modifizierte Deklaration der Klasse CPerson
1: class CPerson : public CObject
2: {
3: DECLARE_SERIAL (CPerson)
4: public:
5: virtual void Serialize(CArchive &ar);
6: // Funktionen zum Setzen der Variablen
7: void SetEmployed(BOOL bEmployed) { m_bEmployed = bEmployed;}
8: void SetMaritalStat(int iStat) { m_iMaritalStatus = iStat;}
9: void SetAge(int iAge) { m_iAge = iAge;}
10: void SetSex(int iSex) { m_iSex = iSex; }
11: void SetName(CString sName) { m_sName = sName;}
12: // Funktionen zum Holen der aktuellen Variableneinstellungen
13: BOOL GetEmployed() { return m_bEmployed;}
14: int GetMaritalStatus() { return m_iMaritalStatus;}
15: int GetAge() {return m_iAge;}
16: int GetSex() {return m_iSex;}
17: CString GetName() {return m_sName;}
18: CPerson();
19: virtual ~CPerson();
20:
21: private:
22: int m_iSex;
23: int m_iMaritalStatus;
24: CString m_sName;
25: int m_iAge;
26: BOOL m_bEmployed;
27: };
Aktualisieren Sie die Funktion Serialize
in der Klasse CPerson
, um die Variable
m_iSex
entsprechend der Zeilen 9 und 12 von Listing B.22 einzubinden.
Listing B.22: Die modifizierte Funktion Serialize der Klasse CPerson
1: void CPerson::Serialize(CArchive &ar)
2: {
3: // Funktion der Basisklasse aufrufen
4: CObject::Serialize(ar);
5:
6: // Wird geschrieben?
7: if (ar.IsStoring())
8: // Alle Variablen in der richtigen Reihenfolge schreiben
9: ar << m_sName << m_iAge << m_iMaritalStatus << m_bEmployed <<m_iSex;
10: else
11: // Alle Variablen in der richtigen Reihenfolge lesen
12: ar >> m_sName >> m_iAge >> m_iMaritalStatus >> m_bEmployed >>m_iSex;
13:
14: }
Modifizieren Sie die Funktion PopulateView
im Ansichtsobjekt, um die Variable
m_iSex
in den Datenaustausch aufzunehmen, wie es Zeile 19 von Listing B.23 zeigt.
Listing B.23: Die modifizierte Funktion PopulateView der Klasse CSerializeView
1: void CSerializeView::PopulateView()
2: {
3: // Einen Zeiger auf das aktuelle Dokument holen
4: CSerializeDoc* pDoc = GetDocument();
5: if (pDoc)
6: {
7: // Aktuelle Datensatzposition in der Menge anzeigen
8: m_sPosition.Format("Datensatz %d von %d", pDoc->GetCurRecordNbr(),
9: pDoc->GetTotalRecords());
10: }
11: // Ist Datensatzobjekt gültig?
12: if (m_pCurPerson)
13: {
14: // Ja, alle Werte des Datensatzes holen
15: m_bEmployed = m_pCurPerson->GetEmployed();
16: m_iAge = m_pCurPerson->GetAge();
17: m_sName = m_pCurPerson->GetName();
18: m_iMaritalStatus = m_pCurPerson->GetMaritalStatus();
19: m_iSex = m_pCurPerson->GetSex();
20: }
21: // Anzeige aktualisieren
22: UpdateData(FALSE);
23: }
Fügen Sie eine Behandlungsroutine für das Klickereignis der beiden neuen Optionsfelder
hinzu. Nutzen Sie für beide Behandlungsroutinen dieselbe Funktion. Aktualisieren
Sie das Feld des Datensatzobjekts mittels der Set
-Funktion wie in Listing B.24.
Listing B.24: Die Funktion OnSex der Klasse CSerializeView
1: void CSerializeView::OnSex()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
Benachrichtigung hier einfügen
4:
5: // Daten im Formular mit Variablen synchronisieren
6: UpdateData(TRUE);
7: // Wenn gültiges Person-Objekt vorhanden, Daten an das Objekt übergeben
8: if (m_pCurPerson)
9: m_pCurPerson->SetSex(m_iSex);
10: // Zeiger auf das Dokument holen
11: CSerialDoc * pDoc = GetDocument();
12: if (pDoc)
13: // Veränderungsflag im Dokument setzen
14: pDoc->SetModifiedFlag();
15: }
1. Open Database Connectivity, d.h. eine offene, herstellerunabhängige Schnittstelle für den Zugriff auf Datenbanken.
2. Move
, MoveNext
, MovePrev
, MoveFirst
, MoveLast
und SetAbsolutePosition
.
4. AddNew
, Update
und Requery
.
1. Erstellen Sie ein neues Dialogfeld mit dem in Abbildung B.1 gezeigten Layout. Konfigurieren Sie die Steuerelemente nach Tabelle B.4.
Abbildung B.1:
Das Dialogfeld Gehe zu
2. Öffnen Sie den Klassen-Assistenten. Erzeugen Sie eine neue Klasse für das neue
Dialogfeld. Nennen Sie die neue Klasse CMoveToDlg
. Fügen Sie dann eine Variable
für das Eingabefeld hinzu. Legen Sie den Variablentyp als long
und den Namen
als m_lRowNbr
fest.
3. Fügen Sie einen weiteren Menübefehl in das Hauptmenü der Anwendung ein. Legen Sie die Menüeigenschaften gemäß Tabelle B.5 fest.
4. Öffnen Sie den Klassen-Assistenten, und fügen Sie eine Behandlungsfunktion für
die Nachricht COMMAND
des neuen Menübefehls in die Ansichtsklasse ein. In die
Funktion übernehmen Sie den Code aus Listing B.25.
Listing B.25: Die Funktion OnRecordMove der Klasse CDbOdbcView
1: void CDbOdbcView::OnRecordMove()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4: // Instanz des Dialogfelds 'Gehe zu' erzeugen
5: CMoveToDlg dlgMoveTo;
6: // Zeilennummer des Ziels ermitteln
7: if (dlgMoveTo.DoModal() == IDOK)
8: {
9: // Zeiger auf den Recordset holen
10: CRecordset* pSet = OnGetRecordset();
11: // Sicherstellen, daß alle Änderungen am aktuellen Datensatz gespeichert
wurden.
12: if (pSet->CanUpdate() && !pSet->IsDeleted())
13: {
14: pSet->Edit();
15: if (!UpdateData())
16: return;
17:
18: pSet->Update();
19: }
20: // Neue Position einstellen
21: pSet->SetAbsolutePosition(dlgMoveTo.m_lRowNbr);
22: // Formular aktualisieren
23: UpdateData(FALSE);
24: }
25: }
5. Binden Sie die Header-Datei für das neue Dialogfeld in den Quellcode der Ansichtsklasse ein, wie es aus Zeile 10 von Listing B.26 hervorgeht.
Listing B.26: Die Include-Anweisungen der Klasse CDbOdbcView
1: // DbOdbcView.cpp : Implementierung der Klasse CDbOdbcView
2: //
3:
4: #include "stdafx.h"
5: #include "DbOdbc.h"
6:
7: #include "DbOdbcSet.h"
8: #include "DbOdbcDoc.h"
9: #include "DbOdbcView.h"
10: #include "MoveToDlg.h"
6. Fügen Sie eine Symbolleistenschaltfläche für den neuen Menübefehl ein.
3. Connection
, Command
, Parameter
, Error
, Recordset
und Field
.
5. pCmd->ActiveConnection = pConn;
_RecordsetPtr pRs;
pRs = pCmd->Execute();
_RecordsetPtr pRs;
pRs.CreateInstance(__uuidof(Recordset));
pRs->PutRefSource(pCmd);
Fügen Sie der Dokumentklasse Behandlungsfunktionen für die Nachricht
UPDATE_COMMAND_UI
der Befehle des Navigationsmenüs hinzu. In die Funktionen für
die Menübefehle Erster und Vorheriger schreiben Sie den Code aus Listing B.27,
für die Menübefehle Letzter und Nächster den Code aus Listing B.28.
Listing B.27: Die Funktion OnUpdateDataFirst der Klasse CDbAdoDoc
1: void CDbAdoDoc::OnUpdateDataFirst(CCmdUI* pCmdUI)
2: {
3: // TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren der
Benutzeroberfläche hier einfügen
4: // Existiert der Datensatz?
5: if (m_pRs)
6: {
7: // Am Anfang der Datei (BOF) angelangt?
8: if (m_pRs->BOF)
9: pCmdUI->Enable(FALSE);
10: else
11: pCmdUI->Enable(TRUE);
12: }
13: }
Listing B.28: Die Funktion OnUpdateDataLast der Klasse CDbAdoDoc
1: void CDbAdoDoc::OnUpdateDataLast(CCmdUI* pCmdUI)
2: {
3: // TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren der
Benutzeroberfläche hier einfügen
4: // Existiert der Datensatz?
5: if (m_pRs)
6: {
7: // Am Ende der Datei (EOF) angelangt?
8: if (m_pRs->EndOfFile)
9: pCmdUI->Enable(FALSE);
10: else
11: pCmdUI->Enable(TRUE);
12: }
13: }
1. Wenn man eine neue Klasse erstellen muß, die von einer existierenden MFC-Klasse abgeleitet ist.
2. Alle Anwendungen sind erneut zu linken.
3. MFC, Allgemein und Formular.
4. Die LIB-Bibliotheksdatei und die Header-Dateien für die Objekte im Modul.
5. Kapselung und Vererbung. Das dritte Prinzip ist der Polymorphismus, der in der heutigen Lektion nicht behandelt wurde.
1. Erstellen Sie ein neues Projekt. Wählen Sie dazu im Dialogfeld Neu auf der Registerkarte
Projekte den Eintrag Win32-Bibliothek (statische). Tragen Sie einen
Projektnamen wie etwa Line
ein.
2. Aktivieren Sie die Unterstützung für MFC und vorkompilierte Header.
3. Kopieren Sie die Dateien Line.cpp
und Line.h
in das Projektverzeichnis. Fügen
Sie beide Dateien dem Projekt hinzu. Kompilieren Sie das Bibliotheksmodul.
4. Öffnen Sie das originale Projekt des Bibliotheksmoduls. Löschen Sie die Dateien
Line.cpp
und Line.h
aus dem Projekt. Fügen Sie am Beginn der Quellcodedatei
für das Zeichenobjekt die Header-Datei Line.h
aus dem Verzeichnis des Projekts
Line
ein, wie es Zeile 9 von Listing B.29 zeigt. Kompilieren Sie das Projekt neu.
Listing B.29: Die Include-Anweisungen und die Farbtabelle der Klasse CModArt
1: // ModArt.cpp: Implementierung der Klasse CModArt.
2: //
3: //////////////////////////////////////////////////////////////////////
4:
5: #include <stdlib.h>
6: #include <time.h>
7:
8: #include "stdafx.h"
9: #include "..\Line\Line.h"
10: #include "ModArt.h"
5. Öffnen Sie das Projekt der Testanwendung. Fügen Sie die Bibliotheksdatei Line
in
das Projekt ein. Erstellen Sie das Projekt.
2. Das Makro AFX_EXT_CLASS
in der Klassendeklaration.
4. Normalerweise nicht. Allerdings müssen Sie die Anwendungen, die auf die DLL zurückgreifen, neu kompilieren, wenn Sie in der exportierten Schnittstelle der DLL Änderungen vorgenommen haben.
5. Die LIB-Datei enthält Funktionsrümpfe der Funktionen in der DLL und den erforderlichen Code, um den Funktionsaufruf zu lokalisieren und an die eigentliche Funktion in der DLL weiterzuleiten.
1. Erstellen Sie ein neues Projekt. Wählen Sie dazu im Dialogfeld Neu auf der Registerkarte
Projekte den Eintrag MFC-Anwendungs-Assistent (dll). Tragen Sie einen
Projektnamen wie beispielsweise LineDll
ein.
Wählen Sie im ersten Schritt des MFC-Anwendungs-Assistenten die Option Erweiterungs-MFC-DLL .
Nachdem Sie das Projektgerüst erstellt haben, kopieren Sie die Quellcode- und
Header-Dateien für die Klasse Line
in das Projektverzeichnis. Nehmen Sie diese
Dateien in das Projekt auf.
Fügen Sie in die Deklaration der Klasse CLine
das Makro AFX_EXT_CLASS
hinzu.
Kompilieren Sie die DLL. Kopieren Sie die DLL in das Debug-Verzeichnis für die Testanwendung.
Öffnen Sie das Projekt der Standard-DLL. Löschen Sie über die Registerkarte Dateien
des Arbeitsbereichs die Quellcode- und Header-Dateien der Klasse Line
aus
dem Projekt. Fügen Sie die Linien-DLL-LIB-Datei in das Projekt ein. Ändern Sie
in der Quellcodedatei die Zeichenfunktionalität, indem Sie den Header der Linienklasse
in der Version aus dem Projektverzeichnis der CLine
-DLL einbinden, wie es
Listing B.30 zeigt.
Listing B.30: Die Include-Anweisungen der Klasse CModArt
1: // ModArt.cpp: Implementierung der Klasse CModArt.
2: //
3: /////////////////////////////////////////////////////////////////////
4:
5: #include <stdlib.h>
6: #include <time.h>
7:
8: #include "stdafx.h"
9: #include "..\LineDll\Line.h"
10: #include "ModArt.h"
Kompilieren Sie das Projekt. Kopieren Sie die DLL in das Debug-Verzeichnis des Projekts für die Testanwendung.
Starten Sie die Testanwendung.
2. Öffnen Sie das Projekt der Linienklasse-DLL, das Sie in der vorherigen Übung erstellt
haben. Ersetzen Sie im Konstruktor der Klasse die Initialisierung der Variablen
m_nWidth
durch einen konstanten Wert, wie es Listing B.31 zeigt.
Listing B.31: Der Konstruktor der Klasse CLine
1: CLine::CLine(CPoint ptFrom, CPoint ptTo, UINT nWidth, COLORREF crColor)
2: {
3: m_ptFrom = ptFrom;
4: m_ptTo = ptTo;
5: m_nWidth = 1;
6: m_crColor = crColor;
7: }
Kompilieren Sie die DLL. Kopieren Sie die DLL in das Debug-Verzeichnis des Projekts für die Testanwendung. Starten Sie die Testanwendung.
1. Wenn die Anwendung im Leerlauf arbeitet und keine Nachrichten in der Nachrichtenwarteschlange stehen.
2. Die Rückgabe des Wertes TRUE
bewirkt, daß die Funktion OnIdle
wiederholt aufgerufen
wird, solange die Anwendung im Leerlauf bleibt.
3. Eine OnIdle
-Task wird nur ausgeführt, wenn die Anwendung im Leerlauf ist und
keine Nachrichten in der Nachrichtenwarteschlange stehen. Ein Thread läuft dagegen
vollkommen unabhängig von der übrigen Anwendung.
4. Kritische Abschnitte, Mutexe, Semaphoren und Ereignisse.
5. Die verbleibenden Threads und Prozesse, die auf dem Computer laufen, erhalten wesentlich weniger Prozessorzeit.
1. Bearbeiten Sie die Funktion OnIdle
gemäß Listing B.32.
Listing B.32: Die modifizierte Funktion OnIdle der Klasse CTaskingApp
1: BOOL CTaskingApp::OnIdle(LONG lCount)
2: {
3: // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
4:
5: // Leerlaufverarbeitung der Basisklasse aufrufen
6: BOOL bRtn = CWinApp::OnIdle(lCount);
7:
8: // Position der ersten Dokumentvorlage holen
9: POSITION pos = GetFirstDocTemplatePosition();
10: // Ist Position der Dokumentvorlage gültig?
11: if (pos)
12: {
13: // Zeiger auf die Dokumentvorlage ermitteln
14: CDocTemplate* pDocTemp = GetNextDocTemplate(pos);
15: // Ist Zeiger gültig?
16: if (pDocTemp)
17: {
18: // Position des ersten Dokuments holen
19: POSITION dPos = pDocTemp->GetFirstDocPosition();
20: // Ist Position des Dokuments gültig?
21: if (dPos)
22: {
23: // Zeiger auf das Dokument ermitteln
24: CTaskingDoc* pDocWnd =
25: (CTaskingDoc*)pDocTemp->GetNextDoc(dPos);
26: // Ist Zeiger gültig?
27: if (pDocWnd)
28: {
29: // Position der Ansicht ermitteln
30: POSITION vPos = pDocWnd->GetFirstViewPosition();
31: // Ist Ansichtsposition gültig?
32: if (vPos)
33: {
34: // Zeiger auf die Ansicht holen
35: CTaskingView* pView = (CTaskingView*)pDocWnd-
>GetNextView(vPos);
36: // Ist Zeiger gültig?
37: if (pView)
38: {
39: // Fächer für ersten Leerlauf-Thread drehen?
40: if (pView->m_bOnIdle1)
41: {
42: // Ersten Leerlauf-Thread drehen
43: pDocWnd->DoSpin(0);
44: bRtn = TRUE;
45: }
46: // Zweiten Leerlauf-Thread drehen?
47: if (pView->m_bOnIdle2)
48: {
49: // Zweiten Leerlauf-Thread drehen
50: pDocWnd->DoSpin(2);
51: bRtn = TRUE;
52: }
53: }
54: }
55: }
56: }
57: }
58: }
59: return bRtn;
60: }
2. Beim Starten der unabhängigen Threads geben Sie einem Thread die Priorität
THREAD_PRIORITY_NORMAL
und dem anderen die Priorität
THREAD_PRIORITY_LOWEST
.
Bearbeiten Sie die Funktion SuspendSpinner
entsprechend Listing B.33.
Listing B.33: Die modifizierte Funktion SuspendSpinner der Klasse CTaskingDoc
1: void CTaskingDoc::SuspendSpinner(int nIndex, BOOL bSuspend)
2: {
3: // Thread anhalten?
4: if (!bSuspend)
5: {
6: // Ist Zeiger für den Thread gültig?
7: if (m_pSpinThread[nIndex])
8: {
9: // Handle für den Thread holen
10: HANDLE hThread = m_pSpinThread[nIndex]->m_hThread;
11: // Auf Absterben des Threads warten
12: ::WaitForSingleObject (hThread, INFINITE);
13: }
14: }
15: else // Thread laufen lassen
16: {
17: int iSpnr;
18: int iPriority;
19: // Welchen Fächer verwenden?
20: switch (nIndex)
21: {
22: case 0:
23: iSpnr = 1;
24: iPriority = THREAD_PRIORITY_NORMAL;
25: break;
26: case 1:
27: iSpnr = 3;
28: iPriority = THREAD_PRIORITY_LOWEST;
29: break;
30: }
31: // Thread starten, Zeiger auf Fächer übergeben
32: m_pSpinThread[nIndex] = AfxBeginThread(ThreadFunc,
33: (LPVOID)&m_cSpin[iSpnr], iPriority);
34: }
35: }
1. Eigenschaften, Methoden und Ereignisse.
2. Um dem Benutzer die Möglichkeit zu geben, die Eigenschaften des Steuerelements festzulegen.
3. Ambient, erweitert, vordefiniert und benutzerdefiniert.
4. Die Schnittstellenparameter werden zu einer standardisierten, maschinenunabhängigen Struktur gepackt und über Prozeßgrenzen hinweg gesendet. Diesen Vorgang bezeichnet man als Marshaling.
5. Mit dem Testcontainer für ActiveX-Steuerelemente.
1. Öffnen Sie den Klassen-Assistenten, und gehen Sie auf die Registerkarte Automatisierung
. Klicken Sie auf die Schaltfläche Methode hinzufügen. Geben Sie
einen Methodennamen wie etwa GenNewDrawing
ein, und legen Sie den Rückgabetyp
als void
fest. Klicken Sie auf OK, um die Methode hinzuzufügen. In die Methode
übernehmen Sie den Code aus Listing B.34.
Listing B.34: Die Funktion GenNewDrawing der Klasse CSquiggleCtrl
1: void CSquiggleCtrl:: GenNewDrawing()
2: {
3: // ZU ERLEDIGEN: Fügen Sie hier den Code für Ihre Dispatch-
Behandlungsroutine ein
4: // Flag setzen, so daß neue Zeichnung generiert wird
5: m_bGenNewDrawing = TRUE;
6: // Steuerelement ungültig machen, um Funktion OnDraw auszulösen
7: Invalidate();
8: }
2. Öffnen Sie den Klassen-Assistenten, und gehen Sie auf die Registerkarte Automatisierung
. Klicken Sie auf die Schaltfläche Methode hinzufügen. Geben Sie
einen Methodennamen wie SaveDrawing
ein, und legen Sie den Rückgabetyp als
BOOL
fest. Nehmen Sie einen einzelnen Parameter, sFileName
, mit dem Typ LPCSTR
auf. Klicken Sie auf OK, um die Methode hinzuzufügen. In die Methode
schreiben Sie den Code aus Listing B.35.
Listing B.35: Die Funktion SaveDrawing der Klasse CSquiggleCtrl
1: BOOL CSquiggleCtrl::SaveDrawing(LPCTSTR sFileName)
2: {
3: // ZU ERLEDIGEN: Fügen Sie hier den Code für Ihre Dispatch-
Behandlungsroutine ein
4: try
5: {
6: // Ein CFile-Objekt erzeugen
7: CFile lFile(sFileName, CFile::modeWrite);
8: // CArchive-Objekt erzeugen, um die Datei zu speichern
9: CArchive lArchive(&lFile, CArchive::store);
10: // Datei speichern
11: m_maDrawing.Serialize(lArchive);
12: }
13: catch (CFileException err)
14: {
15: return FALSE;
16: }
17: return TRUE;
18: }
1. Die Netzwerkadresse (oder den Namen) des Computers und den Anschluß, den der Server abhört.
Führen Sie die folgenden Schritte aus:
1. Nehmen Sie eine Member-Variable in die Dialogfeldklasse (CSockDlg
) auf. Legen
Sie den Variablentyp als BOOL
, den Namen als m_bConnected
und den Zugriffsstatus
als Privat fest.
2. Initialisieren Sie die Variable in der Funktion OnInitDialog
als FALSE
.
3. Setzen Sie die Variable in der Dialogfeldfunktion OnAccept
auf TRUE
, nachdem die
Verbindung angenommen wurde.
4. Setzen Sie die Variable in der Dialogfeldfunktion OnClose
auf FALSE
.
5. Modifizieren Sie die Dialogfeldfunktion OnAccept
gemäß Listing B.36.
Listing B.36: Die modifizierte Funktion OnAccept der Klasse CSockDlg
1: void CSockDlg::OnAccept()
2: {
3: if (m_bConnected)
4: {
5: // Ablehnungs-Socket erzeugen
6: CAsyncSocket sRjctSock;
7: // Zu sendende Meldung erzeugen
8: CString strMsg = "Zu viele Verbindungen, bitte später noch einmal
versuchen.";
9: // Mittels Ablehnungs-Socket annehmen
10: m_sListenSocket.Accept(sRjctSock);
11: // Ablehnungsmeldung senden
12: sRjctSock.Send(LPCTSTR(strMsg), strMsg.GetLength());
13: // Socket schließen
14: sRjctSock.Close();
15: }
16: else
17: {
18: // Verbindungsanforderung annehmen
19: m_sListenSocket.Accept(m_sConnectSocket);\
20: // Socket als verbunden markieren
21: m_bConnected = TRUE;
22: // Steuerelemente für Text und Nachrichten aktivieren
23: GetDlgItem(IDC_EMSG)->EnableWindow(TRUE);
24: GetDlgItem(IDC_BSEND)->EnableWindow(TRUE);
25: GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE);
26: }
27: }
1. Den Webbrowser Internet Explorer.
2. Mit der Funktion GetLocationURL()
.
1. Nehmen Sie einen Menübefehl in das Menü Wechseln zu auf. Legen Sie die Eigenschaften des Menübefehls nach Tabelle B.6 fest.
Fügen Sie der Ansichtsklasse mit dem Klassen-Assistenten eine Behandlungsroutine
für die ID IDM_GO_SEARCH
für die Nachricht COMMAND
hinzu. In die Funktion
schreiben Sie den Code entsprechend Listing B.37.
Listing B.37: Die Funktion OnGoSearch der Klasse CWebBrowseView
1: void CWebBrowseView::OnGoSearch()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4:
5: // Zur Suchseite gehen
6: GoSearch();
7: }
Fügen Sie eine Symbolleistenschaltfläche für die Menü-ID IDM_GO_SEARCH
hinzu.
2. Nehmen Sie einen Menübefehl in das Menü Wechseln zu auf. Legen Sie die Eigenschaften des Menübefehls entsprechend Tabelle B.7 fest.
Fügen Sie der Ansichtsklasse mit dem Klassen-Assistenten eine Behandlungsfunktion
für die ID IDM_GO_START
für die Nachricht COMMAND
hinzu. Übernehmen Sie
den Code aus Listing 38 in die Funktion.
Listing B.38: Die Funktion OnGoStart der Klasse CWebBrowseView
1: void CWebBrowseView::OnGoStart()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4:
5: // Zur Startseite gehen
6: GoHome();
7: }
Fügen Sie eine Symbolleistenschaltfläche für die Menü-ID IDM_GO_START
hinzu.
3. Fügen Sie der Ansichtsklasse mit dem Klassen-Assistenten eine Behandlungsroutine
für die Objekt-ID IDM_VIEW_STOP
für die Nachricht UPDATE_COMMAND_UI
hinzu.
Übernehmen Sie den Code aus Listing B.39 in diese Funktion.
Listing B.39: Die Funktion OnUpdateViewStop der Klasse CWebBrowseView
1: void CWebBrowseView::OnUpdateViewStop(CCmdUI* pCmdUI)
2: {
3: // TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren der
Benutzeroberfläche hier einfügen
4:
5: // Schaltfläche aktivieren, wenn beschäftigt
6: pCmdUI->Enable(GetBusy());
7: }