Added functions to restore scrollbar position after a minimize/restore cycle:
For GUIScrollbars_Ex there are 2 functions: _GUIScrollbars_Minimize and _GUIScrollbars_Restore - called on the relevant events occurring. This is needed because of the way the UDF deals with the scrollbars it generates.
For GUIScrollbars_Size there is a single function: _GUIScrollbars_Restore.
The second example for each UDF has been modified to use these new functions. Thanks to rover and czardas for developing the code.
New UDFs, examples and zip file below.
Previous changes:
Spoiler
21/01/11 Amended: _GUIScrollbars_Ex now only activates the scrollbar and mousewheel handlers if the relevant scrollbar is required by the user.
This prevent inadvertant scrolling if your mouse wheel cannot decide which axis it wants to use - which was the case for czardas who discovered the problem!
10/06/10 Amended: _GUIScrollbars_Ex now includes a function to do control location calculation automatically - new example to show it working. Full details here.
First example for _GUIScrollbars_Size amended to show how how to make manual correction for scrollbar movement.
01/05/10 Amended: _GUIScrollbars_Ex now supports mousewheel scrolling!
- Vertical scroll uses vertical mouse wheel.
- Horizontal scroll uses horizontal mouse wheel or vertical mouse wheel with either Ctrl or Shft pressed.
30/04/10 Added: A simple example to show how easy the syntax is!
21/01/11 Amended: _GUIScrollbars_Ex now only activates the scrollbar and mousewheel handlers if the relevant scrollbar is required by the user.
This prevent inadvertant scrolling if your mouse wheel cannot decide which axis it wants to use - which was the case for czardas who discovered the problem!
10/06/10 Amended: _GUIScrollbars_Ex now includes a function to do control location calculation automatically - new example to show it working. Full details here.
First example for _GUIScrollbars_Size amended to show how how to make manual correction for scrollbar movement.
01/05/10 Amended: _GUIScrollbars_Ex now supports mousewheel scrolling!
- Vertical scroll uses vertical mouse wheel.
- Horizontal scroll uses horizontal mouse wheel or vertical mouse wheel with either Ctrl or Shft pressed.
30/04/10 Added: A simple example to show how easy the syntax is!
Are you bemused by scrollbars?
Do you find them too difficult to use?
Then you need the GUIScrollbars_Ex UDF!
Just download the zip at the end of the post and run this short script with the UDF in the same folder. No tricky calculations, no complicated functions to master - just easy to use, accurate scrollbars with one command!
AutoIt
#include <guiconstantsex.au3> #include "GUIScrollbars_Ex.au3" ; Create GUI with red background $hGUI = GUICreate("Test", 500, 500) GUISetBkColor(0xFF0000, $hGUI) ; Create a 1000x1000 green label GUICtrlCreateLabel("", 0, 0, 1000, 1000) GUICtrlSetBkColor(-1, 0x00FF00) GUISetState() ; Generate scrollbars - Yes, this is all you need to do!!!!!!!!!!!!!!!!!!!! _GUIScrollbars_Generate($hGUI, 1000, 1000) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd
Try it today and see how easy it is!
I have been trying for some time to understand how scrollbars work and how to get them closely to match the area I want to display. After much research and headscratching I have come up with 2 UDFs which I hope will be of use to others. Apologies for the length of this post, but scrollbars are complex beasts and as I did this mainly for the less experienced user I want to make sure that they understand what is going on.
The 2 UDFs are:
GUIScrollbars_Ex.au3 - This gives you scrollbars sized to your GUI in one simple command - with no other includes or commands needed. The UDF is designed for those who would not normally use scrollbars because the whole process looks too complicated. It also includes a command to enable you to scroll page by page, thus making it easy to scroll to anywhere on the GUI with only simple calulations based on the values you used to create the GUIs. [New] Additional commands allow you to restore the scrollbar position after minimizing and restoring the GUI
GUIScrollbars_Size.au3 - This calculates the Page and Max numbers for the user to feed into the _GUIScrollbar_SetScrollInfoPage/Max commands. The UDF is aimed at the more experienced user and is particularly useful when you have a GUI with a dynamic scroll size (i.e. adding or subtracting controls to the scrollable area as the script runs). [New] Addtional command to restore the scrollbar position after a minimize/restore cycle.
First, a short tutorial for those who are interested in how the scrollbars affect your GUI and what it is that the UDFs calculate:
Spoiler
A GUI with scrollbars can be thought of as a window onto a larger underlying GUI which can be brought into view by moving the scrollbars. The difficulty has always been to get the correct values for the Page size and Max scroll values. The Max value determines the visible borders of the larger GUI when the scrollbars are moved to the ends of their travel, while the Page value determines how far a click on the scrollbar will scroll the GUI and the size of the scrollbar thumb in relation to the scrollbar length (normally you want the thumb to indicate the relative sizes of the visible area and the whole GUI). The Page and Max values are closely interrelated and are often diffcult to set so that the scrollbars show enough of the larger GUI to be useful but not so much that you end up looking at a blank area because you have scrolled well past the place where you wanted to stop.
Firstly, we have to understand that the scrollbars work effectively in character units - the number of lines vertically and the number of characters horizontally - and not the pixels we normally use in AutoIt. So to correctly set the Page and Max values for a vertical scrollbar, we need to calculate how many lines of text would fit into the visible window (Page) and into the area we wish to scroll (Max). Similar calculations are need for a horizontal scrollbar - except we use the number of characters that fit across the 2 areas rather then the number of lines.
It is this use of lines and character widths that makes getting the scrollbars to scroll exactly one page at a time, or to exactly the border of a GUI, so difficult. The Page and Max values must be set in integers - and so if there is not an exact number of lines or character widths in the GUI then scrolling a page or to the maximum value of the GUI is more or less accurate depending on how close the value is to an integer.
Here is a diagram showing the edge position of 8000 scrollable GUIs when the scrollbars were set to the maximum value. The green lines indicate distance of the horizontal edge from the gui border and the blue lines the vertical. As you would expect, the average value is around the 0 mark, but the distance can be off by up to half the unit value - on my machine the line height is 17 and the character width is 8, which explains the slightly wider spread of the vertical error. The UDFs actually return Max values which result in the red (horizontal) and purple (vertical) positions - I felt it was more important to have all of the GUI visible, but there is an option to choose the tighter fit if required.
Now we need to understand what happens when scrollbars are added to a GUI. Everything is driven by the fact that the client area of the GUI (the area inside the borders and title bar) is reduced in size when the scrollbars are added. The size of the bars is determined by the system, so this reduction varies from machine to machine. The fact that the client area is reduced in size has different effects depending on whether the GUI contained controls before the scrollbars were displayed.
- If the GUI was empty of controls, then the only requirement is to take account of the slightly smaller client area when adding controls - the available space for displaying controls in the visible window is slightly reduced.
- If the GUI already held controls then the problems are much greater. Windows automatically resizes the GUI so that you will see all of the old client area within the new smaller one. As a result all of the controls in the GUI will shrink and move slightly - even if they are not visible in the client area. This means that the whole GUI has effectively shrunk in size, which will affect the calculation of the Max value. It also means that any controls added to the GUI must take into account the changed positions of the existing controls or they will not align correctly.
The UDFs take into account these changes and calculate the necessary values to display the GUI as the user intended.
There is a small script below which shows the above effects on real GUIs.
I hope this short tutorial has explained why scrollbars are a complicated thing to get to work correctly. Now please read on and see why the 2 UDFs may well allow you to use them in the future.
A GUI with scrollbars can be thought of as a window onto a larger underlying GUI which can be brought into view by moving the scrollbars. The difficulty has always been to get the correct values for the Page size and Max scroll values. The Max value determines the visible borders of the larger GUI when the scrollbars are moved to the ends of their travel, while the Page value determines how far a click on the scrollbar will scroll the GUI and the size of the scrollbar thumb in relation to the scrollbar length (normally you want the thumb to indicate the relative sizes of the visible area and the whole GUI). The Page and Max values are closely interrelated and are often diffcult to set so that the scrollbars show enough of the larger GUI to be useful but not so much that you end up looking at a blank area because you have scrolled well past the place where you wanted to stop.
Firstly, we have to understand that the scrollbars work effectively in character units - the number of lines vertically and the number of characters horizontally - and not the pixels we normally use in AutoIt. So to correctly set the Page and Max values for a vertical scrollbar, we need to calculate how many lines of text would fit into the visible window (Page) and into the area we wish to scroll (Max). Similar calculations are need for a horizontal scrollbar - except we use the number of characters that fit across the 2 areas rather then the number of lines.
It is this use of lines and character widths that makes getting the scrollbars to scroll exactly one page at a time, or to exactly the border of a GUI, so difficult. The Page and Max values must be set in integers - and so if there is not an exact number of lines or character widths in the GUI then scrolling a page or to the maximum value of the GUI is more or less accurate depending on how close the value is to an integer.
Here is a diagram showing the edge position of 8000 scrollable GUIs when the scrollbars were set to the maximum value. The green lines indicate distance of the horizontal edge from the gui border and the blue lines the vertical. As you would expect, the average value is around the 0 mark, but the distance can be off by up to half the unit value - on my machine the line height is 17 and the character width is 8, which explains the slightly wider spread of the vertical error. The UDFs actually return Max values which result in the red (horizontal) and purple (vertical) positions - I felt it was more important to have all of the GUI visible, but there is an option to choose the tighter fit if required.
Now we need to understand what happens when scrollbars are added to a GUI. Everything is driven by the fact that the client area of the GUI (the area inside the borders and title bar) is reduced in size when the scrollbars are added. The size of the bars is determined by the system, so this reduction varies from machine to machine. The fact that the client area is reduced in size has different effects depending on whether the GUI contained controls before the scrollbars were displayed.
- If the GUI was empty of controls, then the only requirement is to take account of the slightly smaller client area when adding controls - the available space for displaying controls in the visible window is slightly reduced.
Original GUI without controls New GUI with reduced Client area #-----------------# #-----------------# # } # # }x # # } # # }x # # } # # }x # # } # #~~~~~~}x # #~~~~~~~} # #xxxxxxxx # # # # # # # # # # # # # #-----------------# #-----------------#
- If the GUI already held controls then the problems are much greater. Windows automatically resizes the GUI so that you will see all of the old client area within the new smaller one. As a result all of the controls in the GUI will shrink and move slightly - even if they are not visible in the client area. This means that the whole GUI has effectively shrunk in size, which will affect the calculation of the Max value. It also means that any controls added to the GUI must take into account the changed positions of the existing controls or they will not align correctly.
Original GUI with controls New GUI with reduced Client area and effectively reduced Max size #-----------------# #---------------# # @ } # # @ }x # # } # # }x # # } # # }x # # } # #~~~~~~}x # #~~~~~~~} # #xxxxxxxx # # # # # # # # # # # # @ # # @ # #---------------# #-----------------#
The UDFs take into account these changes and calculate the necessary values to display the GUI as the user intended.
There is a small script below which shows the above effects on real GUIs.
I hope this short tutorial has explained why scrollbars are a complicated thing to get to work correctly. Now please read on and see why the 2 UDFs may well allow you to use them in the future.
All the files mentioned here are in a downloadable zip file at the end of the post.
GUIScroll_Size.au3
As mentioned previously, the GUIScroll_Size.au3 UDF is aimed at the more experienced user who wants to use the full range of _GUIScrollbar comands, but would like a quick way of getting the required Page and Max values. It uses no other include files so you will need to include GUIScrollbars.au3 yourself, as well as the necessary GUIRegisterMsg and procedures for WM_VSCROLL and WM_HSCROLL. The syntax is simple - the size of the scrollable GUI and either the handle of the GUI you have created to hold the scrollbars or the size of the one you are going to create. It returns a 6-element array including the Page and Max values for the scrollbars and factors to compensate for the "shrinkage" of the GUI if you had already drawn some controls and wished to add others. Of interest, the returned Max value is biased not to clip the edges of the GUI - reducing it by 1 makes a tighter fit but can lead to some clipping. (If that does not make sense, please see the tutorial above for more details)
Here is an example script to show the UDF in action - the "Pass Size" button shows the effect of creating the scrollbars BEFORE the controls, the "Pass Handle" button shows what happens if the scrollbars are created AFTER the controls. If you do not understand why there is a difference - go and read the tutorial above
Spoiler
AutoIt
#include <guiconstantsex.au3> #include <windowsconstants.au3> #include <guiscrollbars.au3> #include <scrollbarconstants.au3> #include "GUIScrollbars_Size.au3" Global $hButton_Show_UnCorr = 9999, $hButton_Show_Corr = 9999, $hButton_Show_Size = 9999, $hButton_Show_Dock = 9999 ; Set aperture and scroll sizes $iH_Aperture = 400 $iV_Aperture = 400 $iH_Scroll = 1000 $iV_Scroll = 1000 ; Create GUI $hGUI = GUICreate("Scrollbar Test", $iH_Aperture, $iV_Aperture) GUISetBkColor(0xD0D0FF, $hGUI) ; Create buttons $hButton_Size = GUICtrlCreateButton("Pass Size", 10, 10, 80, 30) $sMsg = "Pressing 'Pass Size' runs the function BEFORE the scrollbars are" & @CRLF & _ "added. The required size of the aperture is passed." & @CRLF & @CRLF & _ "Controls should be created AFTER the scrollbars are created." $hLabel_Size = GUICtrlCreateLabel($sMsg, 10, 50, $iH_Aperture - 20, 50) $hButton_Handle = GUICtrlCreateButton("Pass Handle", 10, 150, 80, 30) $sMsg = "Pressing 'Pass Handle' runs the function AFTER the scrollbars are" & @CRLF & _ "added. The GUI handle is passed." & @CRLF & @CRLF & _ "Controls should be created BEFORE the scrollbars are created" $hLabel_Handle = GUICtrlCreateLabel($sMsg, 10, 200, $iH_Aperture - 20, 50) GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $hButton_Size GUICtrlSetState($hButton_Size, $GUI_HIDE) GUICtrlSetState($hButton_Handle, $GUI_HIDE) GUICtrlDelete($hLabel_Size) GUICtrlDelete($hLabel_Handle) ; Get scrollbar values BEFORE showing bars $aRet = _GUIScrollbars_Size($iH_Scroll, $iV_Scroll, $iH_Aperture, $iV_Aperture) If @error Then MsgBox(0, "Error", "Sizing error" & @CRLF & _ "Return: " & $aRet & @CRLF & _ "Error: " & @error & @CRLF & _ "Extended: " & @extended) Exit Else For $i = 0 To 5 ConsoleWrite($aRet[$i] & @CRLF) Next EndIf ; Register scrollbar messages GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL") GUIRegisterMsg($WM_HSCROLL, "_Scrollbars_WM_HSCROLL") ; Show scrollbars _GUIScrollBars_Init($hGUI) ; Set scrollbar limits _GUIScrollBars_SetScrollInfoPage($hGUI, $SB_HORZ, $aRet[0]) _GUIScrollBars_SetScrollInfoMax($hGUI, $SB_HORZ, $aRet[1]) _GUIScrollBars_SetScrollInfoPage($hGUI, $SB_VERT, $aRet[2]) _GUIScrollBars_SetScrollInfoMax($hGUI, $SB_VERT, $aRet[3]) $sMsg = "The buttons and labels below have been created AFTER" & @CRLF & _ "the scrollbars. Pressing the buttons will show that there" & @CRLF & _ "is no requirement to apply the correction factors to either" & @CRLF & _ "normal or DOCKALL controls" GUICtrlCreateLabel($sMsg, 10, 10, $iH_Aperture - 20, 90) $hButton_Show_UnCorr = GUICtrlCreateButton("Show UnCorr", 100, 150, 85, 30) $hButton_Show_Dock = GUICtrlCreateButton("Show DOCKALL", 100, 300, 85, 30) ; Show preset positions GUICtrlCreateLabel("", 200, 150, 90, 30) GUICtrlSetBkColor(-1, 0) GUICtrlCreateLabel("200x150", 200, 150, 80, 30) GUICtrlSetBkColor(-1, 0xC4C4C4) GUICtrlCreateLabel("", 200, 300, 90, 30) GUICtrlSetBkColor(-1, 0) GUICtrlCreateLabel("200x300" & @CRLF & "DOCKALL", 200, 300, 80, 30) GUICtrlSetBkColor(-1, 0xC4C4C4) GUICtrlSetResizing(-1, $GUI_DOCKALL) ;; Show edges If $iH_Scroll = 0 Then GUICtrlCreateLabel("", 0, $iV_Scroll, $iH_Aperture, 3) GUICtrlSetBkColor(-1, 0xFF0000) ElseIf $iV_Scroll = 0 Then GUICtrlCreateLabel("", $iH_Scroll, 0, 3, $iV_Aperture) GUICtrlSetBkColor(-1, 0xFF0000) Else GUICtrlCreateLabel("", $iH_Scroll, 0, 3, $iV_Scroll) GUICtrlSetBkColor(-1, 0xFF0000) GUICtrlCreateLabel("", 0, $iV_Scroll, $iH_Scroll + 3, 3) GUICtrlSetBkColor(-1, 0xFF0000) EndIf $sMsg = "As the GUI has not been resized," & @CRLF & _ "the corner position remains:" & @CRLF & _ $iH_Scroll & " x " & $iV_Scroll GUICtrlCreateLabel($sMsg, $iH_Scroll - 210, $iV_Scroll - 50, 200, 50, 2) Case $hButton_Handle GUICtrlSetState($hButton_Size, $GUI_HIDE) GUICtrlSetState($hButton_Handle, $GUI_HIDE) GUICtrlDelete($hLabel_Size) GUICtrlDelete($hLabel_Handle) $sMsg = "The buttons and labels below have been created BEFORE" & @CRLF & _ "the scrollbars. They will be slightly moved and resized as" & @CRLF & _ "the GUI shrinks to the new client area size. Pressing the" & @CRLF & _ "buttons will show the result of applying (or not) the" & @CRLF & _ "correction factors." & @CRLF & _ "Note the DOCKALL label remains in position" GUICtrlCreateLabel($sMsg, 10, 10, $iH_Aperture - 20, 90) $hButton_Show_UnCorr = GUICtrlCreateButton("Show UnCorr", 100, 150, 85, 30) $hButton_Show_Corr = GUICtrlCreateButton("Show Corr Pos", 100, 200, 85, 30) $hButton_Show_Size = GUICtrlCreateButton("Show Corr Size", 100, 250, 85, 30) $hButton_Show_Dock = GUICtrlCreateButton("Show DOCKALL", 100, 300, 85, 30) ; Show preset positions GUICtrlCreateLabel("", 200, 150, 90, 30) GUICtrlSetBkColor(-1, 0) GUICtrlCreateLabel("200x150", 200, 150, 80, 30) GUICtrlSetBkColor(-1, 0xC4C4C4) GUICtrlCreateLabel("", 200, 200, 90, 30) GUICtrlSetBkColor(-1, 0) GUICtrlCreateLabel("200x200", 200, 200, 80, 30) GUICtrlSetBkColor(-1, 0xC4C4C4) GUICtrlCreateLabel("", 200, 250, 90, 30) GUICtrlSetBkColor(-1, 0) GUICtrlCreateLabel("200x250", 200, 250, 80, 30) GUICtrlSetBkColor(-1, 0xC4C4C4) GUICtrlCreateLabel("", 200, 300, 90, 30) GUICtrlSetBkColor(-1, 0) GUICtrlSetResizing(-1, $GUI_DOCKALL) GUICtrlCreateLabel("200x300" & @CRLF & "DOCKALL", 200, 300, 80, 30) GUICtrlSetBkColor(-1, 0xC4C4C4) GUICtrlSetResizing(-1, $GUI_DOCKALL) ; Show edges If $iH_Scroll = 0 Then GUICtrlCreateLabel("", 0, $iV_Scroll, $iH_Aperture, 3) GUICtrlSetBkColor(-1, 0xFF0000) ElseIf $iV_Scroll = 0 Then GUICtrlCreateLabel("", $iH_Scroll, 0, 3, $iV_Aperture) GUICtrlSetBkColor(-1, 0xFF0000) Else GUICtrlCreateLabel("", $iH_Scroll, 0, 3, $iV_Scroll) GUICtrlSetBkColor(-1, 0xFF0000) GUICtrlCreateLabel("", 0, $iV_Scroll, $iH_Scroll + 3, 3) GUICtrlSetBkColor(-1, 0xFF0000) EndIf $hButton_Create = GUICtrlCreateButton("Create Scrollbars", 10, 110, 160, 30) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $hButton_Create GUICtrlDelete($hButton_Create) ExitLoop EndSwitch WEnd ; Register scrollbar messages GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL") GUIRegisterMsg($WM_HSCROLL, "_Scrollbars_WM_HSCROLL") ; Show scrollbars _GUIScrollBars_Init($hGUI) _GUIScrollBars_ShowScrollBar($hGUI, $SB_BOTH, True) If $iH_Scroll = 0 Then _GUIScrollBars_ShowScrollBar($hGUI, $SB_HORZ, False) If $iV_Scroll = 0 Then _GUIScrollBars_ShowScrollBar($hGUI, $SB_VERT, False) ; Get scrollbar values AFTER showing bars $aRet = _GUIScrollbars_Size($iH_Scroll, $iV_Scroll, $hGUI) If @error Then MsgBox(0, "Error", "Sizing error" & @CRLF & _ "Return: " & $aRet & @CRLF & _ "Error: " & @error & @CRLF & _ "Extended: " & @extended) Exit Else For $i = 0 To 5 ConsoleWrite($aRet[$i] & @CRLF) Next EndIf ; Set scrollbar limits _GUIScrollBars_SetScrollInfoPage($hGUI, $SB_HORZ, $aRet[0]) _GUIScrollBars_SetScrollInfoMax($hGUI, $SB_HORZ, $aRet[1]) _GUIScrollBars_SetScrollInfoPage($hGUI, $SB_VERT, $aRet[2]) _GUIScrollBars_SetScrollInfoMax($hGUI, $SB_VERT, $aRet[3]) $sMsg = "As the GUI has been resized," & @CRLF & _ "the corner position is now:" & @CRLF & _ Int($iH_Scroll * $aRet[4]) & " x " & Int($iV_Scroll * $aRet[5]) GUICtrlCreateLabel($sMsg, ($iH_Scroll * $aRet[4]) - 210, ($iV_Scroll * $aRet[5]) - 50, 200, 50, 2) Case $hButton_Show_UnCorr ; Add label with uncorrected coordinates $aCorr = _Scroll_Move_Corr($hGUI) GUICtrlCreateLabel("200x150" & @CRLF & "UnCorrected", 200 - $aCorr[0], 150 - $aCorr[1], 80, 30) GUICtrlSetBkColor(-1, 0xFFC4C4) GUICtrlSetState($hButton_Show_UnCorr, $GUI_DISABLE) Case $hButton_Show_Corr ; Add label with corrected coordinates $aCorr = _Scroll_Move_Corr($hGUI) GUICtrlCreateLabel("200x200" & @CRLF & "Corr Position", 200 * $aRet[4] - $aCorr[0], 200 * $aRet[5] - $aCorr[1], 80, 30) GUICtrlSetBkColor(-1, 0xFFD000) GUICtrlSetState($hButton_Show_Corr, $GUI_DISABLE) Case $hButton_Show_Size ; Add label with corrected coordinates $aCorr = _Scroll_Move_Corr($hGUI) GUICtrlCreateLabel("200x250" & @CRLF & "Corr Pos + Size", 200 * $aRet[4] - $aCorr[0], 250 * $aRet[5] - $aCorr[1], 80 * $aRet[4], 30 * $aRet[5]) GUICtrlSetBkColor(-1, 0xC4FFC4) GUICtrlSetState($hButton_Show_Size, $GUI_DISABLE) Case $hButton_Show_Dock ; Add label with uncorrected coordinates $aCorr = _Scroll_Move_Corr($hGUI) GUICtrlCreateLabel("200x300" & @CRLF & "DOCKALL", 200 - $aCorr[0], 300 - $aCorr[1], 80, 30) GUICtrlSetBkColor(-1, 0xC4FFC4) GUICtrlSetState($hButton_Show_Dock, $GUI_DISABLE) EndSwitch WEnd Func _Scroll_Move_Corr($hWnd) Local $aCorr[2] $aCorr[0] = _GUIScrollBars_GetScrollInfoPos($hWnd, $SB_HORZ) * Int($iH_Scroll / _GUIScrollBars_GetScrollInfoMax($hWnd, $SB_HORZ)) $aCorr[1] = _GUIScrollBars_GetScrollInfoPos($hWnd, $SB_VERT) * Int($iV_Scroll / _GUIScrollBars_GetScrollInfoMax($hWnd, $SB_VERT)) Return $aCorr EndFunc Func _Scrollbars_WM_VSCROLL($hWnd, $Msg, $wParam, $lParam) #forceref $Msg, $wParam, $lParam Local $nScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $yChar, $yPos Local $Min, $Max, $Page, $Pos, $TrackPos For $x = 0 To UBound($aSB_WindowInfo) - 1 If $aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $yChar = $aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $Min = DllStructGetData($tSCROLLINFO, "nMin") $Max = DllStructGetData($tSCROLLINFO, "nMax") $Page = DllStructGetData($tSCROLLINFO, "nPage") $yPos = DllStructGetData($tSCROLLINFO, "nPos") $Pos = $yPos $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $nScrollCode Case $SB_TOP DllStructSetData($tSCROLLINFO, "nPos", $Min) Case $SB_BOTTOM DllStructSetData($tSCROLLINFO, "nPos", $Max) Case $SB_LINEUP DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1) Case $SB_LINEDOWN DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1) Case $SB_PAGEUP DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page) Case $SB_PAGEDOWN DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page) Case $SB_THUMBTRACK DllStructSetData($tSCROLLINFO, "nPos", $TrackPos) EndSwitch DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) $Pos = DllStructGetData($tSCROLLINFO, "nPos") If ($Pos <> $yPos) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos)) $yPos = $Pos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_VSCROLL Func _Scrollbars_WM_HSCROLL($hWnd, $Msg, $wParam, $lParam) #forceref $Msg, $lParam Local $nScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $xChar, $xPos Local $Page, $Pos, $TrackPos For $x = 0 To UBound($aSB_WindowInfo) - 1 If $aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $xChar = $aSB_WindowInfo[$iIndex][2] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_HORZ) $Page = DllStructGetData($tSCROLLINFO, "nPage") $xPos = DllStructGetData($tSCROLLINFO, "nPos") $Pos = $xPos $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $nScrollCode Case $SB_LINELEFT DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1) Case $SB_LINERIGHT DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1) Case $SB_PAGELEFT DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page) Case $SB_PAGERIGHT DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page) Case $SB_THUMBTRACK DllStructSetData($tSCROLLINFO, "nPos", $TrackPos) EndSwitch DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_HORZ, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_HORZ, $tSCROLLINFO) $Pos = DllStructGetData($tSCROLLINFO, "nPos") If ($Pos <> $xPos) Then _GUIScrollBars_ScrollWindow($hWnd, $xChar * ($xPos - $Pos), 0) Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_HSCROLL
Where this UDF really helps is if you have a scrollable GUI of variable size - if the number of controls varies with user selections for example. All you need to do is to rerun the UDF with the new size of the scrollable GUI and it produces a new Max value for you to use. This second example script shows how the function enables you to dynamically size your scrollbars depending on the number of controls required. As before it requires the GUIScroll_Size.au3 UDF in the same folder:
Spoiler
AutoIt
#include <guiconstantsex.au3> #include <windowsconstants.au3> #include <guiscrollbars.au3> #include <scrollbarconstants.au3> #include "GUIScrollbars_Size.au3" Global $ahLabels[100] = [0] $hGUI = GUICreate("Test", 300, 300) GUISetState() $aRet = _GUIScrollbars_Size(0, 550, 300, 300) If @error Then ConsoleWrite($aRet & " - " & @error & " - " & @Extended & @CRLF) Else For $i = 0 To 5 ConsoleWrite($aRet[$i] & @CRLF) Next EndIf GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL") _GUIScrollBars_Init($hGUI) _GUIScrollBars_ShowScrollBar($hGUI, $SB_VERT, True) _GUIScrollBars_ShowScrollBar($hGUI, $SB_HORZ, False) _GUIScrollBars_SetScrollInfoPage($hGUI, $SB_VERT, $aRet[2]) _GUIScrollBars_SetScrollInfoMax($hGUI, $SB_VERT, $aRet[3]) $hButton = GUICtrlCreateButton("Change number of labels", 10, 10, 265, 30) _Draw_Labels(10) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $GUI_EVENT_RESTORE _GUIScrollbars_Restore($hGUI, True, False) ; We only want the vertical scrollbar to show Case $hButton Do $iCount = Number(InputBox("Resize scroll area", "Select number of labels to display (min 6)", "", "", 240, 130)) Until $iCount > 5 _Draw_labels($iCount) $aRet = _GUIScrollbars_Size(0, ($iCount + 1) * 50, 300, 300) _GUIScrollBars_SetScrollInfoPage($hGUI, $SB_VERT, $aRet[2]) _GUIScrollBars_SetScrollInfoMax($hGUI, $SB_VERT, $aRet[3]) EndSwitch WEnd Func _Draw_labels($iCount) ConsoleWrite($iCount & " - " & $ahLabels[0] & @CRLF) GUISwitch($hGUI) If $iCount > $ahLabels[0] Then For $i = $ahLabels[0] + 1 To $iCount ConsoleWrite("Add " & $i & @CRLF) $ahLabels[$i] = GUICtrlCreateLabel($i, 10, $i * 50, 265, 40) GUICtrlSetBkColor(-1, 0xFF8080) GUICtrlSetFont(-1, 18) Next Else For $i = $iCount + 1 To $ahLabels[0] ConsoleWrite("Del " & $i & @CRLF) GUICtrlDelete($ahLabels[$i]) Next EndIf $ahLabels[0] = $iCount EndFunc Func _Scrollbars_WM_VSCROLL($hWnd, $Msg, $wParam, $lParam) #forceref $Msg, $wParam, $lParam Local $nScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $yChar, $yPos Local $Min, $Max, $Page, $Pos, $TrackPos For $x = 0 To UBound($aSB_WindowInfo) - 1 If $aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $yChar = $aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $Min = DllStructGetData($tSCROLLINFO, "nMin") $Max = DllStructGetData($tSCROLLINFO, "nMax") $Page = DllStructGetData($tSCROLLINFO, "nPage") $yPos = DllStructGetData($tSCROLLINFO, "nPos") $Pos = $yPos $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $nScrollCode Case $SB_TOP DllStructSetData($tSCROLLINFO, "nPos", $Min) Case $SB_BOTTOM DllStructSetData($tSCROLLINFO, "nPos", $Max) Case $SB_LINEUP DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1) Case $SB_LINEDOWN DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1) Case $SB_PAGEUP DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page) Case $SB_PAGEDOWN DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page) Case $SB_THUMBTRACK DllStructSetData($tSCROLLINFO, "nPos", $TrackPos) EndSwitch DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) $Pos = DllStructGetData($tSCROLLINFO, "nPos") If ($Pos <> $yPos) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos)) $yPos = $Pos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_VSCROLL
And here is the GUIScrollbars_Size.au3 UDF itself:
Spoiler
AutoIt
#include-once ; #INDEX# ============================================================================================================ ; Title .........: _GUIScrollBars_Size ; AutoIt Version : v3.3.6.0 ; Language ......: English ; Description ...: Calculates scrollbar page and max values with proportional thumb sizes ; Remarks .......: ; Note ..........: ; Author(s) .....: Melba23 - with some code from WinAPI, GUIScrollBars and StructureConstants includes ; and contributions from rover and czardas ; ==================================================================================================================== ;#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 ; #INCLUDES# ========================================================================================================= #include <guiscrollbars.au3> #include <scrollbarconstants.au3> ; #CURRENT# ========================================================================================================== ; _GUIScrollbars_Size: Calculates scrollbar page and max values with proportional thumb sizes ; _GUIScrollbars_Restore: Resets scrollbar positions after a minimize/restore cycle ; ==================================================================================================================== ; #INTERNAL_USE_ONLY#================================================================================================= ; _GSB_Size_Text: Sizes GUI text to set scroll units ; _GSB_Size_SB: Sizes scrollbars to fit required GUI size ;===================================================================================================================== ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Size ; Description ...: Calculates scrollbar page and max values with proportional thumb sizes ; Syntax.........: _GUIScrollbars_Size ($iH_Scroll, $iV_Scroll, $hAperture, [$iH_Aperture = 0]) ; Parameters ....: $iH_Scroll -> Width in pixels of area to be scrolled, must be >= aperture width ; $iV_Scroll -> Height in pixels of area to be scrolled, must be >= aperture height ; $hAperture -> GUI handle / Width of aperture GUI to contain scrollbars ; $iH_Aperture -> Height of aperture GUI to contain scrollbars - only needed if $hAperture is width ; Requirement(s).: v3.3.6.0 or higher ; Return values .: Success - Returns a 6-element array: ; [0] = Horizontal page size ; [1] = Horizontal max size ; [2] = Vertical page size ; [3] = Vertical max size ; [4] = Horizontal position correction factor ; [5] = Vertical position correction factor ; Failure - Returns 0 and sets @error as follows: ; 1 - Scroll area smaller than aperture GUI ; Returns negative integer indicating API error: ; -1 - GetDC failure ; -2 - GetTextMetricsW failure ; -3 - GetClientRect failure ; with @error and @extended as set by API return ; Remarks .......; If controls have been created BEFORE the scrollbars are displayed, the correction factors must be ; applied to the coordinates of any subsequent controls to get positional alignment. The factors ; need not be applied if the control use the $GUI_DOCKALL resizing parameter. ; Author ........: Melba23 - with some code from WinAPI, GUIScrollBars and StructureConstants includes ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Size($iH_Scroll = 0, $iV_Scroll = 0, $hAperture = 0, $iV_Aperture = 0) ; Declare variables Local $fH_Scroll = True, $fV_Scroll = True Local $iX_Client, $iY_Client, $iX_Client_Bar, $iY_Client_Bar, $iX_Char, $iY_Char Local $aRet, $iError, $iExtended Local $tRect = DllStructCreate("long Left;long Top;long Right;long Bottom") ; If passed GUI handle If IsHWnd($hAperture) Then ; Determine GUI client area DllCall("user32.dll", "bool", "GetClientRect", "hwnd", $hAperture, "ptr", DllStructGetPtr($tRect)) If @error Then Return SetError(@error, @extended, -3) Local $iX_Client_GUI = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left") Local $iY_Client_GUI = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top") ; Check valid scroll size parameters If $iH_Scroll < $iX_Client_GUI And $iH_Scroll <> 0 Then Return SetError(1, 0, 0) If $iV_Scroll < $iY_Client_GUI And $iV_Scroll <> 0 Then Return SetError(1, 0, 0) ; Determine horizontal scrollbar state and set GUI sizes Local $aH_SB = _GSB_Size_SB($hAperture, 0xFFFFFFFA) ; $OBJID_HSCROLL $iError = @error $iExtended = @extended If Not IsArray($aH_SB) Then Return SetError($iError, $iExtended, -4) Else If Abs($aH_SB[0]) > @DesktopWidth Then ; No H scrollbar so unset scrollbar flag $fH_Scroll = False ; Set GUI sizes $iY_Client = $iY_Client_GUI $iY_Client_Bar = $iY_Client_GUI Else ; Set GUI sizes $iY_Client = $iY_Client_GUI + ($aH_SB[3] - $aH_SB[1]) $iY_Client_Bar = $iY_Client_GUI EndIf EndIf ; Determine vertical scrollbar state and set GUI sizes Local $aV_SB = _GSB_Size_SB($hAperture, 0xFFFFFFFB) ; $OBJID_VSCROLL $iError = @error $iExtended = @extended If Not IsArray($aH_SB) Then Return SetError($iError, $iExtended, -4) Else If Abs($aV_SB[0]) > @DesktopWidth Then ; No V scrollbar so unset scrollbar flags $fV_Scroll = False ; Set GUI sizes $iX_Client = $iX_Client_GUI $iX_Client_Bar = $iX_Client_GUI Else ; Set GUI sizes $iX_Client = $iX_Client_GUI + ($aV_SB[2] - $aV_SB[0]) $iX_Client_Bar = $iX_Client_GUI EndIf EndIf ; Determine GUI text size $aRet = _GSB_Size_Text($hAperture) $iError = @error $iExtended = @extended If Not IsArray($aRet) Then Return SetError($iError, $iExtended, $aRet) Else $iX_Char = $aRet[0] $iY_Char = $aRet[1] EndIf ; If passed GUI size Else ; Check valid scroll size parameters If $iH_Scroll < $hAperture And $iH_Scroll <> 0 Then Return SetError(1, 0, 0) If $iV_Scroll < $iV_Aperture And $iV_Scroll <> 0 Then Return SetError(1, 0, 0) Local $hWnd = GUICreate("", $hAperture, $iV_Aperture, @DesktopWidth + 10, 0) GUISetState() ; Set client size without bars $iX_Client = $hAperture $iY_Client = $iV_Aperture ; Ensure both scrollbars hidden DllCall("user32.dll", "bool", "ShowScrollBar", "hwnd", $hWnd, "int", 3, "bool", False) If @error Then Return SetError(@error, @extended, -4) ; Show scrollbars if required If $iH_Scroll Then DllCall("user32.dll", "bool", "ShowScrollBar", "hwnd", $hWnd, "int", 0, "bool", True) If @error Then Return SetError(@error, @extended, -4) If $iV_Scroll Then DllCall("user32.dll", "bool", "ShowScrollBar", "hwnd", $hWnd, "int", 1, "bool", True) If @error Then Return SetError(@error, @extended, -4) ; Get client size with scrollbars DllCall("user32.dll", "bool", "GetClientRect", "hwnd", $hWnd, "ptr", DllStructGetPtr($tRect)) If @error Then Return SetError(@error, @extended, -3) $iX_Client_Bar = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left") $iY_Client_Bar = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top") ; Determine GUI text size $aRet = _GSB_Size_Text($hWnd) $iError = @error $iExtended = @extended If Not IsArray($aRet) Then Return SetError($iError, $iExtended, $aRet) Else $iX_Char = $aRet[0] $iY_Char = $aRet[1] EndIf ; Delete test GUI GUIDelete($hWnd) ; Increase scroll limit values to match resized client area $iH_Scroll /= $iX_Client_Bar / $iX_Client $iV_Scroll /= $iY_Client_Bar / $iY_Client ; Unset scrollbar flags if required If Not $iH_Scroll Then $fH_Scroll = False If Not $iV_Scroll Then $fV_Scroll = False EndIf ; If horizontal scrollbar is required Local $iH_Page, $iH_Max If $fH_Scroll Then ; Use reduced aperture width if other scrollbar exists If $fV_Scroll Then ; Determine page size (aperture width / text width) $iH_Page = Floor($iX_Client_Bar / $iX_Char) ; Determine max size (scroll width / text width * correction factor for vertical scrollbar) $iH_Max = Floor($iH_Scroll / $iX_Char * $iX_Client_Bar / $iX_Client) Else ; Determine page size (aperture width / text width) $iH_Page = Floor($iX_Client / $iX_Char) ; Determine max size (scroll width / text width) $iH_Max = Floor($iH_Scroll / $iX_Char) EndIf Else $iH_Page = 0 $iH_Max = 0 EndIf ; If vertical scrollbar required Local $iV_Page, $iV_Max If $fV_Scroll Then ; Use reduced aperture width if other scrollbar exists If $fH_Scroll Then ; Determine page size (aperture width / text width) $iV_Page = Floor($iY_Client_Bar / $iY_Char) ; Determine max size (scroll width / text width * correction factor for horizontal scrollbar) $iV_Max = Floor($iV_Scroll / $iY_Char * $iY_Client_Bar / $iY_Client) Else ; Determine page size (aperture width / text width) $iV_Page = Floor($iY_Client / $iY_Char) ; Determine max size (scroll width / text width) $iV_Max = Floor($iV_Scroll / $iY_Char) EndIf Else $iV_Page = 0 $iV_Max = 0 EndIf ; Create return array Local $aRet[6] = [$iH_Page, $iH_Max, $iV_Page, $iV_Max, $iX_Client_Bar / $iX_Client, $iY_Client_Bar / $iY_Client] Return $aRet EndFunc ;==>_GUIScrollbars_Size ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Restore ; Description ...: Resets scrollbar positions after a minimize/restore cycle ; Syntax.........: _GUIScrollbars_Restore($hWnd[, $fVert = True[, $fHorz = True]]) ; Parameters ....: $hWnd -> GUI containing scrollbars ; $fVert -> True (default) = vertical scrollbar visible; False = vertical scrollbar not visible ; $fHorz -> True (default) = horizontal scrollbar visible; False = horzontal scrollbar not visible ; Requirement(s).: v3.3.6.0 or higher ; Return values .: None ; Remarks .......; ; Author ........: Melba23 - based on code from rover and czardas ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Restore($hWnd, $fVert = True, $fHorz = True) Local $nV_Pos, $nH_Pos _GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, True) $nV_Pos = _GUIScrollBars_GetScrollPos($hWnd, $SB_VERT) ; Get current position _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, 0) ; Set the scroll to zero $nH_Pos = _GUIScrollBars_GetScrollPos($hWnd, $SB_HORZ) ; Get current position _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_HORZ, 0) ; Set the scroll to zero If Not $fVert Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT, False) EndIf If Not $fHorz Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ, False) EndIf If $fVert Then _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, $nV_Pos) EndIf If $fHorz Then _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_HORZ, $nH_Pos) EndIf EndFunc ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _GSB_Size_Text ; Description ...: Sizes GUI text to set scroll units ; Syntax ........: _GSB_Size_Text($hWnd) ; Return values .: Array holding average text width and absolute text height ; Author ........: Melba23 ; Remarks .......: This function is used internally by _Scrollbars_Size ; =============================================================================================================================== Func _GSB_Size_Text($hWnd) Local $tagTEXTMETRIC = "long tmHeight;long tmAscent;long tmDescent;long tmInternalLeading;long tmExternalLeading;" & _ "long tmAveCharWidth;long tmMaxCharWidth;long tmWeight;long tmOverhang;long tmDigitizedAspectX;long tmDigitizedAspectY;" & _ "wchar tmFirstChar;wchar tmLastChar;wchar tmDefaultChar;wchar tmBreakChar;byte tmItalic;byte tmUnderlined;byte tmStruckOut;" & _ "byte tmPitchAndFamily;byte tmCharSet" Local $tTEXTMETRIC = DllStructCreate($tagTEXTMETRIC) Local $hDC = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hWnd) If Not @error Then $hDC = $hDC[0] DllCall("gdi32.dll", "bool", "GetTextMetricsW", "handle", $hDC, "ptr", DllStructGetPtr($tTEXTMETRIC)) If @error Then Local $iError = @error Local $iExtended = @extended DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC) Return SetError($iError, $iExtended, -2) EndIf DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC) Else Return SetError(@error, @extended, -1) EndIf Local $aRet[2] = [ _ DllStructGetData($tTEXTMETRIC, "tmAveCharWidth"), _ DllStructGetData($tTEXTMETRIC, "tmHeight") + DllStructGetData($tTEXTMETRIC, "tmExternalLeading")] Return $aRet EndFunc ;==>_GSB_Size_Text ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _GSB_Size_SB ; Description ...: Sizes scrollbars to fit required GUI size ; Syntax ........: _GSB_Size_SB($hWnd, $idObj) ; Return values .: Array holding size of scrollable GUI ; Author ........: Melba23 ; Remarks .......: This function is used internally by _Scrollbars_Size ; =============================================================================================================================== Func _GSB_Size_SB($hWnd, $idObj) Local $tagSCROLLBARINFO = "dword cbSize;long Left;long Top;long Right;long Bottom;int dxyLineButton;int xyThumbTop;" & _ "int xyThumbBottom;int reserved;dword rgstate[6]" Local $tSCROLLBARINFO = DllStructCreate($tagSCROLLBARINFO) DllStructSetData($tSCROLLBARINFO, "cbSize", DllStructGetSize($tSCROLLBARINFO)) DllCall("user32.dll", "bool", "GetScrollBarInfo", "hwnd", $hWnd, "long", $idObj, "ptr", DllStructGetPtr($tSCROLLBARINFO)) If @error Then Return SetError(@error, @extended, -4) Local $aRect[4] = [ _ DllStructGetData($tSCROLLBARINFO, "Left"), _ DllStructGetData($tSCROLLBARINFO, "Top"), _ DllStructGetData($tSCROLLBARINFO, "Right"), _ DllStructGetData($tSCROLLBARINFO, "Bottom")] Return $aRect EndFunc ;==>_GSB_Size_SB
GUIScrollbars_Ex.au3
Now the "simple" GUIScrollbars_Ex.au3 (which is actually the more complex internally as you would expect).
This UDF is intended to be the single point of call for creating scrollbars on a GUI - it will automatically add the GUIScrollbars UDF and the WM_VSCROLL and WM_HSCROLL GUIRegisterMsg commands and procedures to your script - so you need no commands other than those within the UDF itself. These commands are _GUIScrollbars_Generate and _GUIScrollbars_Scroll_Page.
As you might expect, _GUIScrollbars_Generate generates scrollbars for your GUI. It is usually called AFTER you have added all the controls and all you need to use it is the GUI handle and the size of the underlying GUI you want to scroll. If you so wish, you can also decide to generate the scrollbars BEFORE the controls on the scrollable GUI, and you can choose if you want to risk not quite reaching the edge of the GUI when the scrollbars are at the maximum position. So a basic call could be as simple as:
_GUIScrollbars_Generate ($hGUI, 1000, 1000)
which would put scrollbars on the $hGUI window allowing a 1000x1000 underlying GUI to be displayed.
_GUIScrollbars_Scroll_Page lets you scroll a page at a time. If your GUI was 200 pixels wide, you would have 1000/200 = 5 pages to scroll before reaching the edge - no need to know what the actual Page and Max values are, just use this simple division based on the number you use to draw the GUIs. So:
_GUIScrollbars_Scroll_Page ($hGUI, 3)
would scroll to the third page - it would display the area between 400 and 600 pixels of the full 1000 pixel width. If you ask for a page over the maximum available, you just scroll to the maximum position - asking for page 1 resets you to the origin.
[New] Two new commands _GUIScrollbars_Minimize and _GUIScrollbars_Restore allow you to reset the scrollbars to the correct position after a minimize/restore cycle. The second example shows these commands in action.
Here is an example script to show it working. You can decide whether to have both or just one scrollbar, whether to create the scrollbars before or after the controls, and whether you want the maximum scroll to be tight to the edge or leave a border. Just select the options you want - the script selects a random width and height for both the scrollbar GUI and the underlying GUI - and press the "Scroll" button to show a single page scroll down and/or right followed by a scroll to the bottom right corner of the GUI. There are labels to let you see the size of the GUI and the accuracy of the page scrolls (please read the tutorial above to understand why these are almost certainly inaccurate). The script requires the GUIScrollbars_Ex.au3 UDF in the same folder:
Spoiler
AutoIt
#include <guiconstantsex.au3> #include <windowsconstants.au3> #include <staticconstants.au3> #include <winapi.au3> #include "GUIScrollbars_Ex.au3" Global $iMax_Vert, $iPage_Vert, $nRatio_Vert, $iMax_Horz, $iPage_Horz, $nRatio_Horz, $iH_Tight, $iV_Tight ; Create wrapper GUI $hGUI = GUICreate("Scroll Bar Examples", 520, 675) GUISetBkColor(0xC4C4C4, $hGUI) $hCheckBox_V = GUICtrlCreateCheckBox("", 10, 10, 20, 20) GUICtrlSetState(-1, $GUI_CHECKED) GUICtrlCreateLabel("Vertical Scrollbar", 10, 35, 80, 40) $hVert_Labels = GUICtrlCreateLabel("Panel Ht:", 90, 10, 100, 20) GUICtrlCreateLabel("Scroll Ht:", 90, 35, 100, 20) GUICtrlCreateLabel("Ratio:", 90, 60, 100, 20) $hLabel_AH = GUICtrlCreateLabel("", 190, 10, 50, 20) $hLabel_SH = GUICtrlCreateLabel("", 190, 35, 50, 20) $hLabel_RH = GUICtrlCreateLabel("", 190, 60, 50, 20) $hCheckBox_H = GUICtrlCreateCheckBox("", 260, 10, 20, 20) GUICtrlSetState(-1, $GUI_CHECKED) GUICtrlCreateLabel("Horizontal Scrollbar", 260, 35, 80, 40) $hHorz_Labels = GUICtrlCreateLabel("Panel Width:", 340, 10, 100, 20) GUICtrlCreateLabel("Scroll Width:", 340, 35, 100, 20) GUICtrlCreateLabel("Ratio:", 340, 60, 100, 20) $hLabel_AW = GUICtrlCreateLabel("", 440, 10, 50, 20) $hLabel_SW = GUICtrlCreateLabel("", 440, 35, 50, 20) $hLabel_RW = GUICtrlCreateLabel("", 440, 60, 50, 20) For $i = $hCheckBox_V To $hLabel_RW GUICtrlSetFont($i, 12) GUICtrlSetResizing($i, $GUI_DOCKALL) Next $hCheck_Tight = GUICtrlCreateCheckbox(" Tight", 100, 640, 80, 30) GUICtrlSetFont(-1, 12) GUICtrlSetResizing(-1, $GUI_DOCKBOTTOM) GUIStartGroup() $hRadio_Before = GUICtrlCreateRadio(" Before", 280, 640, 80, 30) GUICtrlSetFont(-1, 12) GUICtrlSetResizing(-1, $GUI_DOCKBOTTOM) $hRadio_After = GUICtrlCreateRadio(" After", 380, 640, 80, 30) GUICtrlSetState(-1, $GUI_CHECKED) GUICtrlSetFont(-1, 12) GUICtrlSetResizing(-1, $GUI_DOCKBOTTOM) GUIStartGroup() GUISetState() ; Start example While 1 If GUICtrlRead($hCheckBox_V) = 1 Then For $i = $hVert_Labels To $hLabel_RH GUICtrlSetState($i, $GUI_SHOW) Next $iAperture_Ht = Random(200, 500, 1) GUICtrlSetData($hLabel_AH, $iAperture_Ht) ; Random ratio for vertical scroll size $nRatio_Vert = Random(2, 20) GUICtrlSetData($hLabel_RH, Round($nRatio_Vert, 2)) $iScroll_Ht = Int($iAperture_Ht * $nRatio_Vert) GUICtrlSetData($hLabel_SH, $iScroll_Ht) Else For $i = $hVert_Labels To $hLabel_RH GUICtrlSetState($i, $GUI_HIDE) Next $iAperture_Ht = 500 $iScroll_Ht = 0 EndIf If GUICtrlRead($hCheckBox_H) = 1 Then For $i = $hHorz_Labels To $hLabel_RW GUICtrlSetState($i, $GUI_SHOW) Next $iAperture_Width = Random(200, 500, 1) GUICtrlSetData($hLabel_AW, $iAperture_Width) ; Random ratio for horizontal scroll size $nRatio_Horz = Random(2, 20) GUICtrlSetData($hLabel_RW, Round($nRatio_Horz, 2)) $iScroll_Width = Int($iAperture_Width * $nRatio_Horz) GUICtrlSetData($hLabel_SW, $iScroll_Width) Else For $i = $hHorz_Labels To $hLabel_RW GUICtrlSetState($i, $GUI_HIDE) Next $iAperture_Width = 500 $iScroll_Width = 0 EndIf If GUICtrlRead($hCheck_Tight) = 1 Then $iH_Tight = 1 $iV_Tight = 1 Else $iH_Tight = 0 $iV_Tight = 0 EndIf ; Resize wrapper GUI WinMove($hGUI, "", Default, Default, Default, $iAperture_Ht + 170) ; Create aperture GUI $hAperture = GUICreate("", $iAperture_Width, $iAperture_Ht, (520 - $iAperture_Width) / 2, 100, $WS_POPUP, $WS_EX_MDICHILD, $hGUI) ; If scrollbars to be created BEFORE controls If GUICtrlRead($hRadio_Before) = 1 Then ; Generate scrollbars $aAperture = _GUIScrollbars_Generate($hAperture, $iScroll_Width, $iScroll_Ht, $iH_Tight, $iV_Tight, True) If @error Then MsgBox(16, "Error", "Scrollbar generation failed") Exit EndIf ; Reset aperture size to smaller area with scrollbars in place $iAperture_Width = $aAperture[0] $iAperture_Ht = $aAperture[1] EndIf ; Create button to start scrolling $hButton_1 = GUICtrlCreateButton("Scroll", ($iAperture_Width - 80) / 2, 20, 80, 30) ; Create label to show edge if Tight selected If GUICtrlRead($hCheck_Tight) = 1 Then If GUICtrlRead($hCheckBox_V) = 1 Then $iY = $iScroll_Ht - 40 Else $iY = $iAperture_Ht - 40 EndIf If GUICtrlRead($hCheckBox_H) = 1 Then $iX = $iScroll_Width - 40 Else $iX = ($iAperture_Width - 40) / 2 EndIf $hCorner = GUICtrlCreateLabel("", $iX, $iY, 40, 40) GUICtrlSetBkColor(-1, 0xC4FFC4) EndIf ; Create max width and horizontal sizing labels if required If GUICtrlRead($hCheckBox_H) = 1 Then $iLine_Ht = $iAperture_Ht If GUICtrlRead($hCheckBox_V) = 1 Then $iLine_Ht = $iScroll_Ht GUICtrlCreateLabel("", $iScroll_Width - 3, 0, 3, $iLine_Ht - 3) GUICtrlSetBkColor(-1, 0xFF0000) For $i = 100 To 1500 Step 100 GUICtrlCreateLabel($i, $i, 0, 30, 15) GUICtrlSetBkColor(-1, 0xC4FFC4) Next ; Create page size label $iLabel_Ht = 0 If GUICtrlRead($hCheckBox_V) = 1 Then $iLabel_Ht = $iAperture_Ht GUICtrlCreateLabel("", $iAperture_Width - 50, $iLabel_Ht + 100, 100, 40) GUICtrlSetBkColor(-1, 0xC4C4FF) GUICtrlCreateLabel("Page 1", $iAperture_Width - 40, $iLabel_Ht + 115, 40, 15) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) GUICtrlCreateLabel("Page 2", $iAperture_Width + 5, $iLabel_Ht + 115, 40, 15) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) EndIf ; Create max length and vertical sizing labels if required If GUICtrlRead($hCheckBox_V) = 1 Then $iLine_Width = $iAperture_Width If GUICtrlRead($hCheckBox_H) = 1 Then $iLine_Width = $iScroll_Width GUICtrlCreateLabel("", 0, $iScroll_Ht - 3, $iLine_Width, 3) GUICtrlSetBkColor(-1, 0xFF0000) For $i = 100 To 5000 Step 100 GUICtrlCreateLabel($i, 0, $i, 30, 15) GUICtrlSetBkColor(-1, 0xC4FFC4) Next ; Create page size label GUICtrlCreateLabel("", $iAperture_Width - 40, $iAperture_Ht - 50, 40, 100) GUICtrlSetBkColor(-1, 0xFFC4C4) GUICtrlCreateLabel("Page 1", $iAperture_Width - 40, $iAperture_Ht - 15, 40, 15) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) GUICtrlCreateLabel("Page 2", $iAperture_Width - 40, $iAperture_Ht, 40, 15) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) EndIf ; Get correction factors for subsequently created controls If GUICtrlRead($hRadio_After) = 1 Then $aFactor = _GUIScrollbars_Generate($hAperture, $iScroll_Width, $iScroll_Ht, $iH_Tight, $iV_Tight) If @error Then MsgBox(16, "Error", "Scrollbar generation failed") Exit EndIf EndIf GUISetState() ; Draw test label in bottom right corner If GUICtrlRead($hRadio_Before) = 1 Then ; Show alignment without factors with $fBefore GUICtrlCreateLabel("", $iScroll_Width - 10, $iScroll_Ht - 10, 10, 10) GUICtrlSetBkColor(-1, 0x0000FF) Else ; Show need for factors without $fBefore GUICtrlCreateLabel("", ($iScroll_Width - 10) * $aFactor[2], ($iScroll_Ht - 10) * $aFactor[3], 10 * $aFactor[2], 10 * $aFactor[3]) GUICtrlSetBkColor(-1, 0x0000FF) EndIf While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $hButton_1 ; Scroll page down if required If GUICtrlRead($hCheckBox_V) = 1 Then _GUIScrollbars_Scroll_Page($hAperture, 0, 2) Sleep(1000) EndIf If GUICtrlRead($hCheckBox_H) = 1 Then ; Scroll page right if required _GUIScrollbars_Scroll_Page($hAperture, 2) Sleep(1000) EndIf ; Now scroll to extremity of scrollable GUI If GUICtrlRead($hCheckBox_H) = 1 Then _GUIScrollbars_Scroll_Page($hAperture, 99, 0) If GUICtrlRead($hCheckBox_V) = 1 Then _GUIScrollbars_Scroll_Page($hAperture, 0, 99) Sleep(1000) GUIDelete($hAperture) ExitLoop Case $hCheckBox_V, $hCheckBox_H, $hRadio_Before, $hRadio_After, $hCheck_Tight ; Delete current instance and start with new settings GUIDelete($hAperture) ExitLoop EndSwitch WEnd WEnd
[New] Here is a really simple example to show how easy generating scrollbars can now become! And remember to check the new commands to reset the scrollbars.
Spoiler
AutoIt
#include <guiconstantsex.au3> #include "GUIScrollbars_Ex.au3" ; Create GUI with red background $hGUI = GUICreate("Test", 500, 500) GUISetBkColor(0xFF0000, $hGUI) ; Create a 1000x1000 green label GUICtrlCreateLabel("", 0, 0, 1000, 1000) GUICtrlSetBkColor(-1, 0x00FF00) GUISetState() ; Generate scrollbars - Yes, this is all you need to do!!!!!!! _GUIScrollbars_Generate($hGUI, 1000, 1000) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $GUI_EVENT_RESTORE _GUIScrollbars_Restore($hGUI) Case $GUI_EVENT_MINIMIZE _GUIScrollbars_Minimize($hGUI) EndSwitch WEnd
As you can see - no other includes, no GUIRegisterMsg commands, no WM_H/VSCROLL procedure functions. Just accurate scrolling and proportional thumb sizes.
Here is an example showing the automatic calculation of control positions:
Spoiler
AutoIt
#include <guiconstantsex.au3> #include "GUIScrollbars_Ex.au3" ; Create GUI 1 $hGUI_1 = GUICreate("BEFORE", 500, 400, 100, 100) $hButton_1 = GUICtrlCreateButton("Press", 400, 300, 80, 30) GUISetState() ; Generate scrollbars BEFORE controls _GUIScrollbars_Generate($hGUI_1, 1000, 1000, 0, 0, True) $hLabel_1 = GUICtrlCreateLabel("", 300, 200, 50, 50) GUICtrlSetBkColor(-1, 0xCCCCFF) ; Create GUI 2 $hGUI_2 = GUICreate("AFTER", 500, 400, 700, 100) $hLabel_2 = GUICtrlCreateLabel("", 200, 300, 50, 50) GUICtrlSetBkColor(-1, 0xCCCCFF) $hButton_2 = GUICtrlCreateButton("Press", 400, 300, 80, 30) GUISetState() ; Generate scrollbars AFTER controls _GUIScrollbars_Generate($hGUI_2, 700, 700) While 1 $aMsg = GUIGetMsg(1) Switch $aMsg[1] Case $hGUI_1 Switch $aMsg[0] Case $GUI_EVENT_CLOSE Exit Case $hButton_1 GUISwitch($hGUI_1) $aPos = _GUIScrollbars_Locate_Ctrl($hGUI_1, 300, 200) $hNewLabel_1 = GUICtrlCreateLabel("",$aPos[0], $aPos[1], 50, 50) GUICtrlSetBkColor(-1, 0xCCFFCC) Sleep(1000) GUICtrlDelete($hNewLabel_1) EndSwitch Case $hGUI_2 Switch $aMsg[0] Case $GUI_EVENT_CLOSE Exit Case $hButton_2 GUISwitch($hGUI_2) $aPos = _GUIScrollbars_Locate_Ctrl($hGUI_2, 200, 300) $hNewLabel_2 = GUICtrlCreateLabel("",$aPos[0], $aPos[1], 50, 50) GUICtrlSetBkColor(-1, 0xCCFFCC) Sleep(1000) GUICtrlDelete($hNewLabel_2) EndSwitch EndSwitch WEnd
[NEW] And here is the GUIScrollbars_Ex.au3 UDF itself:
Spoiler
AutoIt
#include-once ; #INDEX# ============================================================================================================ ; Title .........: GUIScrollBars_Ex ; AutoIt Version : v3.3.6.0 ; Language ......: English ; Description ...: Generates scrollbars for user defined sizes of GUI and aperture and sets proportional thumb sizes ; Remarks .......: ; Note ..........: ; Author(s) .....: Melba23 - with some code based on the WinAPI and GUIScrollBars includes ; and contributions from rover, czardas, MrCreatoR and Malkey ; ==================================================================================================================== ;#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 ; #INCLUDES# ========================================================================================================= #include <guiconstantsex.au3> #include <windowsconstants.au3> #include <guiscrollbars.au3> #include <scrollbarconstants.au3> #include <sendmessage.au3> ; #GLOBAL VARIABLES# ================================================================================================= Global $aSB_WindowInfo[1][10] ; [0] = Handle to window ; [1] = Not used ; [2] = Average horizontal pixels per char ; [3] = Vertical pixels per char ; [4] = Client area width ; [5] = Client area height ; [6] = Horizontal max setting ; [7] = Vertical max setting ; [8] = Vertical scrollbar position for minimize/restore ; [9] = Horizontal scrollbar position for minimize/restore Global $aSB_WindowInfoEx[1][5] ; [0] = Horizontal scrollable size ; [1] = Vertical scrollable size ; [2] = Width correction factor ; [3] = Height correction factor ; [4] = Before/After flag ; #CURRENT# ========================================================================================================== ; _GUIScrollbars_Generate: Generates scrollbars for a GUI with a defined aperture with proportional thumb sizes ; _GUIScrollbars_Locate_Ctrl: Calculates coordinates to use to position controls after scrollbar creation ; _GUIScrollbars_Scroll_Page: Scrolls to min, max or page number ; _GUIScrollbars_Minimize: Stores scrollbar positions on GUI minimize ; _GUIScrollbars_Restore: Restores scrollbar positions on GUI restore ; ==================================================================================================================== ; #INTERNAL_USE_ONLY#================================================================================================= ; _Scrollbars_WM_VSCROLL: GUIRegisterMsg procedure for vertical scrollbar ; _Scrollbars_WM_HSCROLL: GUIRegisterMsg procedure for horizontal scrollbar ; _Scrollbars_WM_MOUSEWHEEL : GUIRegisterMsg procedure for vertical mouse wheel scroll ; _Scrollbars_WM_MOUSEHWHEEL : GUIRegisterMsg procedure for horizontal mouse wheel scroll ;===================================================================================================================== ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Generate ; Description ...: Generates scrollbars for a GUI with a defined aperture with proportional thumb sizes ; Syntax.........: _GUIScrollbars_Generate ($hWnd, $iH_Scroll = 0, [$iV_Scroll = 0, [$iH_Tight = 0, [$iV_Tight = 0, [$fBefore = False]]]]) ; Parameters ....: $hWnd -> GUI to contain scrollbars ; $iH_Scroll -> Width in pixels of area to be scrolled ; $iV_Scroll -> Height in pixels of area to be scrolled (default = 0) ; $iH_Tight -> 1 = Adjust mean position of right edge of scrolled area to right (default = 0) ; $iV_Tight -> 1 = Adjust mean position of bottom edge of scrolled area down (default = 0) ; $fBefore -> True = Scrollbars are being generated BEFORE controls ; False = Scrollbars are being generated AFTER controls (default) ; Requirement(s).: v3.3.6.0 or higher ; Return values .: Success - Returns a 4-element array (see remarks for details): ; [0] = Actual aperture width ; [1] = Actual aperture height] ; [2] = Width correction factor ; [3] = Height correction factor] ; Failure - Returns either 0 (UDF error) or negative integer (API error) ; If UDF error then @error set as follows: ; 1 - hWnd not a valid handle ; 2 - No scroll size parameters ; 3 - Scrollbar creation or parameter setting failure ; If API error then @error and @extended as set by API error. Return values: ; -1 - GetDC failure ; -2 - GetTextMetricsW failure ; -3 - GetClientRect failure ; Remarks .......; The $fBefore parameter is needed because of the way Windows deals with scrollbars. When the ; scrollbars are generated, the visible part of the scrollable GUI resizes to fit the in the ; remaining (smaller) client area. ; - If the scrollbars are to be generated BEFORE any controls, the UDF shoudl be called with the ; $fBefore parameter set. The new client size of the aperture window is returned so that ; controls can then be created using these values. ; - If controls have been created before the scrollbars are generated then the UDF should be ; called without the $fBefore parameter. The correction factors returned can then be applied to ; any subsequent control positioning and sizing. This is necessary because of the positions and ; sizes of existing controls will be slightly altered as the scrollbars are generated and the GUI ; resized. Any controls created subsequently would therefore be slightly misplaced in relation ; to the existing ones unless the correction factors are used when positoning and sizing them. ; - If existing controls were fixed in place using GUICtrlResizing($GUI_DOCKALL) there is no need ; to apply the correction factors as the controls will not have moved with the GUI resizing. ; Author ........: Melba23 - with some code based on the WinAPI and GUIScrollBars includes ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Generate($hWnd, $iH_Scroll = 0, $iV_Scroll = 0, $iH_Tight = 0, $iV_Tight = 0, $fBefore = False) ; Check if valid window handle If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) If $aSB_WindowInfo[0][0] <> "" Then ReDim $aSB_WindowInfo[UBound($aSB_WindowInfo) + 1][10] ReDim $aSB_WindowInfoEx[UBound($aSB_WindowInfo) + 1][5] EndIf ; If no scroll sizes set, return error If $iH_Scroll = 0 And $iV_Scroll = 0 Then Return SetError(2, 0, 0) ; Confirm Tight values If $iH_Tight <> 0 Then $iH_Tight = 1 If $iV_Tight <> 0 Then $iV_Tight = 1 ; Create structs Local $tTEXTMETRIC = DllStructCreate($tagTEXTMETRIC) Local $tSCROLLINFO = DllStructCreate($tagSCROLLINFO) DllStructSetData($tSCROLLINFO, "cbSize", DllStructGetSize($tSCROLLINFO)) Local $tRect = DllStructCreate($tagRECT) ; Declare local variables Local $iIndex = UBound($aSB_WindowInfo) - 1 Local $iError, $iExtended ; Save window handle $aSB_WindowInfo[$iIndex][0] = $hWnd ; Determine text size Local $hDC = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hWnd) If Not @error Then $hDC = $hDC[0] DllCall("gdi32.dll", "bool", "GetTextMetricsW", "handle", $hDC, "ptr", DllStructGetPtr($tTEXTMETRIC)) If @error Then $iError = @error $iExtended = @extended DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC) Return SetError($iError, $iExtended, -2) EndIf DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC) Else Return SetError(@error, @extended, -1) EndIf $aSB_WindowInfo[$iIndex][2] = DllStructGetData($tTEXTMETRIC, "tmAveCharWidth") $aSB_WindowInfo[$iIndex][3] = DllStructGetData($tTEXTMETRIC, "tmHeight") + DllStructGetData($tTEXTMETRIC, "tmExternalLeading") ; Size aperture window without bars DllCall("user32.dll", "bool", "GetClientRect", "hwnd", $hWnd, "ptr", DllStructGetPtr($tRect)) If @error Then Return SetError(@error, @extended, -3) Local $iX_Client_Full = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left") Local $iY_Client_Full = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top") $aSB_WindowInfo[$iIndex][4] = $iX_Client_Full $aSB_WindowInfo[$iIndex][5] = $iY_Client_Full ; Hide both scrollbars _GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, False) ; Show scrollbars and register scrollbar and mousewheel messages if required If $iH_Scroll Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ) GUIRegisterMsg($WM_HSCROLL, "_Scrollbars_WM_HSCROLL") GUIRegisterMsg($WM_MOUSEHWHEEL, '_Scrollbars_WM_MOUSEHWHEEL') EndIf If $iV_Scroll Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT) GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL") GUIRegisterMsg($WM_MOUSEWHEEL, "_Scrollbars_WM_MOUSEWHEEL") EndIf ; Size aperture window with bars DllCall("user32.dll", "bool", "GetClientRect", "hwnd", $hWnd, "ptr", DllStructGetPtr($tRect)) If @error Then Return SetError(@error, @extended, -3) Local $iX_Client_Bar = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left") Local $iY_Client_Bar = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top") ; If horizontal scrollbar is required Local $iH_FullPage If $iH_Scroll Then If $fBefore Then ; Use actual aperture width $aSB_WindowInfo[$iIndex][4] = $iX_Client_Bar ; Determine page size (aperture width / text width) $iH_FullPage = Floor($aSB_WindowInfo[$iIndex][4] / $aSB_WindowInfo[$iIndex][2]) ; Determine max size (scroll width / text width - tight) $aSB_WindowInfo[$iIndex][6] = Floor($iH_Scroll / $aSB_WindowInfo[$iIndex][2]) - $iH_Tight Else ; Use reduced aperture width only if other scrollbar exists If $iV_Scroll Then $aSB_WindowInfo[$iIndex][4] = $iX_Client_Bar ; Determine page size (aperture width / text width) $iH_FullPage = Floor($aSB_WindowInfo[$iIndex][4] / $aSB_WindowInfo[$iIndex][2]) ; Determine max size (scroll width / text width * correction factor for V scrollbar if required - tight) $aSB_WindowInfo[$iIndex][6] = Floor($iH_Scroll / $aSB_WindowInfo[$iIndex][2] * $aSB_WindowInfo[$iIndex][4] / $iX_Client_Full) - $iH_Tight EndIf Else $aSB_WindowInfo[$iIndex][6] = 0 EndIf ; If vertical scrollbar required Local $iV_FullPage If $iV_Scroll Then If $fBefore Then ; Use actual aperture height $aSB_WindowInfo[$iIndex][5] = $iY_Client_Bar ; Determine page size (aperture width / text width) $iV_FullPage = Floor($aSB_WindowInfo[$iIndex][5] / $aSB_WindowInfo[$iIndex][3]) ; Determine max size (scroll width / text width - tight) $aSB_WindowInfo[$iIndex][7] = Floor($iV_Scroll / $aSB_WindowInfo[$iIndex][3]) - $iV_Tight Else ; Use reduced aperture width only if other scrollbar exists If $iH_Scroll Then $aSB_WindowInfo[$iIndex][5] = $iY_Client_Bar ; Determine page size (aperture width / text width) $iV_FullPage = Floor($aSB_WindowInfo[$iIndex][5] / $aSB_WindowInfo[$iIndex][3]) ; Determine max size (scroll width / text width * correction factor for H scrollbar if required - tight) $aSB_WindowInfo[$iIndex][7] = Floor($iV_Scroll / $aSB_WindowInfo[$iIndex][3] * $aSB_WindowInfo[$iIndex][5] / $iY_Client_Full) - $iV_Tight EndIf Else $aSB_WindowInfo[$iIndex][7] = 0 EndIf Local $aRet[4] If $iV_Scroll Then $aRet[0] = $iX_Client_Bar Else $aRet[0] = $iX_Client_Full EndIf If $iH_Scroll Then $aRet[1] = $iY_Client_Bar Else $aRet[1] = $iY_Client_Full EndIf $aRet[2] = $iX_Client_Bar / $iX_Client_Full $aRet[3] = $iY_Client_Bar / $iY_Client_Full ; Save extended window info $aSB_WindowInfoEx[$iIndex][0] = $iH_Scroll $aSB_WindowInfoEx[$iIndex][1] = $iV_Scroll $aSB_WindowInfoEx[$iIndex][2] = $aRet[2] $aSB_WindowInfoEx[$iIndex][3] = $aRet[3] $aSB_WindowInfoEx[$iIndex][4] = $fBefore Local $fSuccess = True If _GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, False) = False Then $fSuccess = False If $iH_Scroll Then If _GUIScrollBars_SetScrollInfoMax($hWnd, $SB_HORZ, $aSB_WindowInfo[$iIndex][6]) = False Then $fSuccess = False _GUIScrollBars_SetScrollInfoPage($hWnd, $SB_HORZ, $iH_FullPage) If @error Then $fSuccess = False If _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ, True) = False Then $fSuccess = False Else If _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ, False) = False Then $fSuccess = False EndIf If $iV_Scroll Then If _GUIScrollBars_SetScrollInfoMax($hWnd, $SB_VERT, $aSB_WindowInfo[$iIndex][7]) = False Then $fSuccess = False _GUIScrollBars_SetScrollInfoPage($hWnd, $SB_VERT, $iV_FullPage) If @error Then $fSuccess = False If _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT, True) = False Then $fSuccess = False Else If _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT, False) = False Then $fSuccess = False EndIf If $fSuccess Then Return $aRet Return SetError(3, 0, 0) EndFunc ;==>_GUIScrollbars_Generate ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Locate_Ctrl ; Description ...: Calculates coordinates to use to position controls after scrollbar creation ; Syntax.........: _GUIScrollbars_Locate_Ctrl ($hWnd, $iX, $iY) ; Parameters ....: $hWnd -> GUI to contain control ; $iX -> Horizontal coordinate relative to scrollable area ; $iY -> Vertical coordinate relative to scrollable area ; Requirement(s).: v3.3.6.0 or higher ; Return values .: Success - Returns a 2-element array: ; [0] = Horizontal coordinate ; [1] = Vertical coordinate ; Failure - Returns either 0 with @error set as follows: ; 1 - Invalid window handle ; 2 - Parameter error ; 3 - Window not found ; Remarks .......; ; Author ........: Melba23 ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Locate_Ctrl($hWnd, $iX, $iY) ; Check $hWnd If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) ; Find window info Local $iIndex = -1 For $i = 0 To UBound($aSB_WindowInfo) - 1 If $hWnd = $aSB_WindowInfo[$i][0] Then $iIndex = $i Next If $iIndex = -1 Then Return SetError(3, 0, 0) ; Check if location is within scrollable area of the window If $iX < 0 Or $iX > $aSB_WindowInfoEx[$iIndex][0] Then Return SetError(2, 0, 0) If $iY < 0 Or $iY > $aSB_WindowInfoEx[$iIndex][1] Then Return SetError(2, 0, 0) ; Calculate factored coordinates if needed If Not $aSB_WindowInfoEx[$iIndex][4] Then $iX *= $aSB_WindowInfoEx[$iIndex][2] $iY *= $aSB_WindowInfoEx[$iIndex][3] EndIf ; Correct for any scrollbar movement $iX -= _GUIScrollBars_GetScrollInfoPos($hWnd, $SB_HORZ) * $aSB_WindowInfo[$iIndex][2] $iY -= _GUIScrollBars_GetScrollInfoPos($hWnd, $SB_VERT) * $aSB_WindowInfo[$iIndex][3] Local $aRet[2] = [$iX, $iY] Return $aRet EndFunc ;==>_GUIScrollbars_Locate_Ctrl ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Scroll_Page ; Description ...: Scrolls scrollbars generated by _GUIScrollbars_Generate to min, max or page number ; Syntax.........: _GUIScrollbars_Scroll_Page ($hWnd, [$iH_Scroll_Pos = -1, [$iV_Scroll_Pos = -1]]) ; Parameters ....: $hWnd -> GUI to contain scrollbars ; $iH_Scroll_Pos -> Horizontal age number: ; 0 = No change ; 1+ = Scroll to page number ; If page number is over max pages, then scroll to max position ; $iV_Scroll_Pos -> As $iH_Scroll_Pos for vertical pages ; Requirement(s).: v3.3.6.0 or higher ; Return values .: Success: @error = 0 ; Failure: @error set as follows: ; 1 - hWnd not a valid handle ; 2 - Scrollbars not generated in that GUI ; 3 - Invalid position parameters ; Remarks .......; ; Author ........: Melba23 ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Scroll_Page($hWnd, $iH_Scroll_Pos = 0, $iV_Scroll_Pos = 0) Local $iPos ; Check $hWnd If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) ; Check $iH/V_Scroll_Pos If Not (IsInt($iH_Scroll_Pos) And IsInt($iV_Scroll_Pos)) Then Return SetError(3, 0, 0) ; Find window info Local $iIndex = -1 For $i = 0 To UBound($aSB_WindowInfo) - 1 If $hWnd = $aSB_WindowInfo[$i][0] Then $iIndex = $i Next If $iIndex = -1 Then Return SetError(2, 0, 0) ; Get page sizes Local $iH_Page = Floor($aSB_WindowInfo[$iIndex][4] / $aSB_WindowInfo[$iIndex][2]) Local $iV_Page = Floor($aSB_WindowInfo[$iIndex][5] / $aSB_WindowInfo[$iIndex][3]) If $iH_Scroll_Pos > 0 Then $iPos = ($iH_Scroll_Pos - 1) * $iH_Page If $iPos > $aSB_WindowInfo[$iIndex][6] Then $iPos = $aSB_WindowInfo[$iIndex][6] _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_HORZ, $iPos) EndIf If $iV_Scroll_Pos > 0 Then $iPos = ($iV_Scroll_Pos - 1) * $iV_Page If $iPos > $aSB_WindowInfo[$iIndex][7] Then $iPos = $aSB_WindowInfo[$iIndex][7] _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, $iPos) EndIf EndFunc ;==>_GUIScrollbars_Scroll_Page ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Minimize ; Description ...: Stores scrollbar positions on GUI minimize ; Syntax.........: _GUIScrollbars_Minimize($hWnd) ; Parameters ....: $hWnd -> GUI containing scrollbars ; Requirement(s).: v3.3.6.0 or higher ; Return values .: Success: @error = 0 ; Failure: @error set as follows: ; 1 - hWnd not a valid handle ; 2 - Scrollbars not generated in that GUI ; Remarks .......; ; Author ........: Melba23, based on code from rover and czardas ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Minimize($hWnd) ; Check $hWnd If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) ; Find window info Local $iIndex = -1 For $i = 0 To UBound($aSB_WindowInfo) - 1 If $hWnd = $aSB_WindowInfo[$i][0] Then $iIndex = $i Next If $iIndex = -1 Then Return SetError(1, 0, 0) ; Show both scrollbars _GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, True) ; Get vertical current position and move to top $aSB_WindowInfo[$iIndex][8] = _GUIScrollBars_GetScrollPos($hWnd, $SB_VERT) _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, 0) ; Get horizontal current position and move to left $aSB_WindowInfo[$iIndex][9] = _GUIScrollBars_GetScrollPos($hWnd, $SB_HORZ) _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_HORZ, 0) EndFunc ; #FUNCTION# ========================================================================================================= ; Name...........: _GUIScrollbars_Restore ; Description ...: Restores scrollbar positions on GUI restore ; Syntax.........: _GUIScrollbars_Restore($hWnd[, $fVert = True[, $fHorz = True]]) ; Parameters ....: $hWnd -> GUI containing scrollbars ; $fVert -> True (default) = vertical scrollbar visible; False = vertical scrollbar not visible ; $fHorz -> True (default) = horizontal scrollbar visible; False = horzontal scrollbar not visible ; Requirement(s).: v3.3.6.0 or higher ; Return values .: Success: @error = 0 ; Failure: @error set as follows: ; 1 - hWnd not a valid handle ; 2 - Scrollbars not generated in that GUI ; Remarks .......; ; Author ........: Melba23, based on code from rover and czardas ; Example........; Yes ;===================================================================================================================== Func _GUIScrollbars_Restore($hWnd, $fVert = True, $fHorz = True) ; Check $hWnd If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) ; Find window info Local $iIndex = -1 For $i = 0 To UBound($aSB_WindowInfo) - 1 If $hWnd = $aSB_WindowInfo[$i][0] Then $iIndex = $i Next If $iIndex = -1 Then Return SetError(2, 0, 0) ; Rehide unwanted scrollbars If Not $fVert Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT, False) EndIf If Not $fHorz Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ, False) EndIf ; Reset visible scrollbars to position on minimize If $fVert Then _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, $aSB_WindowInfo[$iIndex][8]) EndIf If $fHorz Then _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_HORZ, $aSB_WindowInfo[$iIndex][9]) EndIf EndFunc ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _Scrollbars_WM_VSCROLL ; Description ...: GUIRegisterMsg procedure for vertical scrollbar ; Syntax ........: _Scrollbars_WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) ; Return values .: None ; Author ........: Taken from AutoIt Help file ; Remarks .......: This function is used internally by _Scrollbars_Generate ; =============================================================================================================================== Func _Scrollbars_WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Local $nScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $yChar, $yPos Local $Min, $Max, $Page, $Pos, $TrackPos For $x = 0 To UBound($aSB_WindowInfo) - 1 If $aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $yChar = $aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $Min = DllStructGetData($tSCROLLINFO, "nMin") $Max = DllStructGetData($tSCROLLINFO, "nMax") $Page = DllStructGetData($tSCROLLINFO, "nPage") $yPos = DllStructGetData($tSCROLLINFO, "nPos") $Pos = $yPos $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $nScrollCode Case $SB_TOP DllStructSetData($tSCROLLINFO, "nPos", $Min) Case $SB_BOTTOM DllStructSetData($tSCROLLINFO, "nPos", $Max) Case $SB_LINEUP DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1) Case $SB_LINEDOWN DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1) Case $SB_PAGEUP DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page) Case $SB_PAGEDOWN DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page) Case $SB_THUMBTRACK DllStructSetData($tSCROLLINFO, "nPos", $TrackPos) EndSwitch DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) $Pos = DllStructGetData($tSCROLLINFO, "nPos") If ($Pos <> $yPos) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos)) $yPos = $Pos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_VSCROLL ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _Scrollbars_WM_HSCROLL ; Description ...: GUIRegisterMsg procedure for horizontal scrollbar ; Syntax ........: _Scrollbars_WM_HSCROLL($hWnd, $Msg, $wParam, $lParam) ; Return values .: None ; Author ........: Taken from AutoIt Help file ; Remarks .......: This function is used internally by _Scrollbars_Generate ; =============================================================================================================================== Func _Scrollbars_WM_HSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $lParam Local $nScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $xChar, $xPos Local $Page, $Pos, $TrackPos For $x = 0 To UBound($aSB_WindowInfo) - 1 If $aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $xChar = $aSB_WindowInfo[$iIndex][2] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_HORZ) $Page = DllStructGetData($tSCROLLINFO, "nPage") $xPos = DllStructGetData($tSCROLLINFO, "nPos") $Pos = $xPos $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $nScrollCode Case $SB_LINELEFT DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1) Case $SB_LINERIGHT DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1) Case $SB_PAGELEFT DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page) Case $SB_PAGERIGHT DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page) Case $SB_THUMBTRACK DllStructSetData($tSCROLLINFO, "nPos", $TrackPos) EndSwitch DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_HORZ, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_HORZ, $tSCROLLINFO) $Pos = DllStructGetData($tSCROLLINFO, "nPos") If ($Pos <> $xPos) Then _GUIScrollBars_ScrollWindow($hWnd, $xChar * ($xPos - $Pos), 0) Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_HSCROLL ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _Scrollbars_WM_MOUSEWHEEL ; Description ...: GUIRegisterMsg procedure for vertical mouse wheel scroll ; Syntax ........: _Scrollbars_WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) ; Return values .: None ; Author ........: Based on code from MrCreator & Malkey ; Remarks .......: This function is used internally by _Scrollbars_Generate ; =============================================================================================================================== Func _Scrollbars_WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $lParam Local $iDirn, $iDelta = BitShift($wParam, 16) ; Mouse wheel movement If BitAND($wParam, 0x0000FFFF) Then ; If Ctrl or Shft pressed move Horz scrollbar $iDirn = $SB_LINERIGHT If $iDelta > 0 Then $iDirn = $SB_LINELEFT For $i = 1 To 7 _SendMessage($hWnd, $WM_HSCROLL, $iDirn) Next Else ; Move Vert scrollbar $iDirn = $SB_LINEDOWN If $iDelta > 0 Then $iDirn = $SB_LINEUP _SendMessage($hWnd, $WM_VSCROLL, $iDirn) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_MOUSEWHEEL ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _Scrollbars_WM_MOUSEHWHEEL ; Description ...: GUIRegisterMsg procedure for horizontal mouse wheel scroll ; Syntax ........: _Scrollbars_WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) ; Return values .: None ; Author ........: Based on code from MSDN, MrCreator & Malkey ; Remarks .......: This function is used internally by _Scrollbars_Generate ; =============================================================================================================================== Func _Scrollbars_WM_MOUSEHWHEEL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $lParam Local $iDirn = $SB_LINERIGHT If BitShift($wParam, 16) > 0 Then $iDirn = $SB_LINELEFT ; Mouse wheel movement For $i = 1 To 7 _SendMessage($hWnd, $WM_HSCROLL, $iDirn) Next Return $GUI_RUNDEFMSG EndFunc ;==>_Scrollbars_WM_MOUSEHWHEEL
I hope these 2 UDFs are useful to AutoIt users - I certainly find them so.
And here is a zip file with the UDFs and examples:
Scrollbars.zip 15.4K
1257 downloadsMy grateful thanks to the authors of the GUIScrollbars and WinAPI UDFs for their code, some of which I have plundered.
As always I welcome constructive criticism and/or effusive congratulations.
M23
Edited by Melba23, 20 January 2012 - 11:45 AM.







