Fensterstil und -größe während der Laufzeit ändern
-
Das Ändern der Stile WS_CHILD, WS_OVERLAPPED und WS_POPUP ist massiv. Aber wenn es geht ist es eigentlich erlaubt. Manche Stile lassen sich nicht mehr ändern nach dem Anlegen des Fensters.
Wenn das Hide/Show Dein Problem löst würde ich das einfach so einbauen.
Optisch dürfte das kaum auffallen.
-
Naja, das Fenster flackert vielleicht einmal kurz und in der Taskleiste sieht man natürlich auch das Fenster erst verschwindet und anschließend wieder auftaucht, aber da es hier um einen Wechsel von Fenster- auf Vollbildmodus bei einer Direct3D-Anwendung geht, sollte das kein so großes Problem sein

-
Unter welcher Version arbeitet ihr? Bei mir macht oben geschriebener Vorschlag unter XP SP 3 keinerlei Probleme. Unter Win 7 habe ich es heute morgen nicht getestet.
-
Hier läuft ebenfalls XP mit SP3. Allerdings veränderst du in deinem Beispiel auch ausschließlich den Stil des Fensters, nicht jedoch Größe oder Position. Somit wird die neue Variante des Fensters natürlich exakt über die alte gezeichnet und man kann von letzterer dann natürlich auch keine Reste mehr sehen, da diese ja vollständig überzeichnet werden.
~Im Übrigen muss ich in deinem Beispiel auch noch ein SWP_SHOWWINDOW zu den Flags anfügen (oder wahlweise anschließend ShowWindow(hwnd, SW_SHOW); aufrufen), um das "neue" Fenster überhaupt sehen zu können.~
-
Ich habe gerade nachgeschaut, wie ich es einmal mit meinem MDI-Client gemacht habe, dort ist auch erst einmal ein Aufruf von ShowWindow(hwnd,SW_HIDE) zu finden. Scheint wirklich die einzige Möglichkeit zu sein, damals habe ich _einige_ Zeit damit verbracht, eine Lösung zu finden. Bei Child-Fenstern fällt es natürlich nicht so auf.
-
Gerade habe ich noch einmal etwas rumgespielt, und, siehe da...
void ToggleWndStyle(HWND hwnd, const RECT* prcSWNormal) { LONG_PTR dw = GetWindowLongPtr(hwnd,GWL_STYLE); RECT rc; if(dw & WS_POPUP) { dw &= ~(WS_POPUP|WS_MAXIMIZE|WS_THICKFRAME); dw |= WS_OVERLAPPEDWINDOW; rc = *prcSWNormal; } else { dw &= ~(WS_OVERLAPPEDWINDOW); dw |= (WS_POPUP|WS_MAXIMIZE|WS_THICKFRAME); SetRect(&rc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); SetMenu(hwnd,NULL); } SetWindowLongPtr(hwnd, GWL_STYLE, dw); SetWindowPos(hwnd, HWND_TOP,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,SWP_FRAMECHANGED|SWP_DRAWFRAME); }...läuft.
prcSWNormal wird natürlich nur benötigt bei einem Wechsel WS_POPUP->WS_OVERLAPPEDWINDOW
-
Ich weiß wirklich nicht, weshalb bei dir keine Reste übrig bleiben. Wenn ich es bei mir so versuche, tritt immer das beschriebene Problem auf. Könntest du vielleicht die Größenänderung so lassen, jedoch die Styles einfach mal ohne diese vielen Bitoperationen setzen? So stelle ich mir den Code dann etwa vor:
void ToggleWndStyle(HWND hwnd, const RECT* prcSWNormal) { LONG_PTR dw = GetWindowLongPtr(hwnd,GWL_STYLE); RECT rc; if(dw & WS_POPUP) { dw = WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX); rc = *prcSWNormal; } else { dw = WS_POPUP; SetRect(&rc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); SetMenu(hwnd,NULL); } SetWindowLongPtr(hwnd, GWL_STYLE, dw); SetWindowPos(hwnd, HWND_TOP,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,SWP_FRAMECHANGED|SWP_DRAWFRAME); }
-
Hast du den Code 1:1 kopiert und ausgeführt? Das Problem ist evtl., dass du eine 3D - Vollbildanwendung wiederherstellen und anschließend maximieren möchtest.
Zu den Bitoperationen:
Bei einer Zuweisung an dw (dw=...) löschst du ja auch bestehende Styles (WS_VISIBLE , WS_BORDER etc.). Dies wird eben dadurch verhindert.
Statt dw = dw | WS_POPUP kannst du eben dw|=WS_POPUP schreiben. Ist viel kürzer und man gewöhnt sich sehr schnell daran.
Probier das Ganze mal mit einem normalen Fenster aus. Hast du dann immer noch Probleme?
-
Das mit den Kurzformen der Operatoren usw. ist mir schon klar
Auch, dass du durch die Bitoperationen andere gesetzt Flags behalten wolltest. Ich bin aber davon ausgegangen, dass gar keine weiteren Flags gesetzt sind und somit eben auch eine einfache Zuweisung reicht. Das kommt natürlich darauf an, mit welchen Flags du dein Fenster zu Beginn erstellt hast. Ich habe z.B. CreateWindowEx() die Flags WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX) übergeben und möchte eben genau zwischen diesem verknüpften Stil und WS_POPUP wechseln, daher wäre bei mir dann auch eine reine Zuweisung ausreichend.Was aber viel wichtiger ist: Du hast mein Problem gelöst
Ich habe aus diesem Code:case WM_LBUTTONUP: SetWindowLongPtr(hWnd_, GWL_STYLE, WS_POPUP); SetWindowPos(hWnd_, HWND_TOP, 100, 100, 320, 240, SWP_FRAMECHANGED | SWP_SHOWWINDOW); break; case WM_RBUTTONUP: SetWindowLongPtr(hWnd_, GWL_STYLE, WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)); SetWindowPos(hWnd_, HWND_TOP, 100, 100, 640, 480, SWP_FRAMECHANGED | SWP_SHOWWINDOW); break;diesen hier gemacht:
case WM_LBUTTONUP: SetWindowLongPtr(hWnd_, GWL_STYLE, WS_VISIBLE | WS_POPUP); SetWindowPos(hWnd_, HWND_TOP, 100, 100, 320, 240, SWP_FRAMECHANGED); break; case WM_RBUTTONUP: SetWindowLongPtr(hWnd_, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)); SetWindowPos(hWnd_, HWND_TOP, 100, 100, 640, 480, SWP_FRAMECHANGED); break;Durch Hinzufügen von WS_VISIBLE klappt plötzlich alles, ein SWP_SHOWWINDOW bzw. ShowWindow() braucht man dann auch nicht mehr
Offensichtlich wird ein Fenster, dessen Stil WS_VISIBLE nicht enthält, nicht korrekt bei einem Stil- und Größenwechsel gelöscht. Wo liegt denn dann überhaupt der Unterschied darin, WS_VISIBLE beim Erstellen eines Fensters direkt anzugeben oder nach dem Erstellen ShowWindow() aufzurufen? Setzt letztere Funktion nicht genau dieses Flag?
-
Das Flag WS_VISIBLE wird jeweils bei einem Aufruf von ShowWindow(..) gesetzt bzw. gelöscht.
Das Problem war wahrscheinlich das Flag SWP_SHOWWINDOW. Ich kann es mir nur so erklären, dass durch dieses Flag die alte Position verworfen und nur der neue Bereich des Fensters durch den Desktop-Manager aktualisiert wird. Naja, wie auch immer, es ist ja schön, dass du es geschafft hast.
PS.: Auch unter Windows 7 macht der Code genau das, was er tun soll.