Jump to content

Scrollable area and resizing


mpower
 Share

Recommended Posts

Hi guys, I have a GUI which requires scrolling, however resizing is a bit of a problem because any time you scroll down/up and then resize, the controls move down/up and blank space is created within the scrollable area. 

Any help with maintaining scrollable area size to be fixed would be great.

Here is a reproducer:

To achieve the undesirable effect I described, simply run the script, scroll down and then resize window. You will notice that new blank space is created either on top or on bottom of the window depending on scrolling/resizing direction. Easiest way to see how bad it is, is to scroll down the page about half-way and then maximise the window. You will notice now a whole bunch of blank space is added to the top of the window and scrolling up simply shows nothing, scrolling down shows controls but they are cut off because of the blank space created on top of the page.

This is all happening within the yellow bg  child gui. I need to make it so that even if the GUI is resized the contents of the yellow bg child gui do not move and the scrollable area within the child gui remains the same.

#NoTrayIcon
#include-once
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIScroll.au3>
#include <SendMessage.au3>
Opt("GUIResizeMode", 802)

Global $parentgui_w = 880, $parentgui_h = 810, $childgui_w = $parentgui_w - 2, $childgui_h = $parentgui_h - 292

$parentgui = GUICreate("Scrollbar resize problem", $parentgui_w, $parentgui_h, -1, -1, BitOR($WS_MINIMIZEBOX, $WS_MAXIMIZEBOX, $WS_SIZEBOX))
GUISetBkColor(0xFFFFFF, $parentgui)

$childgui = GUICreate("", $childgui_w, $childgui_h, -5, 263, $WS_POPUP, $WS_EX_MDICHILD, $parentgui)
GUISetBkColor(0xFFF123, $childgui)
Dim $buttons[25]

For $i = 0 to 24
    If $i > 0 Then
        $cPos = ControlGetPos($childgui, "", $buttons[$i - 1])
        $buttons[$i] = GUICtrlCreateButton("Button " & $i + 1, ($childgui_w - 200) / 2, $cPos[1] + $cPos[3] + 50, 200, 80)
    Else
        $buttons[$i] = GUICtrlCreateButton("Button " & $i + 1, ($childgui_w - 200) / 2, 20, 200, 80)
    EndIf
Next

Scrollbar_Create($childgui, $SB_VERT, 130 * 25)
Scrollbar_Step(15, $childgui, $SB_VERT)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")
GUIRegisterMsg($WM_NCACTIVATE, "WM_NCACTIVATE")
GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL")

GUISetState(@SW_SHOW, $parentgui)
GUISetState(@SW_SHOWNOACTIVATE, $childgui)

While 1
    $msg = GUIGetMsg(1)
    Switch $msg[1]
        Case $parentgui
            Switch $msg[0]
                Case $GUI_EVENT_CLOSE
                    Exit
                Case $GUI_EVENT_RESTORE
                    $pPos = WinGetPos($parentgui)
                    WinMove($parentgui, "", Default, Default, $pPos[2]+1, $pPos[3]+1)
                    WinMove($parentgui, "", Default, Default, $pPos[2]-1, $pPos[3]-1)
            EndSwitch
    EndSwitch
WEnd

Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam)
    Local $iMw = BitShift($wParam, 16)
    $scroll_lines = 5

    If $iMw > 0 Then
        For $i = 0 to $scroll_lines
            _SendMessage($childgui, $WM_VSCROLL, $SB_LINEUP)
        Next
    Else
        For $i = 0 to $scroll_lines
            _SendMessage($childgui, $WM_VSCROLL, $SB_LINEDOWN)
        Next
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc

Func WM_SIZE($hwnd, $uMsg, $wParam, $lParam)
    If $hwnd = $parentgui Then
        $wPos = WinGetPos($parentgui)
        $pgui_wdiff = ($wPos[2] - $parentgui_w) / 2
        $pgui_hdiff = ($wPos[3] - $parentgui_h) / 2
        If $pgui_wdiff > 7 Then
            If $pgui_hdiff <> 0 Then
                If $wPos[2] > $parentgui_w Then
                    WinMove($childgui, "", $wPos[0] + 2 + $pgui_wdiff, Default, $parentgui_w - 2, $wPos[3] - 306)
                Else
                    WinMove($childgui, "", $wPos[0] + 2 + $pgui_wdiff, Default, $wPos[2] - 16, $wPos[3] - 306)
                EndIf
            Else
                WinMove($childgui, "", $wPos[0] + 2 + $pgui_wdiff, Default)
            EndIf
        ElseIf $pgui_wdiff < 7 Then
            If $wPos[0] <> -32000 Then
                WinMove($childgui, "", $wPos[0] + 8, Default, $wPos[2] - 16, $wPos[3] - 306)
            EndIf
        ElseIf $pgui_hdiff > 42 Then
            WinMove($childgui, "", Default, Default, Default, $wPos[3] - 306)
        EndIf
    EndIf
    Return 0
