GUIScroll-UDF - scrollbare GUIs

  • Hallo,

    als Alternative zu _GUIAutoSize() habe ich mich mit scrollbaren GUIs beschäftigt und mich darum bemüht, sie mit für den Skripter möglichst geringem Aufwand und möglichst wenigen Skriptzeilen und Includes zu erstellen und zu verwalten. So ist meine Version einer GUIScroll-UDF entstanden. Der Funktionskopf enthält eine meiner Meinung nach ausreichende Beschreibung.

    Demo:

    Spoiler anzeigen
    [autoit]

    #include <GUIConstantsEx.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>
    #include <WinAPI.au3>
    #include "GUIScroll.au3"

    [/autoit] [autoit][/autoit] [autoit]

    Dim $VS = _WinAPI_GetSystemMetrics(2) ; SM_CXVSCROLL
    Dim $HS = _WinAPI_GetSystemMetrics(3) ; SM_CYHSCROLL
    Dim $CW = 400
    Dim $CH = 400
    Dim $GW = $CW + $VS
    Dim $GH = $CH + $HS

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUICoordMode", 2)
    Dim $hGUI = GUICreate("Scroll Example", $GW, $GH, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_HSCROLL, $WS_VSCROLL))
    GUISetBkColor(0x88AABB)
    GUISetCoord(10, 10)
    Dim $I = 1
    GUICtrlCreateLabel("Edit " & $I, -1, -1, 380, 20, $SS_CENTERIMAGE)
    GUICtrlCreateInput("", -1, 0)
    For $I = 2 To 20
    GUICtrlCreateLabel("Edit " & $I, -1, 0, -1, -1, $SS_CENTERIMAGE)
    GUICtrlCreateInput("", -1, 0)
    Next
    GUISetCoord(410, 10)
    $I = 21
    GUICtrlCreateLabel("Edit " & $I, -1, -1, 380, 20, $SS_CENTERIMAGE)
    GUICtrlCreateInput("", -1, 0)
    For $I = 22 To 40
    GUICtrlCreateLabel("Edit " & $I, -1, 0, -1, -1, $SS_CENTERIMAGE)
    GUICtrlCreateInput("", -1, 0)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    _GUIScroll_Init($hGUI, 0) ; SB_HORZ
    _GUIScroll_Init($hGUI, 1, 1) ; SB_VERT

    [/autoit] [autoit][/autoit] [autoit]

    While True
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    ExitLoop
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit]


    GUIScroll.au3:

    Spoiler anzeigen
    [autoit]

    #include-Once

    [/autoit] [autoit][/autoit] [autoit]

    ; #INDEX# =======================================================================================================================
    ; Title .........: GUIScroll
    ; AutoIt Version : 3.3.6.1
    ; Language ......: Deutsch
    ; Description ...: Funktionen für ein scrollbares GUI.
    ; Author(s) .....: Großvater & http://www.autoit.de
    ; ===============================================================================================================================

    [/autoit] [autoit][/autoit] [autoit]

    ; #CURRENT# =====================================================================================================================
    ;_GUIScroll_Init
    ; ===============================================================================================================================

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ;__GUIScroll_Delta
    ;__GUIScroll_Max
    ;__GUIScroll_GetInfo
    ;__GUIScroll_SetInfo
    ;__GUIScroll_Restore
    ;__GUIScroll_Wheel
    ;__GUIScroll_HWheel
    ;__GUIScroll_Scroll
    ; ===============================================================================================================================

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _GUIScroll_Init
    ; Description ...: Initialisierung der Behandlung der Scrollnachrichten WM_HSCROLL und/oder WM_VSCROLL
    ; in "scrollbaren" GUIs.
    ; Für die entsprechende Nachricht wird mit GUIRegisterMsg() eine Funktion registriert,
    ; die Scrollbars werden mit den passenden Werten initialisiert.
    ; Syntax.........: _GUIScroll_Init($hWnd, $fnBar[, $bWheel = False[, $iDelta = Default[, $iPage = Default[, $iMax = Default]]]])
    ; Parameters ....: $hWnd - HWND des GUI
    ; $fnBar - Art der Scrollbar:
    ; |0 - (SB_HORZ) = horizontal
    ; |1 - (SB_VERT) = vertikal
    ; $bWheel - WM_MOUSEWHEEL/WM_MOUSEHWHEEL für das Scrollen registrieren (WM_MOUSEHWHEEL gibt es erst ab Vista)
    ; |False : nein
    ; |True : ja
    ; |Default : nein
    ; $iDelta - Schrittweite in Pixeln
    ; - wird verwendet, wenn auf die äußeren Scrollbuttons geklickt oder per Mausrad gescrollt wird
    ; |Default : 5 Prozent von $iMax
    ; $iPage - Größe einer "Seite" in Pixeln
    ; - wird verwendet, wenn neben dem "Schieber" in die Scrollbar geklickt wird
    ; |Default : Aktuelle Breite/Höhe des Clientbereichs
    ; $iMax - Größe des Scrollbereichs in Pixeln
    ; |Default : Für die Darstellung aller Controls benötigte Breite/Höhe
    ; Return values .: Im Erfolgsfall: True
    ; Im Fehlerfall: False
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: Das GUI muss mit den Styles WS_HSCROLL und/oder WS_VSCROLL versehen sein, sonst passiert nichts.
    ; Die Funktion darf erst dann aufgerufen werden, wenn das GUI in der gewünschten Größe erstellt worden ist.
    ; Dabei ist immer zu beachten, dass AutoIt den tatsächlich benötigten oder vorgegebenen Clientbereich um
    ; die Breite/Höhe der Scrollbars vermindert.
    ; Weil ich AutoIt nicht davon abbringen konnte, den Fensterinhalt nach einem Restore immer wieder ab
    ; Position 0-0 neu zu zeichnen, wird auch die Nachricht WM_SYSCOMMAND für SC_RESTORE registriert.
    ; Wer eine der registrierten Nachrichten selbst auswerten will oder muss, muss sie nach dem Aufruf
    ; von _GUIScroll_Init() für die eigenen Funktionen registrieren und am Anfang der eigenen Funktionen
    ; die entsprechenden "internen" __GuiScroll-Funktionen mit den 4 Originalparametern aufrufen.
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _GUIScroll_Init($hWnd, $fnBar, $bWheel = False, $iDelta = Default, $iPage = Default, $iMax = Default)
    Local Static $GWL_STYLE = -16
    Local Static $SB_HORZ = 0, $SB_VERT = 1
    Local Static $WM_HSCROLL = 0x0114, $WM_VSCROLL = 0x0115, $WM_SYSCOMMAND = 0x0112
    Local Static $WM_MOUSEWHEEL = 0x020A, $WM_MOUSEHWHEEL = 0x020E
    Local Static $WS_HSCROLL = 0x100000, $WS_VSCROLL = 0x200000
    Local $aResult, $aScrollInfo, $aSize, $Msg
    If $fnBar <> $SB_HORZ And $fnBar <> $SB_VERT Then Return False
    $aResult = DllCall("User32.dll", "Bool", "IsWindow", "UInt", $hWnd)
    If Not $aResult[0] Then Return False
    $aResult = DllCall("User32.dll", "UInt", "GetWindowLong", "UInt", $hWnd, "Int", $GWL_STYLE)
    If $fnBar = $SB_HORZ And Not BitAnd($aResult[0], $WS_HSCROLL) Then Return False
    If $fnBar = $SB_VERT And Not BitAnd($aResult[0], $WS_VSCROLL) Then Return False
    If $iMax = Default Then
    $iMax = __GUIScroll_Max($hWnd, $fnBar)
    EndIf
    If $iPage = Default Then
    $aSize = WinGetClientSize($hWnd)
    If $fnBar = $SB_HORZ Then
    $iPage = $aSize[0]
    Else
    $iPage = $aSize[1]
    EndIf
    EndIf
    If $iDelta = Default Then
    $iDelta = Round($iMax / 20)
    EndIf
    __GUIScroll_Delta($fnBar, $iDelta)
    $aScrollInfo = __GUIScroll_GetInfo($hWnd, $fnBar)
    $aScrollInfo[0] = 0
    $aScrollInfo[1] = $iMax
    $aScrollInfo[2] = $iPage
    __GUIScroll_SetInfo($hWnd, $fnBar, $aScrollInfo)
    If $fnBar = $SB_HORZ Then
    GUIRegisterMsg($WM_HSCROLL, "__GUIScroll_Scroll")
    Else
    GUIRegisterMsg($WM_VSCROLL, "__GUIScroll_Scroll")
    EndIf
    GUIRegisterMsg($WM_SYSCOMMAND, "__GUIScroll_Restore")
    If $bWheel Then
    If $fnBar = $SB_VERT Then
    GUIRegisterMsg($WM_MOUSEWHEEL, "__GUIScroll_Wheel")
    Else
    GUIRegisterMsg($WM_MOUSEHWHEEL, "__GUIScroll_HWheel")
    EndIf
    EndIf
    Return True
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_Delta
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_Delta($fnBar, $SetValue = "")
    Static Local $Delta0 = 1, $Delta1 = 1
    If @NumParams = 2 Then Assign("Delta" & $fnBar, $SetValue, 4)
    Return Eval("Delta" & $fnBar)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_Max
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_Max($hWnd, $fnBar)
    Local Static $GW_CHILD = 5, $GW_HWNDNEXT = 2
    Local Static $Max0 = "INIT", $Max1 = "INIT"
    If $Max0 = "INIT" Then
    Local $aID, $aPos, $aResult, $Controls = False
    Local $aSize[4] = [99999, 99999, 0, 0]
    $aResult = DllCall("User32.dll", "HWND", "GetWindow", "HWND", $hWnd, "UInt", $GW_CHILD)
    If @error Or $aResult[0] = 0 Then Return False
    While $aResult[0]
    $aID = DllCall("User32.dll", "Int", "GetDlgCtrlID", "Hwnd", $aResult[0])
    $aPos = ControlGetPos($hWnd, "", $aID[0])
    $aPos[2] += $aPos[0]
    $aPos[3] += $aPos[1]
    If $aPos[0] < $aSize[0] Then $aSize[0] = $aPos[0]
    If $aPos[1] < $aSize[1] Then $aSize[1] = $aPos[1]
    If $aPos[2] > $aSize[2] Then $aSize[2] = $aPos[2]
    If $aPos[3] > $aSize[3] Then $aSize[3] = $aPos[3]
    $Controls = True
    $aResult = DllCall("User32.dll", "HWND", "GetWindow", "HWND", $aResult[0], "UInt", $GW_HWNDNEXT)
    If @error Then Return False
    $Max0 = $aSize[2] + $aSize[0]
    $Max1 = $aSize[3] + $aSize[1]
    WEnd
    If Not $Controls Then Return False
    EndIf
    Return Eval("Max" & $fnBar)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_GetInfo
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_GetInfo($hWnd, $fnBar)
    Local Static $SIF_ALL = 0x17
    Local Static $Size = 1, $Mask = 2, $Min = 3, $Max = 4, $Page = 5, $Pos = 6, $TrackPos = 7
    Local Static $SCROLLINFO = "INIT"
    If Not IsDllStruct($SCROLLINFO) Then
    $SCROLLINFO = DllStructCreate("UInt; UInt; Int; Int; UInt; Int; Int")
    DllStructSetData($SCROLLINFO, $Size, DllStructGetSize($SCROLLINFO))
    DllStructSetData($SCROLLINFO, $Mask, $SIF_ALL)
    EndIf
    Local $aResult = DllCall("User32.dll", "Bool", "GetScrollInfo", "Hwnd", $hWnd, "Int", $fnBar, "Ptr", DllStructGetPtr($SCROLLINFO))
    If @error Then Return SetError(@error, @extended, False)
    Local $aScrollInfo[5]
    $aScrollInfo[0] = DllStructGetData($SCROLLINFO, $Min)
    $aScrollInfo[1] = DllStructGetData($SCROLLINFO, $Max)
    $aScrollInfo[2] = DllStructGetData($SCROLLINFO, $Page)
    $aScrollInfo[3] = DllStructGetData($SCROLLINFO, $Pos)
    $aScrollInfo[4] = DllStructGetData($SCROLLINFO, $TrackPos)
    Return $aScrollInfo
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_SetInfo
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_SetInfo($hWnd, $fnBar, $aScrollInfo)
    Local Static $SIF_ALL = 0x17
    Local Static $Size = 1, $Mask = 2, $Min = 3, $Max = 4, $Page = 5, $Pos = 6, $TrackPos = 7
    Local Static $SCROLLINFO = "INIT"
    If Not IsArray($aScrollInfo) Or UBound($aScrollInfo) <> 5 Then Return SetError(1, 0, False)
    If Not IsDllStruct($SCROLLINFO) Then
    $SCROLLINFO = DllStructCreate("UInt; UInt; Int; Int; UInt; Int; Int")
    DllStructSetData($SCROLLINFO, $Size, DllStructGetSize($SCROLLINFO))
    DllStructSetData($SCROLLINFO, $Mask, $SIF_ALL)
    EndIf
    DllStructSetData($SCROLLINFO, $Min, $aScrollInfo[0])
    DllStructSetData($SCROLLINFO, $Max, $aScrollInfo[1])
    DllStructSetData($SCROLLINFO, $Page, $aScrollInfo[2])
    DllStructSetData($SCROLLINFO, $Pos, $aScrollInfo[3])
    DllStructSetData($SCROLLINFO, $TrackPos, $aScrollInfo[4])
    Local $aResult = DllCall("User32.dll", "Int", "SetScrollInfo", "Hwnd", $hWnd, "Int", $fnBar, "Ptr", DllStructGetPtr($SCROLLINFO), "Bool", 1)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_Restore
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_Restore($hWnd, $Msg, $wParam, $lParam)
    Local Static $SC_RESTORE = 0xF120
    Local Static $SB_HORZ = 0, $SB_VERT = 1
    Local $aScrollInfo
    If $wParam = $SC_RESTORE Then
    $aScrollInfo = __GUIScroll_GetInfo($hWnd, $SB_HORZ)
    $aScrollInfo[3] = 0
    __GUIScroll_SetInfo($hWnd, $SB_HORZ, $aScrollInfo)
    $aScrollInfo = __GUIScroll_GetInfo($hWnd, $SB_VERT)
    $aScrollInfo[3] = 0
    __GUIScroll_SetInfo($hWnd, $SB_VERT, $aScrollInfo)
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_Wheel
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_Wheel($hWnd, $Msg, $wParam, $lParam)
    Local Static $SB_LINEBACK = 0, $SB_LINEFORW = 1
    Local Static $WM_VSCROLL = 0x0115
    Local $UpDown
    If BitShift($wParam, 16) > 0 Then
    $UpDown = $SB_LINEBACK
    Else
    $UpDown = $SB_LINEFORW
    EndIf
    __GUIScroll_Scroll($hWnd, $WM_VSCROLL, $UpDown, 0)
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_HWheel
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_HWheel($hWnd, $Msg, $wParam, $lParam)
    Local Static $SB_LINEBACK = 0, $SB_LINEFORW = 1
    Local Static $WM_HSCROLL = 0x0114
    Local $UpDown
    If BitShift($wParam, 16) > 0 Then
    $UpDown = $SB_LINEBACK
    Else
    $UpDown = $SB_LINEFORW
    EndIf
    __GUIScroll_Scroll($hWnd, $WM_HSCROLL, $UpDown, 0)
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __GUIScroll_Scroll
    ; Author ........: Großvater & http://www.autoit.de
    ; Modified.......:
    ; Remarks .......: For Internal Use Only
    ; ===============================================================================================================================
    Func __GUIScroll_Scroll($hWnd, $Msg, $wParam, $lParam)
    Local Static $SB_LINEBACK = 0, $SB_LINEFORW = 1
    Local Static $SB_PAGEBACK = 2, $SB_PAGEFORW = 3
    Local Static $SB_THUMBTRACK = 5
    Local Static $WM_HSCROLL = 0x0114, $WM_VSCROLL = 0x0115
    Local Static $SB_HORZ = 0, $SB_VERT = 1
    If Not $lParam = 0 Then Return $GUI_RUNDEFMSG
    Local $Delta = 0, $HScroll = 0, $VScroll = 0, $SB
    If $Msg = $WM_HSCROLL Then
    $SB = $SB_HORZ
    Else
    $SB = $SB_VERT
    EndIf
    Local $aScrollInfo = __GUIScroll_GetInfo($hWnd, $SB)
    Local $Pos = $aScrollInfo[3]
    $Delta = __GUIScroll_Delta($SB)
    Switch BitAND($wParam, 0x0000FFFF)
    Case $SB_LINEBACK
    $aScrollInfo[3] -= $Delta
    Case $SB_LINEFORW
    $aScrollInfo[3] += $Delta
    Case $SB_PAGEBACK
    $aScrollInfo[3] -= $aScrollInfo[2]
    Case $SB_PAGEFORW
    $aScrollInfo[3] += $aScrollInfo[2]
    Case $SB_THUMBTRACK
    $aScrollInfo[3] = $aScrollInfo[4]
    EndSwitch
    __GUIScroll_SetInfo($hWnd, $SB, $aScrollInfo)
    $aScrollInfo = __GUIScroll_GetInfo($hWnd, $SB)
    If ($Pos <> $aScrollInfo[3]) Then
    If $SB = $SB_HORZ Then
    $HScroll = $Pos - $aScrollInfo[3]
    Else
    $VScroll = $Pos - $aScrollInfo[3]
    EndIf
    DllCall("User32.dll", "Bool", "ScrollWindow", "Hwnd", $hWnd, "Int", $HScroll, "Int", $VScroll, "ptr", 0, "ptr", 0)
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit]