Darstellen des Fensterinhalts

Zurück Zum Inhaltsverzeichnis Weiter

Wurde bisher nur die Erstellung und das Schließen eines Fensters aufgezeigt, so soll nun der prinzipielle Ablauf bei der Darstellung des Fensterinhalts betrachtet werden.

Wenn WINDOWS entweder das ganze Fenster oder einen Teil davon neu zeichnen lassen möchte,  so sendet es eine Nachricht WM_PAINT. Die Zusatzinformationen zur Nachricht haben folgende Bedeutung:

WM_PAINT Nachricht

WPARAM wParam keine Bedeutung
LPARAM lParam keine Bedeutung

Beachten Sie bitte, dass die Fensterprozedur im Parameter hWnd das Fenster-Handle des Fensters erhält, dessen Inhalt zu aktualisieren ist.

Merken Sie sich aber für alle Zeiten folgenden wichtigen Satz:

Ein WINDOWS Programm muss jederzeit in der Lage sein den Inhalt seines Fensters neu darzustellen. WINDOWS selbst speichert den Inhalt eines Fenster nicht ab!

Um das Fenster auf das Zeichnen (und darunter fällt auch die Ausgabe von Texten, denn WINDOWS ist ein grafisches System) seines Inhaltes vorzubereiten, muss zuerst die Funktion BeginPaint(...) aufgerufen werden. Sie liefert als Returnwert ein Handle auf einen Device Context den jede Zeichenoperation benötigt. Der Device Context enthält alle aktuellen Einstellungen die für das Zeichnen benötigt werden. Darunter fällt z.B. der aktuelle Pen (Zeichenstift) oder auch der aktuelle Brush (Pinsel).

Außer diesem Device-Context-Handle liefert die Funktion BeginPaint(...) auch den Bereich innerhalb des Fensters zurück, innerhalb dessen gezeichnet wird. Zeichenoperationen die außerhalb dieses Bereichs liegen werden unterdrückt. Dieser Bereich wird auch als Clipping-Bereich bezeichnet.

Beispiel: Die Client-Area des Fensters besitzt eine Ausdehnung von 150x150 Pixel. Daraus folgt, dass das Fenster die Koordinaten von (0/0) bis (149/149) besitzt. Nehmen wir jetzt an, dass der Clipping-Bereich von (50/50) bis (100/100) gehen soll. Wird jetzt versucht eine Linie von links oben (0/0) nach rechts unten (149/149) zu zeichnen, so wird die Linie nur im Bereich von (50/50) bis (100/100) neu gezeichnet. Der darüber hinausgehende Teil der Linie wird beim Zeichnen abgeschnitten.

Das Clipping

Nach dem Aufruf von BeginPaint(...) kann die Anwendung dann mit Hilfe des erhaltenen Device Context Handle den Fensterinhalt neu darstellen.

Ist der Fensterinhalt aktualisiert worden, muss die Anwendung das Gegenstück zu BeginPaint(...) aufrufen, die Funktion EndPaint(...). EndPaint(...) kennzeichnet den gesamten Fensterinhalt als gültig, d.h. der Clipping-Bereich wird geleert.

Doch woher weiß WINDOWS, welcher Bereich im Fenster ungültig ist und damit neu gezeichnet werden muss? Um diese Frage zu beantworten müssen wir drei Fälle unterscheiden:

  • Ein Teil des Fensters war vorher von einem anderen Fenster verdeckt und ist nun wieder sichtbar. In diesem Fall kennzeichnet WINDOWS den nun sichtbar gewordenen Teil des Fensters als neu zu zeichnenden Bereich (im Beispiel unten der blau markierte Bereich).

    vorher nachher


  • Das Fenster wurde vergrößert. In diesem Fall kennzeichnet WINDOWS den neu hinzugekommenen Bereich des Fensters als ungültig. Aber sehen Sie sich dazu das nachfolgende rechte Bild einmal genauer an. Obwohl das hier eingesetzte  Programm immer eine Linie von links oben nach rechts unten zeichnet bleibt die alte Linie vollständig erhalten da dieser Teil des Fensters nicht als ungültig gekennzeichnet wurde und damit dem Clipping zum Opfer fällt. Wie Sie solche Fälle trotzdem richtig handhaben, erfahren Sie in der nächsten Lektion.

    vorher nachher


  • Die Anwendung teilt WINDOWS über den Aufruf der Funktion InvalidateRect(...) mit, dass ein bestimmter Bereich des Fensters neu zu zeichnen ist.

