Jump to content

How to drag GUI window around but prevent it from moving outside of a parent window


graydwarf
 Share

Recommended Posts

I'm looking for a way that my users can drag a child window (dialog) around while preventing it from leaving (rendering outside) the parent window. Attached is a mockup showing what I mean. 

- The child window needs to be sizeable. The way I have it now is the user can resize the window via grab handle.

- The child window has an input box that resizes with the child window.

- The child window is a typical tools dialog that has a title and close button.

- The end solution ideally prevents the child window from going outside the parent window border at all. My mockup suggests it could but I'd rather it didn't.

Before I start digging into repositioning the child window based on mouse (drag/resize) events, I was hoping there was a simple way to do this using GUI/Control Styles. Any help with this would be much appreciated.

post-69172-0-30562100-1424629276_thumb.p

Link to comment
Share on other sites

  • Moderators

graydwarf,

Something like this looks as if it might fit most of the bill: :)

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinApi.au3>

Const $SC_MOVE = 0xF010
Global $hChild, $bChildMax = False

$hMain = GUICreate("Parent", 500, 500)
GUICtrlCreateLabel("", 0, 0, 0, 0) ; You need this
$mMain = GUICtrlCreateMenu("New")
$mChild = GUICtrlCreateMenuItem("Child", $mMain)
GUISetState(@SW_SHOW)

; Prevent maximised child being moved
GUIRegisterMsg($WM_SYSCOMMAND, "On_WM_SYSCOMMAND")

While 1
    ; Use advanced GUIGetMsg to distinguish between windows
    $aMsg = GUIGetMsg(1)
    Switch $aMsg[1]
        ; It is the parent
        Case $hMain
            ; Now check the message
            Switch $aMsg[0]
                Case $GUI_EVENT_CLOSE
                    Exit
                Case $mChild
                    ; Deactivate menu
                    GUICtrlSetState($mChild, $GUI_DISABLE)
                    ; Create child
                    $hChild = GUICreate("Child", 300, 300, 10, 0, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX))
                    ; Set as child
                    _WinAPI_SetParent($hChild, $hMain)
                    GUISetState()
            EndSwitch
            ; Must be the child
        Case Else
            Switch $aMsg[0]
                Case $GUI_EVENT_CLOSE
                    ; Activate menu
                    GUICtrlSetState($mChild, $GUI_ENABLE)
                    ; Clear the Maximised flag
                    $bChildMax = False
                    ; Delete child
                    GUIDelete($hChild)
                Case $GUI_EVENT_MAXIMIZE
                    ; Set the Maximised flag
                    $bChildMax = True
                Case $GUI_EVENT_MINIMIZE
                    ; Clear the Maximised flag
                    $bChildMax = False
                Case $GUI_EVENT_RESTORE
                    ; Clear the Maximised flag
                    $bChildMax = False
            EndSwitch
    EndSwitch
WEnd

Func On_WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)

    If $hWnd = $hChild Then
        ; Is the child maximised?
        If $bChildMax Then
            ;Is it a MOVE mesage?
            If BitAND($wParam, 0xFFF0) = $SC_MOVE Then Return False
        EndIf
    EndIf

    Return $GUI_RUNDEFMSG
EndFunc   ;==>On_WM_SYSCOMMAND

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

graydwarf,

Something like this looks as if it might fit most of the bill: :)

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinApi.au3>

Const $SC_MOVE = 0xF010
Global $hChild, $bChildMax = False

$hMain = GUICreate("Parent", 500, 500)
GUICtrlCreateLabel("", 0, 0, 0, 0) ; You need this
$mMain = GUICtrlCreateMenu("New")
$mChild = GUICtrlCreateMenuItem("Child", $mMain)
GUISetState(@SW_SHOW)

; Prevent maximised child being moved
GUIRegisterMsg($WM_SYSCOMMAND, "On_WM_SYSCOMMAND")