EndFunc

Func WM_NCACTIVATE($hwnd, $imsg, $wparam)
    If $hwnd = $parentgui Then
        If NOT $wparam Then Return 1
    EndIf
    Return $gui_rundefmsg
EndFunc

 

Edited by mpower
Link to comment
Share on other sites

I'd recommend getting the dialog metrics for the system so you can make your child fit a little better.

Func GetDialogMetrics()
    Local $tStruct = DllStructCreate("struct;long caption;long xBorder;long yBorder;long xDlgFrame;long yDlgFrame;endstruct")
    For $iSysMetric = $SM_CYCAPTION To $SM_CYDLGFRAME
        DllStructSetData($tStruct, $iSysMetric - $SM_CYCAPTION + 1, _WinAPI_GetSystemMetrics($iSysMetric))
    Next
    Return $tStruct
EndFunc   ;==>GetDialogMetrics

As for the sizing, you can get the new width and height of the main gui using the lParam from the WM_SIZE function

Func WM_SIZE($hwnd, $uMsg, $wParam, $lParam)
    Local $iWidth = _WinAPI_LoWord($lParam)
    Local $iHeight = _WinAPI_HiWord($lParam)

    If $hwnd = $parentgui Then
        WinMove($childgui, "", x, y, $iWidth - 2, $iHeight - 292)
    EndIf
    Return 0
EndFunc

Also, if you use _WinApi_SetParent you can make your child GUI a real mdi child gui, so it's drawn inside the parent. It will get rid of that nasty effect where the child and parent minimize separately.

Link to comment
Share on other sites

49 minutes ago, InunoTaishou said:

I'd recommend getting the dialog metrics for the system so you can make your child fit a little better.

Func GetDialogMetrics()
    Local $tStruct = DllStructCreate("struct;long caption;long xBorder;long yBorder;long xDlgFrame;long yDlgFrame;endstruct")
    For $iSysMetric = $SM_CYCAPTION To $SM_CYDLGFRAME
        DllStructSetData($tStruct, $iSysMetric - $SM_CYCAPTION + 1, _WinAPI_GetSystemMetrics($iSysMetric))
    Next
    Return $tStruct
EndFunc   ;==>GetDialogMetrics

As for the sizing, you can get the new width and height of the main gui using the lParam from the WM_SIZE function

Func WM_SIZE($hwnd, $uMsg, $wParam, $lParam)
    Local $iWidth = _WinAPI_LoWord($lParam)
    Local $iHeight = _WinAPI_HiWord($lParam)

    If $hwnd = $parentgui Then
        WinMove($childgui, "", x, y, $iWidth - 2, $iHeight - 292)
    EndIf
    Return 0
EndFunc

Also, if you use _WinApi_SetParent you can make your child GUI a real mdi child gui, so it's drawn inside the parent. It will get rid of that nasty effect where the child and parent minimize separately.

Thanks for these! I will take this into account, especially _WinApi_SetParent. 

Scrollbar issues still persists though :(

 

EDIT: Hmm I tried using _WinApi_SetParent($childgui, $parentgui) however its not working correctly :(

Edited by mpower
Link to comment
Share on other sites

  • 2 weeks later...

Does anyone know of an effective way of dealing with the issue of scrollable area when resizing? Is there a way to perhaps retain the scroll position, resize the gui and adjust the scrollable area to fit the new window size?

Link to comment
Share on other sites

So the only solution I've been able to come up with is to set the vertical scroll position to 0 when resizing. Whilst its not very good for user experience, it does negate the blank white space that would be padded to the top of the gui and end up cutting of controls further down below.

If anyone does come up with a better solution I'd be super keen to see it! :)

 

P.S. Here's the updated WM_SIZE function with the scroll to top line added:

Func WM_SIZE($hwnd, $uMsg, $wParam, $lParam)
    Local $iWidth = _WinAPI_LoWord($lParam)
    Local $iHeight = _WinAPI_HiWord($lParam)

    If $hwnd = $parentgui Then
        Scrollbar_Scroll($childgui, $SB_VERT, 0)
        WinMove($childgui, "", Default, Default, $iWidth - 2, $iHeight - 292)
    EndIf
    Return 0
EndFunc

 

Edited by mpower
Link to comment
Share on other sites

  • Moderators

mpower,

Quote

the only solution I've been able to come up with is to set the vertical scroll position to 0 when resizing

That was my conclusion too - see GUIScrollBars_Ex_Example_5 in my Scrollbars UDF (the link is in my sig). The _Scrollbars_WM_ENTER/EXITSIZEMOVE functions in the main UDF do all the work.

M23

Edited by Melba23
Fixed formatting

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

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

×
×
  • Create New...