Mit dem jetzt erworben Wissen könnten wir das vorherige Beispiel um die Bearbeitung der WM_PAINT Nachricht erweitern. Was zum Schluss noch fehlt, ist das eigentliche Zeichnen als Reaktion auf die Nachricht. Dies wird aber erst später im Kapitel GDI behandelt. Damit im Beispiel trotzdem festgestellt werden kann wann eine WM_PAINT Nachricht eintrifft, geben wir als Reaktion auf die Nachricht einen Ton aus. Dies kann durch den Aufruf der Funktion MessageBeep(...) erreicht werden.

Fügen Sie jetzt zu Ihrer Fensterprozedur die Verarbeitung der WM_PAINT Nachricht hinzu. Da wird ja noch nichts zeichnen können, rufen Sie statt dessen die Funktion MessageBeep(-1UL) auf.

Lösung zur WM_PAINT Nachricht

// Die Fensterprozedur!
// --------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg,
                         WPARAM wParam, LPARAM lParam)
{
    // Nachrichten auswerten.
    switch (uMsg)
    {
    case WM_DESTROY:
        ....
    case WM_CLOSE:
        ....
    case WM_PAINT:
        {
            // Struktur fuer Zeichendaten
            PAINTSTRUCT strPaint;
            // Zeichenvorgang einleiten
            HDC hDC = BeginPaint(hWnd,&strPaint);
            // WM_PAINT signalisieren
            MessageBeep(-1);
            // Zeichenvorgang abschliessen
            EndPaint(hWnd,&strPaint);
            return 0L;
        }
    }
    // Nicht bearbeitete Nachrichten an WINDOWS uebergeben
    return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

Beachten Sie bitte, dass Sie immer die beiden Funktionen BeginPaint(...) und EndPaint(...) aufrufen müssen und das auch dann, wenn Sie nichts zeichnen!

Ende der Lösung

Wenn Sie das Beispiel laufen lassen spielen Sie auch einmal mit dem Fenster. Beobachten Sie wann eine WM_PAINT Nachricht ausgelöst wird und wann nicht.

Kommentieren Sie zu Versuchszwecken die beiden Aufrufe von BeginPaint(...) und EndPaint(...) einmal aus. Wenn Sie das Programm erneut starten, werden Sie laufend WM_PAINT Nachrichten empfangen. Warum? Nun, erst durch den Aufruf von EndPaint(...) wird der Fensterinhalt wieder als gültig gekennzeichnet. Und solange Sie dies nicht tun sendet WINDOWS ständig weitere WM_PAINT Nachrichten an das Fenster damit es seinen Inhalt als gültig markieren kann.

Noch eine kleine Frage am Rande: Wenn das Fenster beim Auskommentieren von BeginPaint(...) und EndPaint(...) ständig WM_PAINT Nachrichten erhält, warum kann es dennoch geschlossen werden, d.h. warum erhält das Fenster trotzdem eine WM_CLOSE bzw. WM_DESTROY Nachricht? Der Grund dafür ist, dass WINDOWS Nachrichten priorisiert, und die WM_PAINT Nachricht hat eine relativ niedrige Priorität. Solange das Fenster noch andere Nachrichten zu verarbeiten hat wird die WM_PAINT Nachricht ganz einfach zurückgehalten.

Und zum Schluss noch ein ganz wichtiger Hinweis:

ACHTUNG! Setzen Sie NIEMALS innerhalb des Bearbeiters für die WM_PAINT Nachricht mit dem Debugger einen Breakpoint. Läuft der Debugger nämlich auf diesen Breakpoint und hält das Programm an, so wird das Debugger-Fenster in den Vordergrund gebracht. Dadurch wird aber der Fensterinhalt des zu untersuchenden Programms sofort wieder ungültig und das Fensters erhält umgehend eine weitere WM_PAINT zugesandt.
Das gleiche gilt übrigens auch wenn Sie im Verarbeitungszweig der WM_PAINT Nachricht versuchen eine Messagebox darzustellen.

Im nächsten und letzten Praxisschritt in diesem Kapitel werden wir uns noch ansehen was beim Verändern der Fenstergröße so alles passiert.

Zurück Zum Inhaltsverzeichnis Weiter


Copyright © 2004

Senden Sie Emails mit Fragen oder Kommentaren zu dieser Website an: mailto:info@cpp-tutor.de
 Wolfgang Schröder, Lerchenweg 23, D-72805 Lichtenstein. Tel: +49 7129 6470