While 1
    ; Use advanced GUIGetMsg to distinguish between windows
    $aMsg = GUIGetMsg(1)
    Switch $aMsg[1]
        ; It is the parent
        Case $hMain
            ; Now check the message
            Switch $aMsg[0]
                Case $GUI_EVENT_CLOSE
                    Exit
                Case $mChild
                    ; Deactivate menu
                    GUICtrlSetState($mChild, $GUI_DISABLE)
                    ; Create child
                    $hChild = GUICreate("Child", 300, 300, 10, 0, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX))
                    ; Set as child
                    _WinAPI_SetParent($hChild, $hMain)
                    GUISetState()
            EndSwitch
            ; Must be the child
        Case Else
            Switch $aMsg[0]
                Case $GUI_EVENT_CLOSE
                    ; Activate menu
                    GUICtrlSetState($mChild, $GUI_ENABLE)
                    ; Clear the Maximised flag
                    $bChildMax = False
                    ; Delete child
                    GUIDelete($hChild)
                Case $GUI_EVENT_MAXIMIZE
                    ; Set the Maximised flag
                    $bChildMax = True
                Case $GUI_EVENT_MINIMIZE
                    ; Clear the Maximised flag
                    $bChildMax = False
                Case $GUI_EVENT_RESTORE
                    ; Clear the Maximised flag
                    $bChildMax = False
            EndSwitch
    EndSwitch
WEnd

Func On_WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)

    If $hWnd = $hChild Then
        ; Is the child maximised?
        If $bChildMax Then
            ;Is it a MOVE mesage?
            If BitAND($wParam, 0xFFF0) = $SC_MOVE Then Return False
        EndIf
    EndIf

    Return $GUI_RUNDEFMSG
EndFunc   ;==>On_WM_SYSCOMMAND

 

That gets me real close. Thanks for providing it. I do have a bit of a rendering problem though that I don't see in the example you provided. The child window doesn't paint on initial render and it doesn't repaint on drag. If I click on another window or the parent window, suddenly the child window paints (usually). Any ideas? I'm digging through the help file looking for anything that would help me repaint but no luck so far.

Link to comment
Share on other sites

  • Moderators

graydwarf,

No ideas sorry. I just run a boring no-frills theme and it (re)paints fine for me. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

The demo paints fine and it's nearly the same code except I've got some other controls on my parent window. I tried changing my window theme to classic and I still get the same behavior. 

The only code that's needed to create the "embedded" child window is this:

_WinAPI_SetParent($g_SpeechBubbleWindow, $g_SnapShotWindow) 

Couple good things are coming from this. 

- Learning that I can place all my GUI msg's in a single loop instead of per GUI which will simplify some things for me.

- I've been using Aero theme for a long time and dealing with the transparent title bar frustrations without realizing it all this time. Switching to Win7 Classic for the win.

Anyway, I'll start ripping stuff out until I figure out what's causing it.

Thanks.

Link to comment
Share on other sites

Yeah, here we go. All you need to do is add a picture control to the parent page and suddenly the child window won't render properly. Add this to the global declarations of that sample code and point it at a valid image to repro.

Global $g_idPictureControl = GUICtrlCreatePic (@WorkingDir & "\Scenarios\BYOND\Images\snapshot_21_02_2015_17_15_50.jpg", 0, 0, 0, 0)
Link to comment
Share on other sites

I just changed the image size to 100,100 and now the rendering issue for the child dialog is only where the 100x100 image rendered underneath it. The rest of the child dialog rendered fine. So, windows/autoit is confused about what to repaint in this scenario. It's really weird actually because it seems to be doing a partial repaint which makes it almost seem like a timing issue for that region. 

Link to comment
Share on other sites

  • Moderators

graydwarf,

I have been adding controls to the parent and I see the same effect - trying to see if I can find a solution. :wacko:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Thank I found a solution. Still testing. Just add $WS_CLIPSIBLINGS to the styles. This explicitly calls out the very problem in the help file. 

*edit*

$WS_CLIPSIBLINGS - Help: "Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window."

Global $g_idPictureControl = GUICtrlCreatePic (@WorkingDir & "\Scenarios\BYOND\Images\snapshot_21_02_2015_17_15_50.jpg", 0, 0, 100, 100, $WS_CLIPSIBLINGS)
Edited by graydwarf
Link to comment
Share on other sites

  • Moderators

graydwarf,

Got there at the same time as you - "great minds", as they say! :D

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Yeah, thanks for getting me there. 

*edit*

For anyone else coming across this issue, important to note that using 'WS_CLIPSIBLINGS' in the above scenario might interfere with your ability to interact with the picture control. I'm no longer getting GUI event messages when clicking on the image. Still troubleshooting.

Edited by graydwarf
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...