Komplette Neuzeichnung des Fensters

JohnnyEnglish

Grünschnabel
Hallo!

Ich arbeite mit C, der Windows API und somit GDI. Ich zeichne direkt ins Fenster. Nun gibt es Benutzereingaben, welche eine komplette Neuzeichnung des Fensterinhalts bewirken sollten. Bei mir funktioniert das aber nicht.

Das meiste meines Codes ist in der Message-Loop:

Code:
WM_CREATE:

hDC = GetDC(mainWindow);
		
		statusFont = CreateFont(15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
				CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, NULL);
		SelectObject(hDC, statusFont);
		InvalidateRgn(mainWindow, NULL, FALSE);
		
		SetUpCoordinates();
		
		UpdateWindow(mainWindow);

Schon hier funktioniert UpdateWindow nicht. Er sendet nicht einmal ein WM_PAINT. Wenn ich anstelle von UpdateWindow() direkt zu WM_PAINT springe, macht er zwar meine Malanweisungen, auf dem Bildschirm tut sich aber auch nichts.

Einzig bei Resizes und Maximierungen zeichnet er alles neu.

Das funktioniert z. B. auch nicht:
Code:
case WM_KEYDOWN:
		switch(wParam)
		{
		case VK_F12:
			extendedView = !extendedView;
			SetUpCoordinates();
		}
		UpdateWindow(mainWindow);

Ich muss also immer die Fenstergrösse ändern, um auf dem aktuellen Stand zu sein.

Meine Nachrichtenschleife sieht so aus:

Code:
	MSG msg;
	
	MainWindow = CreateMainWin();
	
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			
		}
	}

Wie kann ich einen kompletten Repaint auch ohne Fenstergrössenänderung erzwingen?
WM_PAINT sieht übrigens ungefähr so aus:

Code:
BeginPaint(mainWindow, &ps);
		SetBkColor(hDC, RGB(200, 200, 200));
		SetTextColor(hDC, 0);
		SelectObject(hDC, CreateSolidBrush(RGB(200, 200, 0)));
		FillRect(hDC, &statusBar, CreateSolidBrush(RGB(200, 200, 200)));
EndPaint(mainWindow, &ps);
		break;
 
Code:
InvalidateRgn(mainWindow, NULL, FALSE);

Müsste an und für sich schon funktionieren...
Warum rufst du das in WM_CREATE auf?
Vor dem Anzeigen auf dem Screen wird WM_PAINT doch sowieso ausgeführt werden..


Übrigens.. es ist an und für sich eigentlich schöner, mit dem hWnd, dass du oben in der Callback als Parameter übergeben bekommen hast, zu arbeiten, statt mit einer globalen Variable..
Womöglich erweiterst du dein Programm irgendwann, so dass es mehrere Fenster haben kann... Eine globale Fenster-Variable ist selten nötig..

Das funktioniert z. B. auch nicht:
C++:
switch(wParam)
{
	case VK_F12:
		extendedView = !extendedView;
		SetUpCoordinates();
}
UpdateWindow(mainWindow);

Was soll das denn machen? (Wie sieht denn die SetUpCoordinates aus, oder funktioniert der Teil?)

Einen Repaint erzwingst du auch hier nicht, wenn du nicht InvalidateRgn/InvalidateRect aufrufst..

Im Prinzip solltest du InvalidateRect/Rgn aufrufen, wenn durch einen Prozessschritt der alte Fensterinhalt veraltet ist und ihn neu zu zeichnen zu viele Abhängigkeiten mit sich bringt, als dass du es "ad-hoc" schnell erledigen kannst...
 
Warum rufst du das in WM_CREATE auf?

Ich dachte, das gelte für immer. Anscheinend aber nur bis die nächste WM_PAINT eintrifft.

Was soll das denn machen? (Wie sieht denn die SetUpCoordinates aus, oder funktioniert der Teil?

SetUpCoordinates berechnet alle RECT-Strukturen neu. Und diese werden eben bei WM_PAINT ins Fenster gezeichnet. Bei F12 sieht das Fenster nachher ganz anders aus.
 
Übrigens, danke für deine Antwort, jetzt funktioniert es perfekt! Und einen letzten Fehler konnte ich eliminieren, indem ich mainWindow nur lokal brauche. Anscheinend ist dies nicht dasselbe Handle; das globale hatte bei GetClientRect() nicht die gewünschten Daten geliefert.
 
Und einen letzten Fehler konnte ich eliminieren, indem ich mainWindow nur lokal brauche. Anscheinend ist dies nicht dasselbe Handle; das globale hatte bei GetClientRect() nicht die gewünschten Daten geliefert.

Ja, wenn du das globale Handle in der WM_CREATE verwendest, ist das ein Fehler.
Weil die WM_CREATE wird noch in CreateWindow(Ex) gesendet. Das bedeutet, zu diesem Zeitpunkt ist dem globalen Handle noch gar kein Wert zugewiesen...
(hWnd = CreateWindowEx(...);)

Ich dachte, das gelte für immer. Anscheinend aber nur bis die nächste WM_PAINT eintrifft.

Hä.. :confused:
Wie meinst du das?
WM_CREATE wird nur einmal gesendet... wenn das Fenster erstellt wird..
Oder versteh ich dich falsch?
 
Hä.. :confused:
Wie meinst du das?
WM_CREATE wird nur einmal gesendet... wenn das Fenster erstellt wird..
Oder versteh ich dich falsch?

Ich dachte, InvalidateRgn setze den Bereich, der neugezeichnet wird, für immer. Aber im Laufe eines Programms wird das Fenster sicher mehrmals neugezeichnet. Also frufe ich InvalidateRgn bei jeder grösseren Fensterinhaltsänderung wieder neu auf.
 
Genau.

InvalidateRgn/Rect ist dafür gut, dass man Windows sozusagen mitteilen kann, welche Bereiche des Fensters ungültig geworden sind und neu gezeichnet werden müssen..
Tatsächlich gezeichnet werden diese Bereiche dann erst vom WM_PAINT handler..
Und auch nur diese Bereiche (dafür sorgst du mit deinem Aufruf von BeginPaint), das verhindert zu viele Neuzeichnungen von Bereichen, die gar nicht ungültig geworden sind, und damit flackern..

Nach der Zeichenoperation werden diese Bereiche dann wieder aus der Update-Region deines Fensters heraus genommen, weil sie ja wieder gültig geworden sind..
Wenn du dann als Programmierer weißt, da ist wieder ein Bereich ungültig geworden, rufst du InvalidateX auf..
 
Zurück