Jump to content
mpower

Scrollable area and resizing

Recommended Posts

mpower

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

Share this post


Link to post
Share on other sites
InunoTaishou

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.

Share this post


Link to post
Share on other sites
mpower
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

Share this post


Link to post
Share on other sites
mpower

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?

Share this post


Link to post
Share on other sites
mpower

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

Share this post


Link to post
Share on other sites
Melba23

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

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______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

 

Share this post


Link to post
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

  • Similar Content

    • therks
      By therks
      I'm trying to create a simple clock widget that automatically scales the text to the size of the window. I came up with the following method, but it doesn't work as well as I'd like. It especially has trouble scaling to the width of the window for some reason (in the example, try resizing the window to be narrow and tall).
      Does anyone have a better method?
      #include <Misc.au3> #include <WinAPIConv.au3> #include <GUIConstants.au3> #include <GDIPlus.au3> Opt('MustDeclareVars', 1) Global $_FONT_FAMILY = 'Arial', $_LB_TEXT Main() Func Main() _GDIPlus_Startup() Local $hGUI GUIRegisterMsg($WM_SIZE, WM_SIZE) $hGUI = GUICreate('', 300, 100, Default, Default, $WS_OVERLAPPEDWINDOW, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) $_LB_TEXT = GUICtrlCreateLabel('This is a string', 0, 0, 300, 100, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont($_LB_TEXT, _MeasureString($hGUI, GUICtrlRead($_LB_TEXT), $_FONT_FAMILY), 0, 0, $_FONT_FAMILY, 5) GUISetState() Local $iGM While 1 $iGM = GUIGetMsg() Switch $iGM Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd _GDIPlus_Shutdown() EndFunc Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) GUICtrlSetFont($_LB_TEXT, _MeasureString($hWnd, GUICtrlRead($_LB_TEXT), $_FONT_FAMILY), 0, 0, $_FONT_FAMILY, 5) EndFunc Func _MeasureString($hWnd, $sString, $sFont = 'Arial') Local $iError, $aSize, $hGraphic, $hFormat, $hFamily, $tLayout, $iFontSize, $hFont, $aInfo If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) EndIf $aSize = WinGetClientSize($hWnd) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd) $hFormat = _GDIPlus_StringFormatCreate() $hFamily = _GDIPlus_FontFamilyCreate($sFont) $tLayout = _GDIPlus_RectFCreate(0, 0, $aSize[0], $aSize[1]) $iFontSize = 0 Do If Not $hFamily Then $iError = 1 $iFontSize = 10 ExitLoop EndIf $iFontSize += 1 $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize, 0) $aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $sString, $hFont, $tLayout, $hFormat) _GDIPlus_FontDispose($hFont) If $aInfo[1] = 0 Then ExitLoop Until DllStructGetData($aInfo[0], 3) >= $aSize[0] Or DllStructGetData($aInfo[0], 4) >= $aSize[1] $iFontSize -= 1 _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_GraphicsDispose($hGraphic) Return SetError($iError, 0, $iFontSize) EndFunc
    • Ascer
      By Ascer
      Hello,
      Do you have any idea to resize Vector graphic using some maths trick?
      It's example to create Vector image 10x10px and write A
      Local $a10x10 = [ _ 1,1,1,1,1,1,1,1,1,1, _ 1,1,1,0,0,0,0,1,1,1, _ 1,1,0,0,1,1,0,0,1,1, _ 1,1,0,1,1,1,1,0,1,1, _ 1,1,0,1,1,1,1,0,1,1, _ 1,1,0,0,0,0,0,0,1,1, _ 1,1,0,1,1,1,1,0,1,1, _ 1,1,0,1,1,1,1,0,1,1, _ 1,0,0,0,1,1,0,0,0,1, _ 1,1,1,1,1,1,1,1,1,1 _ ] Local $oVector = ObjCreate("WIA.Vector.1") If Not IsObj($oVector) Then ConsoleWrite("+++ Error " & @error & " durning create a Vector.object." & @CRLF) Exit EndIf Local $iBlue = 0xFF0000FF ; ARGB color Local $iWhite = 0xFFFFFFFF ; adding pixels to vector For $i = 0 To UBound($a10x10) - 1 Local $iPixel = $a10x10[$i] Local $iColor = $iBlue If $iPixel = 0 Then $iColor = $iWhite $oVector.Add($iColor) Next ; create a img 10x10 px Local $oImg = $oVector.ImageFile(10, 10) ; path to file Local $sPath = @ScriptDir & "\Vector.bmp" ; delete previous file if exits. FileDelete($sPath) ; save img to script direction. $oImg.SaveFile($sPath) ; show result, you have to use 800% size to see effects. ShellExecute("Vector.bmp")  
    • CYCho
      By CYCho
       
      #include <GUIConstants.au3>
      #include <WindowsConstants.au3>

      Local $oPlayer, $gVideo, $width, $height
      $oPlayer = ObjCreate("WMPlayer.OCX.7")
      $oPlayer.URL = 'http://www.clubbalcony.com/upload/culture/yong(2).wmv'
      Local $srcFound = True
      Local $time1 = TimerInit()
      While 1
          If $oPlayer.playState() = 3 Then
              $width = $oPlayer.currentMedia.imageSourceWidth
              $height = $oPlayer.currentMedia.imageSourceHeight
              ExitLoop
          EndIf
          If TimerDiff($time1) > 5000 Then
              $srcFound = False
              ExitLoop
          EndIf
          Sleep(50)
      WEnd
      If Not $srcFound Or $width = 0 Then
          $oPlayer.Close()
          Exit
      Else
          $gVideo = GUICreate("Video Control", $width, $height+63, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX), $WS_EX_TOPMOST)
          GUICtrlCreateObj($oPlayer, 0, 0, $width, $height+63)
          $oPlayer.uiMode = "Full"
          $oPlayer.stretchToFit = True
          GUISetState(@SW_SHOW, $gVideo)
      EndIf

      While 1
          $Msg = GUIGetMsg(1)
          Switch $Msg[0]
              Case $GUI_EVENT_CLOSE
                  ExitLoop
              Case $GUI_EVENT_RESIZED
                  ;This is where I want to resize the video image to fit the new window size
          EndSwitch
      WEnd
      $oPlayer.Close()
         
      How should I code the $GUI_EVENT_RESIZED portion to resize the video to fit the resized window? Your help will be greatly appreciated.

       
    • slidy56fr
      By slidy56fr
      Internet Explorer 11, AutoIt 3.3.14.2
      I want to download many files which are published with hyperlink on a web page. I use AutoIt and when there is a few files, it works even if It's on a website with secured links.
      I have a script to download link items with the object method (I gave a partial sample), but when the number of link exceed the web page, there is not an auto scroll, then the links which are not on displayed without scroll are not downloaded.
      Thank you
      From France
       
       
      EchantillonRecepAnonym.au3
    • Guy_
      By Guy_
      Let's say a script has to do something that may or may not shift the page a fair bit in a general DTP program, browser, ...
      In other words, the scrollbar was moved.
      (1) Can the original scrollbar position be saved and restored?
      I can think of a rough workaround or two, but I mean, more precisely...?
      (2) If so, is it for example a different control for every program?
      (3) Let's say for a workaround you might use the help of ...
      MouseWheel ( "direction" [, clicks = 1] ) Is there an absolute relationship of clicks to pixels?
      Or does the amount of scroll from these 'clicks' depend on how much movement was defined for the scroll wheel in Windows or Mouse driver software?
      Thank You
×