Verhindern, dass Fenster Größe ändert bei Ziehen an Bildschirmrand

    • Offizieller Beitrag

    Hi,

    ich möchte verhindern, dass ein Fenster seine Größe ändert bei folgenden Aktionen:

    • an Titelleiste greifen - an den seitlichen Desktoprand ziehen (Fenster bekommt halbe Bildschirmgröße, dockt am seitlichen Rand an)
    • an oberen/unteren Fensterrand greifen - an den oberen/unteren Desktoprand ziehen (Fenster bekommt volle Bildschirmhöhe)
    • Doppelklick Titel (Fenster wird maximiert) - das habe ich gelöst durch Auswertung: $_iMsg = $WM_NCLBUTTONDBLCLK And $_iwParam = $HTCAPTION

    Leider friert mein Winspector Spy beim Loggen von Messages ein, sodass ich das nicht nachverfolgen kann.

    Ich habe getestet, ob es eine Kombination mit WM_NCLBUTTONDOWN ist. Dass die Maustaste gedrückt ist am Fensterrand (zum Ziehen) kann ich damit auch erkennen. Nun fehlt mir aber der nächste Schritt. Die oben angeführten Ereignisse treten ja erst auf, wenn mit der gezogenen Maus der Bildschirmrand berührt wird. Ich kann mir nicht vorstellen, dass ich hier permanent berechnen muss, ob Mausposition mit Bildschirmrand übereinstimmt. Da sollte doch eigentlich eine Nachricht gesendet werden mit den Infos: Mouse hold-down moved-to Border (links,rechts,oben,unten).

    Bin für Anregungen dankbar.


    EDIT:

    Ich habe mal aus meinem Projekt den Code in ein einzelnes minimales Skript gezogen, zum besseren Verständnis:

  • Kannst du nicht mit Events arbeiten?

    Und es gibt noch einen weiteren unbedachten Fall bei dir:

    Wenn du ein Fenster in der Größe änderst und dann nach ganz oben oder unten kommst, wird das Fenster auf die Volle Bildschirmgröße angepasst. Soll das auch verhindert werden?

    1. Fenstergröße (defaultwerte) generell zwischenspeichern
    2. Wenn $GUI_EVENT_RESIZED triggert + Mausposition ganz oben oder ganz unten => Fenstergröße auf alten Wert zurück
    3. Wenn $GUI_EVENT_RESIZED triggert + Mausposition ganz rechts oder ganz links => Fenstergröße auf alten Wert zurück
    4. Wenn $GUI_EVENT_RESIZED triggert + keine der oberen Fälle passt => neue Fenstergröße speichern

    https://www.autoitscript.com/autoit3/docs/f…ISetOnEvent.htm

    Nachteil: Man sieht das ändern der Fenstergröße.

    Einmal editiert, zuletzt von Moombas (6. November 2020 um 15:01)

    • Offizieller Beitrag

    Das hast du falsch verstanden. Normale Größenänderung ist selbstverständlich erlaubt.

    Ich verwalte die Fenster und Messages sowieso in eigener Window-Procedure. Ich möchte aber die 3 oben genannten Ereignisse verhindern. Auf Danach-Events zuzugreifen ist auch kein guter Weg. Die von mir erlaubte Größenänderung in gesetzten Grenzen (minSize, maxSize) beeinflusse ich bevor sie passiert (WM_SIZING).

    Denn wenn ich für ein Fenster eine maximale Größe definiere, ist ein Maximize fehl am Platz, ebenso die Änderung auf halben Bildschirm oder volle Höhe.

  • Noch eine kleine Anmerkung am Rande:
    Wenn du manuell die entsprechenden Mouse-Events abfängst, solltest du evtl. beachten, dass man den gleichen Effekt mit den Tastenkombinationen Win+Pfeiltaste ebenfalls erreicht. Ein reines Abfragen von Mouse-Events könnte also je nach genauer Zielstellung nicht ausreichen.

    • Offizieller Beitrag

    Ich würde die Minimale/Maximale größe des Fensters mit WM_GETMINMAXINFO begrenzen.

    Das schaut schonmal ganz gut aus. Da muss ich jetzt nur noch eine Änderung der Position verhindern. Momentan springt das Fenster an den Wert, den es hätte - aber aufgrund der unterdrückten Größenänderung nicht einnehmen darf.

    Naja, ist eine Windowseinstellung. Das ist in einem Programm nicht von Nutzen.

    Wenn du manuell die entsprechenden Mouse-Events abfängst, solltest du evtl. beachten, dass man den gleichen Effekt mit den Tastenkombinationen Win+Pfeiltaste ebenfalls erreicht. Ein reines Abfragen von Mouse-Events könnte also je nach genauer Zielstellung nicht ausreichen.

    Ja, leider. Windows weist da keinerlei Konsistenz auf. Eigentlich könnte man erwarten, dass ein gleiches Ergebnis auch eine identisch WM_ als Basis hat. Aber leider....

    Bill Gates wird sicher sagen: It's not a bug - it's a feature.

  • Hier steht etwas von einem Event für WinProc (SC_MOVE), welches das verschieben verhindert, falls es nicht weitergegeben wird.

    https://stackoverflow.com/questions/9078…rom-being-moved

    Es gehört zum gleichen Typ, wie WM_NCLBUTTONDOWN, was du ja schon verarbeitest.

    Wenn man dann schaut, ob das Fesnter in eine der Ecken verschoben wird und dabei mehrere Pixel springt könnte man das verhindern.

    Ist aber zugegebenermaßen nicht die schönste Methode.

  • Ich weiß nicht ob das Hilft, aber bei Fenstern "selbstgebauter Titelleiste" (also z.B. Labels mit NCHITTEST zum Bewegen, eigene Buttons, etc) passiert keines dieser Events (allerdings werden wahrscheinlich auch nützliche Events verschluckt).

    Falls dein Fenster also keine Menuzeile hat (die ist sonst ganz oben, wobeeeeei, die kann man doch bestimmt als Pseudotitelleiste missbrauchen, wenn man ihren Grafikpuffer geschickt übermalt :D), kannst du via WS_POPUP ein "nacktes" Fenster erzeugen und die von dir gewünschten zulässigen Events (Resize wenn der User es will, Minimieren, Maximieren, Exit, Verschieben, etc) manuell verarbeiten.

    Kann gut sein, dass das viel zu viel arbeit ist, ist nur eine Überlegung :)

    lg

    M

  • Hallo BugFix,

    die WM_MOVING wird beim ziehen der Titelleiste gesendet und Du kannst über die RECT Struktur die Position des Fensters prüfen und ändern.

    WM_MOVING message

    Die WM_SIZING wird nur gesendet, wenn der Rahmen gezogen wird, bzw. die Größe geändert wird.

    Edit: Ich benutze meist die WM_WINDOWPOSCHANGING um die Fensterposition und -größe zu kontrollieren, aber cih denke die WM_MOVING ist in diesem Fall vllt besser geeignet.


    LG

    Greenhorn


    Einmal editiert, zuletzt von Greenhorn (7. November 2020 um 23:33)

    • Offizieller Beitrag

    steht etwas von einem Event für WinProc (SC_MOVE),

    Im Moment lasse ich WM_GETMINMAXINFO aussen vor, wo das evtl. den Positionssprung anzeigen könnte. Vielleicht komme ich nochmal drauf zurück.

    Falls dein Fenster also keine Menuzeile hat (die ist sonst ganz oben, wobeeeeei, die kann man doch bestimmt als Pseudotitelleiste missbrauchen, wenn man ihren Grafikpuffer geschickt übermalt :D), kannst du via WS_POPUP ein "nacktes" Fenster erzeugen und die von dir gewünschten zulässigen Events (Resize wenn der User es will, Minimieren, Maximieren, Exit, Verschieben, etc) manuell verarbeiten.

    Mein Ziel ist kein individuelles Fenster, sondern geplant ist eine Anwendung für beliebige Fenster.

    die WM_MOVING wird beim ziehen der Titelleiste gesendet

    Ja, auch das muss überwacht werden mit entsprechender Kollision am Bildschirmrand.

    Die WM_SIZING wird nur gesendet, wenn der Rahmen gezogen wird, bzw. die Größe geändert wird.

    Das ist wesentlicher Bestandteil, da es in meinem geplanten Projekt ein möglicher Style des genutzten Fensters ist. Somit möchte ich da auch volle Funktionalität haben.

    WM_WINDOWPOSCHANGING

    Das scheint wohl die sinnvollste Variante zu sein, um einen Kollisionscheck (mit Bildschirmrand) dauerhaft zu implementieren..


    Ich habe in Post 1 eine Kurzversion eines Skriptes gestellt, dass mein Vorgehen zeigt.

    • Offizieller Beitrag

    Ich benutze meist die WM_WINDOWPOSCHANGING

    Ich habe das jetzt mal eingebunden. Damit werden tatsächlich alle Szenarien (auch Tastatur!) abgedeckt. :thumbup:

    Alleine führt es aber nicht zum Ziel. Der Doppelklick auf die Titelleiste und Klick auf Maximize Button müssen separat abgefangen werden. WM_WINDOWPOSCHANGING verhindert sonst zwar die Größenänderung (Maxwerte werden gesetzt), danach ist das Fenster aber "eingefroren" und muss mit einem MOVE wieder freigegeben werden - dann springt aber die Größe auf den Zeitpunkt vor WM_WINDOWPOSCHANGING. Und dasselbe passiert bei Maximize per Tastatur (Win+Up).

    Fehlt mir also noch eine saubere Lösung für Maximize per Tastatur.

    Hier das Skript:

  • Hi BugFix,

    ich habe festgestellt, dass bei Win+Up in der WINDOWPOS Struktur das Flag 0x00008000 gesetzt ist. Dies scheint ein undokumentiertes Flag zu sein.

    Code
    If $_iMsg = $WM_WINDOWPOSCHANGING Then
        ; ...
        If (BitAND($tWINDOWPOS.flags, 0x00008000)) Then _
            GUISetState(@SW_RESTORE)        ; This does the trick...
    
        Return 0 ; avoid default window processing

    LG

    Greenhorn


    • Offizieller Beitrag

    ich habe festgestellt, dass bei Win+Up in der WINDOWPOS Struktur das Flag 0x00008000 gesetzt ist. Dies scheint ein undokumentiertes Flag zu sein.

    Da habe ich mal in der Richtung gesucht, es gibt sogar 3 undokumentierte Flags: 0x8000, 0x1000 and 0x0800 - aber eine Erklärung dafür hat keiner so richtig.

    Ich habe jetzt kurzerhand definiert:

    Local Const $SWP_FROZENWINDOW = 0x8000

    und angewendet dann:

    If (BitAND($tWINDOWPOS.flags, $SWP_FROZENWINDOW)) Then _WinAPI_ShowWindow($_hWnd, @SW_RESTORE)

    :thumbup: Danke für den Hinweis. Damit kann ich die anderen Messages außen vorlassen und brauch nur WM_WINDOWPOSCHANGING prüfen.

  • BugFix 12. November 2020 um 11:58

    Hat das Label von [ offen ] auf [ gelöst ] geändert.
    • Offizieller Beitrag

    Schiebst du dann bitte noch eine korrigierte, bzw. finale Version hoch - danke!

    Hier zwei Varianten: