Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2 Topic is solved

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

Nussbeisser
Posts: 118
Joined: 17 Jul 2019, 08:49

Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

05 Apr 2024, 15:53

Hallo zusammen,
wurde die Klasse "Class_ScrollGUI" von just me auf AHK V2 aktualisiert?
vielen Dank im Voraus!
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

11 Apr 2024, 06:52

Moin @Nussbeisser,

ich habe noch eine weitgehend umgestellte Version gefunden (die Methode AdjustToChild() fehlt). Du kannst das ja mal ausprobieren:

Code: Select all

#Requires AutoHotkey v2.0
; ======================================================================================================================
; Namepace:       ScrollGUI
; Function:       Creates a scrollable GUI as a parent for GUI windows.
; Tested with:    AHK 2.0.2
; Tested on:      Win 10 Pro (x64)
; License:        The Unlicense -> http://unlicense.org
; Change log:     2.0.0/2023-01-??/just me            - Initial release for AHK v2
; ======================================================================================================================
Class ScrollGUI {
   ; ===================================================================================================================
   ; __New          Creates a scrollable parent window (ScrollGUI) for the passed GUI.
   ; Parameters:
   ;    Child       -  The GUI object of the child window.
   ;    Width       -  Width of the client area of the ScrollGUI.
   ;                   Pass 0 to set the client area to the width of the child GUI.
   ;    Height      -  Height of the client area of the ScrollGUI.
   ;                   Pass 0 to set the client area to the height of the child GUI.
   ;    ----------- Optional:
   ;    GuiOpts     -  GUI options to be used when creating the ScrollGUI (e.g. +LabelMyLabel).
   ;                   Default: empty (no options)
   ;    ScrollBars  -  Scroll bars to register:
   ;                   1 : horizontal
   ;                   2 : vertical
   ;                   3 : both
   ;                   Default: 3
   ;    Wheel       -  Register WM_MOUSEWHEEL / WM_MOUSEHWHEEL messages:
   ;                   1 : register WM_MOUSEHWHEEL for horizontal scrolling (reqires Win Vista+)
   ;                   2 : register WM_MOUSEWHEEL for vertical scrolling
   ;                   3 : register both
   ;                   4 : register WM_MOUSEWHEEL for vertical and Shift+WM_MOUSEWHEEL for horizontal scrolling
   ;                   Default: 0
   ; Return values:
   ;    On failure:    False
   ; Remarks:
   ;    The dimensions of the child GUI are determined internally according to the visible children.
   ;    The maximum width and height of the parent GUI will be restricted to the dimensions of the child GUI.
   ;    If you register mouse wheel messages, the messages will be passed to the focused control, unless the mouse 
   ;    is hovering on one of the ScrollGUI's scroll bars. If the control doesn't process the message, it will be
   ;    returned back to the ScrollGUI.
   ;    Common controls seem to ignore wheel messages whenever the CTRL is down. So you can use this modifier to 
   ;    scroll the ScrollGUI even if a scrollable control has the focus.
   ; ===================================================================================================================
   BF_SCROLL := 0
   BF_SIZE := 0
   BF_WHEEL := 0
   Child := 0
   Parent := 0
   ; ===================================================================================================================
   __New(Child, Width := 0, Height := 0, GuiOpts := "", ScrollBars := 3, Wheel := 0) {
      Static WS_HSCROLL := "0x100000", WS_VSCROLL := "0x200000"
      If !(Type(Child) = "Gui")
         Throw TypeError("Paramweter Child must be a Gui object!", -1, Type(Child))
      HGUI := Child.Hwnd
      If !(Type(Width) = "Integer")
         Throw TypeError("Paramweter Width must be an integer!", -1, Type(Width))
      If !(Type(Height) = "Integer")
         Throw TypeError("Paramweter Height must be an integer!", -1, Type(Height))
      If !(Type(ScrollBars) = "Integer")
         Throw TypeError("Paramweter ScrollBars must be an integer!", -1, Type(ScrollBars))
      If !(Type(Wheel) = "Integer")
         Throw TypeError("Paramweter Wheel must be an integer!", -1, Type(Wheel))
      Bars := ScrollBars & 3
      Wheel &= 7
      If (Bars = 0)
         Throw ValueError("Paramweter ScrollBars must be an integer between 1 and 3!", -1, ScrollBars)
      AutoSize := (Width = -1)
      This.BF_SCROLL := ObjBindMethod(This, "On_WM_Scroll")
      This.BF_SIZE   := ObjBindMethod(This, "On_WM_Size")
      This.BF_WHEEL  := ObjBindMethod(This, "On_WM_Wheel")
      Child.Opt("-Caption -Resize")
      Child.Show((AutoSize ? "AutoSize " : "") . "Hide")
      Child.GetClientPos( , , &GW, &GH)
      WinGetClientPos( , , &CW, &CH, Child.Hwnd)
      MaxH := CW
      MaxV := CH
      LineH := Ceil(MaxH / 20)
      LineV := Ceil(MaxV / 20)
      ; ScrollGUI
      If (Width = 0)
         Width := GW
      If (Height = 0)
         Height := GH
      Styles := (Bars & 1 ? " +" . WS_HSCROLL : "") . (Bars & 2 ? " +" . WS_VSCROLL : "")
      Parent := Gui(GuiOpts . Styles)
      Parent.Show("w" . Width . " h" . Height . " Hide")
      If AutoSize
         Parent.Opt("+MaxSize" . GW . "x" . GH)
      WinGetClientPos( , , &CW, &CH, Parent.Hwnd)
      PageH := CW + 1
      PageV := CH + 1
      ; Instance variables
      This.Parent := Parent
      This.Child := Child
      This.Width := Width
      This.Height := Height
      This.UseShift := False
      If (Bars & 1) {
         This.SetScrollInfo(0, {Max: MaxH, Page: PageH, Pos: 0}) ; SB_HORZ = 0
         OnMessage(0x0114, This.BF_SCROLL) ; WM_HSCROLL = 0x0114
         If (Wheel & 1)
            OnMessage(0x020E, This.BF_WHEEL) ; WM_MOUSEHWHEEL = 0x020E
         Else If (Wheel & 4) {
            OnMessage(0x020A, This.BF_WHEEL) ; WM_MOUSEWHEEL = 0x020A
            This.UseShift := True
         }
         This.MaxH := MaxH
         This.LineH := LineH
         This.PageH := PageH
         This.PosH := 0
         This.ScrollH := True
         If (Wheel & 5)
            This.WheelH := True
      }
      If (Bars & 2) {
         This.SetScrollInfo(1, {Max: MaxV, Page: PageV, Pos: 0}) ; SB_VERT = 1
         OnMessage(0x0115, This.BF_SCROLL) ; WM_VSCROLL = 0x0115
         If (Wheel & 6)
            OnMessage(0x020A, This.BF_WHEEL) ; WM_MOUSEWHEEL = 0x020A
         This.MaxV := MaxV
         This.LineV := LineV
         This.PageV := PageV
         This.PosV := 0
         This.ScrollV := True
         If (Wheel & 6)
            This.WheelV := True
      }
      ; Set the position of the child GUI
      Child.Opt("+Parent" . Parent.Hwnd)
      Child.Show("x0 y0")
      ; Adjust the scroll bars
      This.Size()
      OnMessage(0x0005, This.BF_SIZE) ; WM_SIZE = 0x0005
   }
   ; ===================================================================================================================
   ; __Delete       Destroy the GUIs, if they still exist.
   ; ===================================================================================================================
   __Delete() {
      This.Destroy()
   }
   ; ===================================================================================================================
   ; Show           Shows the ScrollGUI.
   ; Parameters:
   ;    Title       -  Title of the ScrollGUI window
   ;    ShowOptions -  Gui, Show command options, width or height options are ignored
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; ===================================================================================================================
   Show(Title := "", ShowOptions := "") {
      ShowOptions := RegExReplace(ShowOptions, "i)\+?AutoSize")
      WH := Format(" w{:} h{:}", This.Width, This.Height)
      If Title != ""
         This.Parent.Title := Title
      This.Parent.Show(ShowOptions . WH)
      Return True
   }
   ; ===================================================================================================================
   ; Destroy        Destroys the ScrollGUI and the associated child GUI.
   ; Parameters:
   ;    None.
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; Remarks:
   ;    Use this method instead of 'Gui, Destroy' to remove the ScrollGUI from the 'Instances' object.
   ; ===================================================================================================================
   Destroy() {
      If This.Parent {
         This.Parent.Destroy()
         This.Parent := 0
      }
      If This.BF_SCROLL {
         OnMessage(0x0114, This.BF_SCROLL, 0) ; WM_HSCROLL = 0x0114
         This.BF_SCROLL := 0
      }
      If This.BF_SIZE {
         OnMessage(0x0005, This.BF_SIZE, 0) ; WM_SIZE = 0x0005
         This.BF_SIZE := 0
      }
      If This.This.BF_WHEEL {
         OnMessage(0x020A, This.BF_WHEEL, 0) ; WM_MOUSEWHEEL = 0x020A
         OnMessage(0x020E, This.BF_WHEEL, 0) ; WM_MOUSEHWHEEL = 0x020E
         This.BF_WHEEL := 0
      }
      Return True
   }
   ; ===================================================================================================================
   ; AdjustToChild  Adjust the scroll bars to the new child dimensions.
   ; Parameters:
   ;    None
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; Remarks:
   ;    Call this method whenever the visible area of the child GUI has to be changed, e.g. after adding, hiding,
   ;    unhiding, resizing, or repositioning controls.
   ;    The dimensions of the child GUI are determined internally according to the visible children.
   ; ===================================================================================================================
   AdjustToChild() {
;       This.Child.GetPos(&CX, &CY, &CW, &CH)
;       VarSetCapacity(RC, 16, 0)
;       DllCall("User32.dll\GetWindowRect", "Ptr", This.HGUI, "Ptr", &RC)
;       PrevW := NumGet(RC, 8, "Int") - NumGet(RC, 0, "Int")
;       PrevH := Numget(RC, 12, "Int") - NumGet(RC, 4, "Int")
;       DllCall("User32.dll\ScreenToClient", "Ptr", This.HWND, "Ptr", &RC)
;       XC := XN := NumGet(RC, 0, "Int")
;       YC := YN := NumGet(RC, 4, "Int")
;       If !This.AutoSize(This.HGUI, GuiW, GuiH)
;          Return False
;       Gui, % This.HGUI . ":Show", x%XC% y%YC% w%GuiW% h%GuiH%
;       MaxH := GuiW
;       MaxV := GuiH
;       Gui, % This.HWND . ":+MaxSize" . MaxH . "x" . MaxV
;       If (GuiW < This.Width) || (GuiH < This.Height) {
;          Gui, % This.HWND . ":Show", w%GuiW% h%GuiH%
;          This.Width := GuiW
;          This.SetPage(1, MaxH + 1)
;          This.Height := GuiH
;          This.SetPage(2, MaxV + 1)
;       }
;       LineH := Ceil(MaxH / 20)
;       LineV := Ceil(MaxV / 20)
;       If This.ScrollH {
;          This.SetMax(1, MaxH)
;          This.LineH := LineH
;          If (XC + MaxH) < This.Width {
;             XN += This.Width - (XC + MaxH)
;             If (XN > 0)
;                XN := 0
;             This.SetScrollInfo(0, {Pos: XN * -1})
;             This.GetScrollInfo(0, SI)
;             This.PosH := NumGet(SI, 20, "Int")
;          }
;       }
;       If This.ScrollV {
;          This.SetMax(2, MaxV)
;          This.LineV := LineV
;          If (YC + MaxV) < This.Height {
;             YN += This.Height - (YC + MaxV)
;             If (YN > 0)
;                YN := 0
;             This.SetScrollInfo(1, {Pos: YN * -1})
;             This.GetScrollInfo(1, SI)
;             This.PosV := NumGet(SI, 20, "Int")
;          }
;       }
;       If (XC != XN) || (YC != YN)
;          DllCall("User32.dll\ScrollWindow", "Ptr", This.Parent.Hwnd, "Int", XN - XC, "Int", YN - YC, "Ptr", 0, "Ptr", 0)
      Return True
   }
   ; ===================================================================================================================
   ; SetMax         Sets the width or height of the scrolling area.
   ; Parameters:
   ;    SB          -  Scroll bar to set the value for:
   ;                   1 = horizontal
   ;                   2 = vertical
   ;    Max         -  Width respectively height of the scrolling area in pixels
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; ===================================================================================================================
   SetMax(SB, Max) {
      ; SB_HORZ = 0, SB_VERT = 1
      SB--
      If (SB != 0) && (SB != 1)
         Return False
      If (SB = 0)
         This.MaxH := Max
      Else
         This.MaxV := Max
      Return This.SetScrollInfo(SB, {Max: Max})
   }
   ; ===================================================================================================================
   ; SetLine        Sets the number of pixels to scroll by line.
   ; Parameters:
   ;    SB          -  Scroll bar to set the value for:
   ;                   1 = horizontal
   ;                   2 = vertical
   ;    Line        -  Number of pixels.
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; ===================================================================================================================
   SetLine(SB, Line) {
      ; SB_HORZ = 0, SB_VERT = 1
      SB--
      If (SB != 0) && (SB != 1)
         Return False
      If (SB = 0)
         This.LineH := Line
      Else
         This.LineV := Line
      Return True
   }
   ; ===================================================================================================================
   ; SetPage        Sets the number of pixels to scroll by page.
   ; Parameters:
   ;    SB          -  Scroll bar to set the value for:
   ;                   1 = horizontal
   ;                   2 = vertical
   ;    Page        -  Number of pixels.
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; Remarks:
   ;    If the ScrollGUI is resizable, the page size will be recalculated automatically while resizing.
   ; ===================================================================================================================
   SetPage(SB, Page) {
      ; SB_HORZ = 0, SB_VERT = 1
      SB--
      If (SB != 0) && (SB != 1)
         Return False
      If (SB = 0)
         This.PageH := Page
      Else
         This.PageV := Page
      Return This.SetScrollInfo(SB, {Page: Page})
   }
   ; ===================================================================================================================
   GetScrollInfo(SB, &SI) {
      SI := Buffer(28, 0) ; SCROLLINFO
      NumPut("UInt", 28, "UInt", 0x17, SI) ; SIF_ALL = 0x17
      Return DllCall("GetScrollInfo", "Ptr", This.Parent.Hwnd, "Int", SB, "Ptr", SI, "UInt")
   }
   ; ===================================================================================================================
   SetScrollInfo(SB, Values) {
      Static SIF := {Max: 0x01, Page: 0x02, Pos: 0x04}
      Static Off := {Max: 12, Page: 16, Pos: 20}
      Mask := 0
      SI := Buffer(28, 0) ; SCROLLINFO
      NumPut("UInt", 28, SI)
      For Key, Value In Values.OwnProps() {
         If SIF.HasProp(Key) {
            Mask |= SIF.%Key%
            NumPut("UInt", Value, SI, Off.%Key%)
         }
      }
      If (Mask) {
         NumPut("UInt", Mask | 0x08, SI, 4) ; SIF_DISABLENOSCROLL = 0x08
         Return DllCall("SetScrollInfo", "Ptr", This.Parent.Hwnd, "Int", SB, "Ptr", SI, "UInt", 1, "UInt")
      }
      Return False
   }
   ; ===================================================================================================================
   On_WM_Scroll(WP, LP, Msg, HWND) {
      ; WM_HSCROLL = 0x0114, WM_VSCROLL = 0x0115
      If (HWND = This.Parent.Hwnd) && (((Msg = 0x0114) && This.ScrollH) || ((Msg = 0x0115) && This.ScrollV))
         Return This.Scroll(WP, LP, Msg, HWND)
   }
   ; ===================================================================================================================
   Scroll(WP, LP, Msg, HWND) {
      ; WM_HSCROLL = 0x0114, WM_VSCROLL = 0x0115
      Static SB_LINEMINUS := 0, SB_LINEPLUS := 1, SB_PAGEMINUS := 2, SB_PAGEPLUS := 3, SB_THUMBTRACK := 5
      If (LP != 0)
         Return
      SB := (Msg = 0x0114 ? 0 : 1) ; SB_HORZ : SB_VERT
      SC := WP & 0xFFFF
      SD := (Msg = 0x0114 ? This.LineH : This.LineV)
      SI := 0
      If !This.GetScrollInfo(SB, &SI)
         Return
      PA := PN := NumGet(SI, 20, "Int")
      Switch SC {
         Case 0: PN := PA - SD ; SB_LINEMINUS
         Case 1: PN := PA + SD ; SB_LINEPLUS
         Case 2: PN := PA - NumGet(SI, 16, "UInt") ; SB_PAGEMINUS
         Case 3: PN := PA + NumGet(SI, 16, "UInt") ; SB_PAGEPLUS
         Case 5: PN := NumGet(SI, 24, "Int") ; SB_THUMBTRACK
      }
      If (PN = PA)
         Return 0
      This.SetScrollInfo(SB, {Pos: PN})
      This.GetScrollInfo(SB, &SI)
      PN := NumGet(SI, 20, "Int")
      If (SB = 0)
         This.PosH := PN
      Else
         This.PosV := PN
      If (PA != PN) {
         HS := (Msg = 0x0114) ? PA - PN : 0
         VS := (Msg = 0x0115) ? PA - PN : 0
         DllCall("ScrollWindow", "Ptr", HWND, "Int", HS, "Int", VS, "Ptr", 0, "Ptr", 0)
      }
      Return 0
   }
   ; ===================================================================================================================
   On_WM_Size(WP, LP, Msg, HWND) {
      If (HWND = This.Parent.Hwnd) && ((WP = 0) || (WP = 2))
         Return This.Size(LP & 0xFFFF, (LP >> 16) & 0xFFFF)
   }
   ; ===================================================================================================================
   Size(Width := 0, Height := 0) {
      If (Width = 0) || (Height = 0)
         WinGetClientPos( , , &Width, &Height, This.Parent.Hwnd)
      SH := SV := 0
      If This.ScrollH && (Width != This.Width) {
         This.SetScrollInfo(0, {Page: Width + 1}),
         This.Width := Width,
         This.GetScrollInfo(0, &SI),
         PosH := NumGet(SI, 20, "Int"),
         SH := This.PosH - PosH,
         This.PosH := PosH
      }
      If This.ScrollV && (Height != This.Height) {
         This.SetScrollInfo(1, {Page: Height + 1}),
         This.Height := Height,
         This.GetScrollInfo(1, &SI),
         PosV := NumGet(SI, 20, "Int"),
         SV := This.PosV - PosV,
         This.PosV := PosV
      }
      If (SH) || (SV)
         DllCall("User32.dll\ScrollWindow", "Ptr", This.Parent.Hwnd, "Int", SH, "Int", SV, "Ptr", 0, "Ptr", 0)
      Return 0
   }
   ; ===================================================================================================================
   On_WM_Wheel(WP, LP, Msg, HWND) {
      ; MK_SHIFT = 0x0004, WM_MOUSEWHEEL = 0x020A, WM_MOUSEHWHEEL = 0x020E, WM_NCHITTEST = 0x0084
      If (HWND != This.Parent.Hwnd) {
         If (WinActive("A") = This.Parent.Hwnd) {
            OnBar := SendMessage(0x0084, 0, LP & 0xFFFFFFFF, This.Parent.Hwnd)
            If (OnBar = 6) && This.WheelH ; HTHSCROLL = 6
               Return This.Wheel(WP, LP, 0x020E, This.Parent.Hwnd)
            If (OnBar = 7) && This.WheelV ; HTVSCROLL = 7
               Return This.Wheel(WP, LP, 0x020A, This.Parent.Hwnd)
         }
      }
      Else If ((Msg = 0x020E) && This.WheelH) ||
              ((Msg = 0x020A) && (This.WheelV || (This.WheelH && This.UseShift && (WP & 0x0004))))
              Return This.Wheel(WP, LP, Msg, HWND)
   }
   ; ===================================================================================================================
   Wheel(WP, LP, Msg, HWND) {
      ; MK_SHIFT = 0x0004, WM_MOUSEWHEEL = 0x020A, WM_MOUSEHWHEEL = 0x020E, WM_HSCROLL = 0x0114, WM_VSCROLL = 0x0115
      ; SB_LINEMINUS = 0, SB_LINEPLUS = 1
      If (Msg = 0x020A) && This.UseShift && (WP & 0x0004)
         Msg := 0x020E
      Msg := (Msg = 0x020A ? 0x0115 : 0x0114)
      SB := ((WP >> 16) > 0x7FFF) || (WP < 0) ? 1 : 0
      Return This.Scroll(SB, 0, Msg, HWND)
   }
}
Minibeispiel:

Code: Select all

#Requires AutoHotkey v2.0.0
#Include Class_ScrollGUI.ahk
; -------------------------------------------------------------------------------------------------------------------
; ChildGUI 1
Lines := "1`n2`n3`n4`n5`n6`n7`n8"
ChildGui := Gui()
ChildGui.MarginX := 20
ChildGui.MarginY := 20
I := 0
ChildGui.AddText("w370 h20 0x200 Section", "Edit " . ++I)
ChildGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   ChildGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   ChildGui.AddEdit("xp y+0 wp r6", Lines)
}
ChildGui.AddText("ys wp h20 0x200", "Edit " . ++I)
ChildGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   ChildGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   ChildGui.AddEdit("xp y+0 wp r6", Lines)
}
; Create ScrollGUI1 with both horizontal and vertical scrollbars
SG1 := ScrollGUI(ChildGui, 300, 400, "+Resize +MinSize", , 3)
SG1.Parent.OnEvent("Close", Scroll1Close)
SG1.Parent.OnEvent("Escape", Scroll1Close)
; Show ScrollGUI1
SG1.Show("ScrollGUI1 Title", "")
Return
; ----------------------------------------------------------------------------------------------------------------------
Scroll1Close(*) {
   ExitApp
}
Nussbeisser
Posts: 118
Joined: 17 Jul 2019, 08:49

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

11 Apr 2024, 12:03

Hallo @Just me

Vielen Dank für deine Mühe!
Jetzt habe ich versucht, meine Schaltflächen zu platzieren, aber die letzte 3 erscheinen nicht.
Muss ich beim Positionieren auf etwas Bestimmtes achten?

Code: Select all

#Requires AutoHotkey v2.0.0
#Include Class_ScrollGUI.ahk
; -------------------------------------------------------------------------------------------------------------------
; ChildGUI 1
Lines := "1`n2`n3`n4`n5`n6`n7`n8"
ChildGui := Gui()
ChildGui.MarginX := 20
ChildGui.MarginY := 20
I := 0
ChildGui.AddText("w370 h20 0x200 Section", "Edit " . ++I)
ChildGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   ChildGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   ChildGui.AddEdit("xp y+0 wp r6", Lines)
}
ChildGui.AddText("ys wp h20 0x200", "Edit " . ++I)
ChildGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   ChildGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   ChildGui.AddEdit("xp y+0 wp r6", Lines)
}

ChildGui.SetFont("Norm","verdana")
MeinBtn := ChildGui.Add("Button", "Default w80 xm", "Starten")
MeinBtn := ChildGui.Add("Button", "w80", "Schliessen")
MeinBtn := ChildGui.Add("Button", " w80", "Speichern")
MeinBtn := ChildGui.Add("Button", "w80", "Öffnen")
MeinBtn := ChildGui.Add("Button", "w80 x+", "Ignorieren")
MeinBtn := ChildGui.Add("Button", "w80 x+", "Hilfe")



; Create ScrollGUI1 with both horizontal and vertical scrollbars
SG1 := ScrollGUI(ChildGui, 300, 400, "+Resize +MinSize", , 3)
SG1.Parent.OnEvent("Close", Scroll1Close)
SG1.Parent.OnEvent("Escape", Scroll1Close)
; Show ScrollGUI1
SG1.Show("ScrollGUI1 Title", "")
Return
; ----------------------------------------------------------------------------------------------------------------------
Scroll1Close(*) {
   ExitApp
}

SG1.Parent.OnEvent("Close", Scroll1Close) funktioniert bei mir nicht.
Das konnte mich mit ChildGui.OnEvent("Close", Scroll1Close) zum laufen bringen.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

12 Apr 2024, 01:35

Moin,

ich kann Deine Probleme nicht nachvollziehen. Arbeitest Du mit einem Display mit einer Auflösung ungleich 96 DPI?
Nussbeisser
Posts: 118
Joined: 17 Jul 2019, 08:49

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

12 Apr 2024, 08:55

Hallo Just me,

an DPI habe ich gar nicht gedacht. Ich habe einen 4K-Monitor, und bei voller Auflösung ist immer alles zu klein. Daher habe ich die Auflösung heruntergestellt. Wenn ich die empfohlene Auflösung wähle, sind die Schaltflächen an der richtigen Stelle.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

12 Apr 2024, 10:26

Ok, ich schaue mal, ob mir dazu etwas Kluges einfällt.
Ich melde mich wieder.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

21 Apr 2024, 04:27

Moin @Nussbeisser,

das hat etwas länger gedauert als ursprünglich gedacht. Ich habe hier mal eine aktualisierte Sammlung von Funktionen als Ersatz für die Klasse. Einige der neuen Eigenschaften von v2 erleichtern das erheblich. Die einzige Funktion, die Du brauchst, ist ScrollGUI_Init(). Die wird aufgerufen, wenn das Fenster anzeigebereit ist, also kurz vor dem Gui.Show(). Ein übergestülptes 'Elternfenster' gibt es nicht mehr. Alle Einstellungen des bisherigen 'Kindfensters' werden direkt übernommen. Probier doch mal bitte, ob das auch mit der veränderten Bildschirmauflösung funktioniert.

Code: Select all

#Requires AutoHotkey v2.0
Lines := "1`n2`n3`n4`n5`n6`n7`n8"
MainGui := Gui("+Resize +MinSize")
MainGui.MarginX := 20
MainGui.MarginY := 20
I := 0
MainGui.AddText("w370 h20 0x200 Section", "Edit " . ++I)
MainGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   MainGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   MainGui.AddEdit("xp y+0 wp r6", Lines)
}
MainGui.AddText("ys wp h20 0x200", "Edit " . ++I)
MainGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   MainGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   MainGui.AddEdit("xp y+0 wp r6", Lines)
}
MainGui.SetFont("Norm", "Verdana")
Btn1 := MainGui.Add("Button", "xm w80 Default", "Starten")
Btn2 := MainGui.Add("Button", "xm w80", "Schliessen")
Btn3 := MainGui.Add("Button", "xm w80", "Speichern")
Btn4 := MainGui.Add("Button", "xm w80", "Öffnen")
Btn5 := MainGui.Add("Button", "x+m yp w80", "Ignorieren")
Btn6 := MainGui.Add("Button", "x+m yp w80", "Hilfe")

ScrollGui_InitGui(MainGui, , 4)

MainGui.Show("w300 h300")
;=======================================================================================================================
; Namepace:       ScrollGUI
; Function:       Functions to make a GUI window scrollable.
; Tested with:    AHK 2.0.13
; Tested on:      Win 10 Pro (x64)
; License:        The Unlicense -> http://unlicense.org
; Change log:     1.0.0/2024-04-21/just me            - Initial release
;=======================================================================================================================
; Prepares a GUI window to be scrollable.
; Parameters:
;     GuiObj   -  GUI object
;     Bars     -  Scroll bars to register:
;                 1 : horizontal
;                 2 : vertical
;                 3 : both
;                 Default: 3
;     Wheels   -  Register WM_MOUSEWHEEL / WM_MOUSEHWHEEL messages:
;                 1 : register WM_MOUSEHWHEEL for horizontal scrolling (reqires Win Vista+)
;                 2 : register WM_MOUSEWHEEL for vertical scrolling
;                 3 : register both
;                 4 : register WM_MOUSEWHEEL for vertical and Shift+WM_MOUSEWHEEL for horizontal scrolling
;                 Default: 0
; Return value:
;     None
;=======================================================================================================================
ScrollGui_InitGui(GuiObj, Bars := 3, Wheels := 0) {
   Static ScrollH := 0, ScrollV := 0, WheelH := 0, WheelV := 0
   If !(GuiObj Is Gui)
      Throw TypeError("Paramweter GuiObj must be an GUI object!", -1, Type(GuiObj))
   If !(Type(Bars) = "Integer")
      Throw TypeError("Paramweter Bars must be an integer!", -1, Type(Bars))
   If (Bars < 1) || (Bars > 3)
      Throw ValueError("Paramweter Bars must be an integer between 1 and 3!", -1, Bars)
   If !(Type(Wheels) = "Integer")
      Throw TypeError("Paramweter Wheels must be an integer!", -1, Type(Wheels))
   If (Wheels < 0) || (Wheels > 4)
      Throw ValueError("Paramweter Wheels must be an integer between 0 and 4!", -1, Wheels)
   GuiObj.Opt((Bars & 1 ? "+" : "-") . "0x100000") ; WS_HSCROLL
   GuiObj.Opt((Bars & 2 ? "+" : "-") . "0x200000") ; WS_VSCROLL
   GuiObj.Opt("+Resize")
   If (Bars & 1) {
      If (ScrollH = 0) {
         OnMessage(0x0114, ScrollGui_Scroll) ; WM_HSCROLL
         ScrollH := 1
      }
      If (Wheels & 1) && (WheelH = 0) {
         OnMessage(0x020E, ScrollGui_Wheel) ; WM_MOUSEHWHEEL = 0x020E
         WheelH := 1
      }
      If (Wheels & 4) && (WheelV = 0) {
         OnMessage(0x020A, ScrollGui_Wheel) ; WM_MOUSEWHEEL = 0x020A
         WheelV := 1
      }
   }
   If (Bars & 2) {
      If (ScrollV = 0) {
         OnMessage(0x0115, ScrollGui_Scroll) ; WM_VSCROLL
         ScrollV := 1
      }
      If (Wheels & 6) && (WheelV = 0) {
         OnMessage(0x020A, ScrollGui_Wheel) ; WM_MOUSEWHEEL = 0x020A
         WheelV := 1
      }
   }
   GuiObj.OnEvent("Size", ScrollGui_Size)
   GuiObj.ScrollInfo := {Bars: Bars, Wheels: Wheels}
}
;=======================================================================================================================
ScrollGui_GetScrollInfo(GuiObj, Bar) {
   If !(GuiObj Is Gui)
      Throw TypeError("Paramweter GuiObj must be an GUI object!", -1, Type(GuiObj))
   If !(Type(Bar) = "Integer")
      Throw TypeError("Paramweter Bar must be an integer!", -1, Type(Bar))
   If (Bar < 0) || (Bar > 1)
      Throw ValueError("Paramweter Bar must be an integer between 0 and 1!", -1, Bar)
   Local SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", 0x17, SI) ; cbSize, fMask: SIF_ALL
   If !DllCall("GetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", SI, "UInt")
      Throw Error("DllCall GetScrollInfo failed with error " . A_LastError, -1)
   Return {Min:  NumGet(SI,  8, "Int"),  ; nMin
           Max:  NumGet(SI, 12, "Int"),  ; nMax
           Page: NumGet(SI, 16, "UInt"), ; nPage
           Pos:  NumGet(SI, 20, "Int")}  ; nPos
}
;=======================================================================================================================
ScrollGui_Scroll(WP, LP, Msg, HWND) {
   Static SCROLL_STEP := 10
   Critical -1
   Local GuiObj := GuiFromHwnd(WinExist())
   If !GuiObj || !(GuiObj.Hwnd = HWND) || !GuiObj.HasProp("ScrollInfo")
      Return
   Local Bar := (Msg = 0x0115) ; SB_HORZ=0, SB_VERT=1
   Local SI := ScrollGui_GetScrollInfo(GuiObj, Bar)
   Local NewPos := SI.Pos
   Switch (WP & 0xFFFF) {
      Case 0: NewPos -= SCROLL_STEP ; SB_LINEUP
      Case 1: NewPos += SCROLL_STEP ; SB_LINEDOWN
      Case 2: NewPos -= SI.Page     ; SB_PAGEUP
      Case 3: NewPos += SI.Page     ; SB_PAGEDOWN
      Case 4, 5: NewPos := WP >> 16 ; SB_THUMBTRACK, SB_THUMBPOSITION
      Default: Return
   }
   NewPos := Min(NewPos, SI.Max - SI.Page)
   NewPos := Max(SI.Min, NewPos)
   Local X := (Bar = 0) ? SI.Pos - NewPos : 0
   Local Y := (Bar = 1) ? SI.Pos - NewPos : 0
   If (X || Y) {
      ; Scroll contents of window and invalidate uncovered area.
      DllCall("ScrollWindow", "Ptr", HWND, "Int", X, "Int", Y, "Ptr", 0, "Ptr", 0)
      ; Update scroll bar.
      SI := Buffer(28, 0)
      NumPut("UInt", 28, "UInt", 4, SI) ; cbSize , fMask: SIF_POS = 0x04
      NumPut("Int", NewPos, SI, 20)
      DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", SI, "Int", 1)
   }
}
;=======================================================================================================================
ScrollGui_Wheel(WP, LP, Msg, HWND) {
   Critical -1
   Local GuiObj := GuiFromHwnd(WinExist())
   If !GuiObj || !(GuiObj.Hwnd = HWND) || !GuiObj.HasProp("ScrollInfo")
      Return
   Local Bars := GuiObj.ScrollInfo.Bars
   Local Wheels := GuiObj.ScrollInfo.Wheels
   If ((Msg = 0x020A) && (Bars & 1) && (Wheels & 4) && (WP & 0x04)) {
      Msg := 0x020E
   }
   If ((Msg = 0x020E) && (Bars & 1) && (Wheels & 5)) || ((Msg = 0x020A) && (Bars & 2) && (Wheels & 6)) {
      Local SB := (WP & 0x80000000) ? 1 : 0 ; SB_LINEDOWN = 1, SB_LINEUP = 0
      Local SM := (Msg = 0x020A) ? 0x0115 : 0x0114
      Return ScrollGui_Scroll(SB, 0, SM, HWND)
   }
}
;=======================================================================================================================
ScrollGui_Size(GuiObj, MinMax, Width, Height) {
   Critical -1
   If !(MinMax = 1) && GuiObj.HasProp("ScrollInfo")
      ScrollGui_UpdateBars(GuiObj, Width, Height)
}
;=======================================================================================================================
ScrollGui_GetTotalSize(GuiObj) {
   Local Width := 0, Height := 0
   Local GuiCtrl, X, Y, W, H
   For GuiCtrl In GuiObj {
      GuiCtrl.GetPos(&X, &Y, &W, &H)
      Width := Max(Width, W + X)
      Height := Max(Height, H + Y)
   }
   GuiObj.TotalWidth := Width + GuiObj.MarginX
   GuiObj.TotalHeight := Height + GuiObj.MarginY
}
;=======================================================================================================================
ScrollGui_UpdateBars(GuiObj, Width, Height) {
   ; SIF_RANGE = 0x01, SIF_PAGE = 0x02, SIF_DISABLENOSCROLL = 0x04, SB_HORZ = 0, SB_VERT = 1
   ; Calculate scrolling area.
   If !GuiObj.HasProp("TotalWidth")
      ScrollGui_GetTotalSize(GuiObj)
   Local TotalWidth := GuiObj.TotalWidth
   Local TotalHeight := GuiObj.TotalHeight
   ; Initialize SCROLLINFO.
   Local SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", 11, SI) ; cbSize , fMask: SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL
   ; Update horizontal scroll bar.
   NumPut("Int", TotalWidth, "Int", Width, SI, 12) ; nMax , nPage
   DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 0, "Ptr", SI, "Int", 1) ; SB_HORZ
   ; Update vertical scroll bar.
   NumPut("Int", TotalHeight, "UInt", Height, SI, 12) ; nMax , nPage
   DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 1, "Ptr", SI, "Int", 1) ; SB_VERT
}
;=======================================================================================================================
Nussbeisser
Posts: 118
Joined: 17 Jul 2019, 08:49

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

21 Apr 2024, 14:32

Hallo @just me
Vielen lieben Dank für deine Arbeit.
Es funktioniert nun auch mit der geänderten Bildschirmauflösung.

Ich habe zwei Fragen:

1. Ist es möglich, die Vertikalscrollgeschwindigkeit anzupassen? Wenn ich das Mausrad drehe, würde ich gerne mehrere Zeilen auf einmal nach oben oder unten scrollen können. Ich weiß, dass man die Mausgeschwindigkeit global einstellen kann, aber bei GUI ist sehr langsam.


2. Sobald ein Steuerelement unter den Mauszeiger gerät – sei es ein Text, ein Button oder ein Bild –, hört das Scrollen auf. Gibt es eine Möglichkeit, dieses Verhalten zu ändern?
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2  Topic is solved

22 Apr 2024, 08:59

Moin @Nussbeisser,

danke fürs Testen und die Rückmeldung. Zu Deinen Fragen:
  1. Es ist schwierig, die Werte für das 'zeilenweise' Scrollen in einem Control (hier das Gui-Fenster) zu ermitteln, das keine Zeilen hat. Ich habe jetzt versucht, die Werte für das vertikale und horizontale Scrollen variabel relativ zum gesamten Scrollbereich festzulegen. Außerdem übernimmt die Funktion die aktuellen Mauseinstellungen des Benutzers. Hat der einen Wert von 3 Zeilen für das vertikale Scrollen eingestellt, wird auch dreifach gescrollt. Als Hintertür kannst Du die Werte in GuiObjekt.ScrollInfo.DeltaX (horizontal) und GuiObjekt.ScrollInfo.DeltaY (vertikal) anpassen, wenn Dir das nicht gefällt.
  2. Seit dem Erstellen der ursprünglichen Klasse für v1 hat sich im System anscheinend einiges verändert. Ich habe damals in der Beschreibung der Klasse geschrieben:
    ; If you register mouse wheel messages, the messages will be passed to the focused control, unless the mouse
    ; is hovering on one of the ScrollGUI's scroll bars. If the control doesn't process the message, it will be
    ; returned back to the ScrollGUI.
    ; Common controls seem to ignore wheel messages whenever the CTRL is down. So you can use this modifier to
    ; scroll the ScrollGUI even if a scrollable control has the focus.
    Ich weiß nicht mehr, für welche Controls ich das festgestellt habe. Für die im Beispielfenster anhaltenen Buttons gilt es jedenfalls nicht (mehr). Und die Edits müssen die Scrollnachrichten bekommen. Zu dieser Frage habe ich deshalb nichts geändert bzw. ändern können.

Code: Select all

#Requires AutoHotkey v2.0
Lines := "1`n2`n3`n4`n5`n6`n7`n8"
MainGui := Gui("+Resize +MinSize")
MainGui.MarginX := 20
MainGui.MarginY := 20
I := 0
MainGui.AddText("w370 h20 0x200 Section", "Edit " . ++I)
MainGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   MainGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   MainGui.AddEdit("xp y+0 wp r6", Lines)
}
MainGui.AddText("ys wp h20 0x200", "Edit " . ++I)
MainGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   MainGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   MainGui.AddEdit("xp y+0 wp r6", Lines)
}
MainGui.SetFont("Norm", "Verdana")
Btn1 := MainGui.Add("Button", "xm w80 Default", "Starten")
Btn2 := MainGui.Add("Button", "xm w80", "Schliessen")
Btn3 := MainGui.Add("Button", "xm w80", "Speichern")
Btn4 := MainGui.Add("Button", "xm w80", "Öffnen")
Btn5 := MainGui.Add("Button", "x+m yp w80", "Ignorieren")
Btn6 := MainGui.Add("Button", "x+m yp w80", "Hilfe")

ScrollGui_InitGui(MainGui, , 3)

MainGui.Show("w300 h300")

Sleep(100)

MsgBox("TotalW: " . MainGui.ScrollInfo.TotalW . "`nDeltyX: " . MainGui.ScrollInfo.DeltaX . "`n" .
       "TotalH: " . MainGui.ScrollInfo.TotalH . "`nDeltyY: " . MainGui.ScrollInfo.DeltaY, "MainGui")



; ======================================================================================================================
; Namepace:       ScrollGUI
; Function:       Functions to make a GUI window scrollable.
; Tested with:    AHK 2.0.13
; Tested on:      Win 10 Pro (x64)
; License:        The Unlicense -> http://unlicense.org
; Change log:     1.0.0/2024-04-21/just me            - Initial release
; ======================================================================================================================
; Prepares a GUI window to be scrollable.
; Parameters:
;     GuiObj            -  GUI object
;     Bars              -  Scroll bars to register:
;                          1 : horizontal
;                          2 : vertical
;                          3 : both
;                          Default: 3
;     Wheels            -  Register WM_MOUSEWHEEL / WM_MOUSEHWHEEL messages:
;                          1 : register WM_MOUSEHWHEEL for horizontal scrolling (reqires Win Vista+)
;                              If not HWHEEL is present, use Shift+WM_MOUSEWHEEL instead.
;                          2 : register WM_MOUSEWHEEL for vertical scrolling
;                          3 : register both
;                          Default: 0
;     DisableNoScroll   -  Disable the scroll bars instead of removing them if the whole client area is visible.
;                          False : Remove
;                          True  : Disable
;                          Default: True
; Return value:
;     None
; Notes:
;     On success, the function adds a property called 'ScrollInfo' to the Gui-object. ScrollInfo contains an object
;     containing the following keys:
;        Bars              -  parameter Bars passed to this function.
;        Wheels            -  parameter Wheels passed to this function
;        DisableNoScroll   -  parameter DisableNoScroll passed to this function
;        DeltaX            -  default value in pixels used for horizontal scrolling by one unit (line)
;        DeltaY            -  default value in pixels used for horizontal scrolling by one unit (char)
;     You may change the values of DeltaX and/or DeltaY to adjust the amount of scrolling.
; ======================================================================================================================
ScrollGui_InitGui(GuiObj, Bars := 3, Wheels := 0, DisableNoScroll := True) {
   Static MouseVWheel := SysGet(75) ; SM_MOUSEWHEELPRESENT
   Static MouseHWheel := SysGet(91) ; SM_MOUSEHORIZONTALWHEELPRESENT
   Static ScrollH := 0, ScrollV := 0, WheelH := 0, WheelV := 0
   If !(GuiObj Is Gui)
      Throw TypeError("Paramweter GuiObj must be an GUI object!", -1, Type(GuiObj))
   If !(Type(Bars) = "Integer")
      Throw TypeError("Paramweter Bars must be an integer!", -1, Type(Bars))
   If (Bars < 1) || (Bars > 3)
      Throw ValueError("Paramweter Bars must be an integer between 1 and 3!", -1, Bars)
   If !(Type(Wheels) = "Integer")
      Throw TypeError("Paramweter Wheels must be an integer!", -1, Type(Wheels))
   If (Wheels < 0) || (Wheels > 3)
      Throw ValueError("Paramweter Wheels must be an integer between 0 and 3!", -1, Wheels)
   GuiObj.Opt((Bars & 1 ? "+" : "-") . "0x100000") ; WS_HSCROLL
   GuiObj.Opt((Bars & 2 ? "+" : "-") . "0x200000") ; WS_VSCROLL
   GuiObj.Opt("+Resize")
   If (Bars & 1) {
      If (ScrollH = 0) {
         OnMessage(0x0114, ScrollGui_Scroll) ; WM_HSCROLL
         ScrollH := 1
      }
      If (Wheels & 1){
         If (MouseHWheel) && (WheelH = 0) {
            OnMessage(0x020E, ScrollGui_Wheel) ; WM_MOUSEHWHEEL = 0x020E
            WheelH := 1
         }
         Else If (MouseVWheel) && (WheelV = 0)
            OnMessage(0x020A, ScrollGui_Wheel) ; WM_MOUSEWHEEL = 0x020A
            WheelV := 1
      }
   }
   If (Bars & 2) {
      If (ScrollV = 0) {
         OnMessage(0x0115, ScrollGui_Scroll) ; WM_VSCROLL
         ScrollV := 1
      }
      If (Wheels & 2) (MouseVWheel) && (WheelV = 0) {
         OnMessage(0x020A, ScrollGui_Wheel) ; WM_MOUSEWHEEL = 0x020A
         WheelV := 1
      }
   }
   GuiObj.OnEvent("Size", ScrollGui_Size)
   GuiObj.ScrollInfo := {Bars: Bars, Wheels: Wheels, DisableNoScroll: DisableNoScroll, DeltaX: 6, DeltaY: 12}
}
; ======================================================================================================================
ScrollGui_GetScrollInfo(GuiObj, Bar) {
   If !(GuiObj Is Gui)
      Throw TypeError("Paramweter GuiObj must be an GUI object!", -1, Type(GuiObj))
   If !(Type(Bar) = "Integer")
      Throw TypeError("Paramweter Bar must be an integer!", -1, Type(Bar))
   If (Bar < 0) || (Bar > 1)
      Throw ValueError("Paramweter Bar must be an integer between 0 and 1!", -1, Bar)
   Local SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", 0x17, SI) ; cbSize, fMask: SIF_ALL
   If !DllCall("GetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", SI, "UInt")
      Throw Error("DllCall GetScrollInfo failed with error " . A_LastError, -1)
   Return {Min:  NumGet(SI,  8, "Int"),  ; nMin
           Max:  NumGet(SI, 12, "Int"),  ; nMax
           Page: NumGet(SI, 16, "UInt"), ; nPage
           Pos:  NumGet(SI, 20, "Int")}  ; nPos
}
; ======================================================================================================================
ScrollGui_Scroll(WP, LP, Msg, HWND) {
   Critical -1
   Local GuiObj := GuiFromHwnd(WinExist())
   If !GuiObj || !(GuiObj.Hwnd = HWND) || !GuiObj.HasProp("ScrollInfo")
      Return
   Local Bar := (Msg = 0x0115) ; SB_HORZ=0, SB_VERT=1
   Local SI := ScrollGui_GetScrollInfo(GuiObj, Bar)
   Local NewPos := SI.Pos
   Local LineStep := (Bar = 0 ? GuiObj.ScrollInfo.DeltaX : GuiObj.ScrollInfo.DeltaY)
   Switch (WP & 0xFFFF) {
      Case 0: NewPos -= LineStep    ; SB_LINEUP
      Case 1: NewPos += LineStep    ; SB_LINEDOWN
      Case 2: NewPos -= SI.Page     ; SB_PAGEUP
      Case 3: NewPos += SI.Page     ; SB_PAGEDOWN
      Case 4, 5: NewPos := WP >> 16 ; SB_THUMBTRACK, SB_THUMBPOSITION
      Default: Return
   }
   Switch {
      Case (NewPos < SI.Min): NewPos := SI.Min
      Case (NewPos > (SI.Max - SI.Page)): NewPos := SI.Max - SI.Page
   }
   Local X := (Bar = 0) ? SI.Pos - NewPos : 0
   Local Y := (Bar = 1) ? SI.Pos - NewPos : 0
   If (X || Y) {
      ; Scroll contents of window and invalidate uncovered area.
      DllCall("ScrollWindow", "Ptr", HWND, "Int", X, "Int", Y, "Ptr", 0, "Ptr", 0)
      ; Update scroll bar.
      SI := Buffer(28, 0)
      NumPut("UInt", 28, "UInt", 4, SI) ; cbSize , fMask: SIF_POS = 0x04
      NumPut("Int", NewPos, SI, 20)
      DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", SI, "Int", 1)
   }
}
; ======================================================================================================================
ScrollGui_Wheel(WP, LP, Msg, HWND) {
   Static SCROLL_STEP := 10
   Static WheelScrollChars := GetWheelScrollChars()
   Static WheelScrollLines := GetWheelScrollLines()
   Critical -1
   Local GuiObj := GuiFromHwnd(HWND)
   If !GuiObj || !GuiObj.HasProp("ScrollInfo")
      Return
   Local WheelDelta := WP << 32 >> 48
   Local Bars := GuiObj.ScrollInfo.Bars
   Local Wheels := GuiObj.ScrollInfo.Wheels
   If ((Msg = 0x020A) && (Bars & 1) && (Wheels & 1) && (WP & 0x04)) {
      Msg := 0x020E
   }
   If ((Msg = 0x020E) && (Bars & 1) && (Wheels & 1)) || ((Msg = 0x020A) && (Bars & 2) && (Wheels & 2)) {
      Local Bar := (Msg = 0x020A)
      Local SI := ScrollGui_GetScrollInfo(GuiObj, Bar)
      Local NewPos := SI.Pos
      Local Dir := (WP & 0x80000000) ? 1 : -1
      Switch Bar {
         Case 0: NewPos += GuiObj.ScrollInfo.DeltaX * WheelScrollChars * Dir
         Case 1: NewPos += (WheelScrollLines = -1 ? SI.Page : GuiObj.ScrollInfo.DeltaY * WheelScrollLines) * Dir
      }
      Switch {
         Case (NewPos < SI.Min): NewPos := SI.Min
         Case (NewPos > (SI.Max - SI.Page)): NewPos := SI.Max - SI.Page
      }
      Local X := (Bar = 0) ? SI.Pos - NewPos : 0
      Local Y := (Bar = 1) ? SI.Pos - NewPos : 0
      If (X || Y) {
         ; Scroll contents of window and invalidate uncovered area.
         DllCall("ScrollWindow", "Ptr", GuiObj.Hwnd, "Int", X, "Int", Y, "Ptr", 0, "Ptr", 0)
         ; Update scroll bar.
         SI := Buffer(28, 0)
         NumPut("UInt", 28, "UInt", 4, SI) ; cbSize , fMask: SIF_POS = 0x04
         NumPut("Int", NewPos, SI, 20)
         DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", SI, "Int", 1)
      }
   }
   ; -------------------------------------------------------------------------------------------------------------------
   GetWheelScrollChars() {
      Local ScrollChars := 3 ; default
      DllCall("SystemParametersInfoW", "UInt", 0x006C, "UInt", 0, "UIntP", &ScrollChars, "UInt", 0)
      Return ScrollChars
   }
   GetWheelScrollLines() {
      Local ScrollLines := 3 ; default
      DllCall("SystemParametersInfoW", "UInt", 0x0068, "UInt", 0, "IntP", &ScrollLines, "UInt", 0)
      Return ScrollLines
   }
}
; ======================================================================================================================
ScrollGui_Size(GuiObj, MinMax, Width, Height) {
   Critical -1
   If !(MinMax = 1) && GuiObj.HasProp("ScrollInfo")
      ScrollGui_UpdateBars(GuiObj, Width, Height)
}
;=======================================================================================================================
ScrollGui_GetTotalSize(GuiObj) {
   If !GuiObj.HasProp("ScrollInfo")
      Return False
   Local Width := 0, Height := 0
   Local GuiCtrl, X, Y, W, H
   For GuiCtrl In GuiObj {
      GuiCtrl.GetPos(&X, &Y, &W, &H)
      Width := Max(Width, W + X)
      Height := Max(Height, H + Y)
   }
   Width += GuiObj.MarginX
   Height += GuiObj.MarginY
   GuiObj.ScrollInfo.TotalW := Width
   GuiObj.ScrollInfo.TotalH := Height
   GuiObj.ScrollInfo.DeltaX := Max(6, Width // 100)
   GuiObj.ScrollInfo.DeltaY := Max(12, Height // 100)
   GuiObj.Opt("+MaxSize" . Width . "x" . Height)
}
; ======================================================================================================================
ScrollGui_UpdateBars(GuiObj, Width, Height) {
   ; SIF_RANGE = 0x01, SIF_PAGE = 0x02, SIF_DISABLENOSCROLL = 0x08, SB_HORZ = 0, SB_VERT = 1
   ; Calculate scrolling area.
   If !GuiObj.HasProp("ScrollInfo")
      Return False
   Local DisableNoScroll := GuiObj.ScrollInfo.DisableNoScroll
   If !GuiObj.ScrollInfo.HasProp("TotalW")
      ScrollGui_GetTotalSize(GuiObj)
   Local TotalW:= GuiObj.ScrollInfo.TotalW
   Local TotalH := GuiObj.ScrollInfo.TotalH
   ; Initialize SCROLLINFO.
   Local Mask := 3 | (DisableNoScroll ? 8 : 0) ; SIF_RANGE | SIF_PAGE | ? SIF_DISABLENOSCROLL
   Local SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", Mask, SI) ; cbSize , fMask
   ; Update horizontal scroll bar.
   NumPut("Int", TotalW, "Int", Width, SI, 12) ; nMax , nPage
   DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 0, "Ptr", SI, "Int", 1) ; SB_HORZ
   ; Update vertical scroll bar.
   NumPut("Int", TotalH, "UInt", Height, SI, 12) ; nMax , nPage
   DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 1, "Ptr", SI, "Int", 1) ; SB_VERT
}
; ======================================================================================================================
Nussbeisser
Posts: 118
Joined: 17 Jul 2019, 08:49

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

22 Apr 2024, 13:22

Vielen Dank für die Hilfe. Die Scroll-Geschwindigkeit ist jetzt perfekt.

Das ist jetzt nur ein Luxusproblem aber gibt es eine einfache Möglichkeit, die Breite des Scrollbalkens anzupassen? Vielleicht durch eine Art 'SendMessage', um dem Scrollbalken mehr Platz zu geben. Aber ich könnte auch links neben der Scrollbalken etwas Platz lassen um störungsfreier zu Scrollen.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Aktualisierung der Klasse Class_ScrollGUI auf AuotHotkey Version 2

23 Apr 2024, 12:00

Moin @Nussbeisser,

die Breite der Scrollbalken ist im System definiert. Ich weiß nicht, ob und wie man die ändern kann.

Meine Funktionssammlung habe ich nochmal überarbeitet. Ich habe einige Fehler korrigiert und die Funktionen redaktionell überarbeitet.
Die Option 4 für den Parameter Wheels gibt es nicht mehr. Die Funktion prüft intern, ob die Maus horizontales Scrollen anbietet. Wenn nicht, wird das horizontale Scrollen automatisch auf Shift+Scrollrad gelegt, wenn ein horizontaler Scrollbalken angezeigt werden soll.

Code: Select all

#Requires AutoHotkey v2.0
Lines := "1`n2`n3`n4`n5`n6`n7`n8"
MainGui := Gui("+Resize +MinSize")
MainGui.MarginX := 20
MainGui.MarginY := 20
I := 0
MainGui.AddText("w370 h20 0x200 Section", "Edit " . ++I)
MainGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   MainGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   MainGui.AddEdit("xp y+0 wp r6", Lines)
}
MainGui.AddText("ys wp h20 0x200", "Edit " . ++I)
MainGui.AddEdit("xp y+0 wp r6")
Loop 4 {
   MainGui.AddText("xp y+0 wp h20 0x200", "Edit " . ++I)
   MainGui.AddEdit("xp y+0 wp r6", Lines)
}
MainGui.SetFont("Norm", "Verdana")
Btn1 := MainGui.Add("Button", "xm w80 Default", "Starten")
Btn2 := MainGui.Add("Button", "xm w80", "Schliessen")
Btn3 := MainGui.Add("Button", "xm w80", "Speichern")
Btn4 := MainGui.Add("Button", "xm w80", "Öffnen")
Btn5 := MainGui.Add("Button", "x+m yp w80", "Ignorieren")
Btn6 := MainGui.Add("Button", "x+m yp w80", "Hilfe")

ScrollGui_InitGui(MainGui, , 3)

MainGui.Show("w300 h300")

Sleep(100)

MsgBox("TotalW: " . MainGui.ScrollInfo.TotalW . "`nLineH: " . MainGui.ScrollInfo.LineH . "`n" .
       "TotalH: " . MainGui.ScrollInfo.TotalH . "`nLineV: " . MainGui.ScrollInfo.LineV, "MainGui")

; ======================================================================================================================
; Namepace:       ScrollGUI
; Function:       Functions to make a GUI window scrollable.
; Tested with:    AHK 2.0.13
; Tested on:      Win 10 Pro (x64)
; License:        The Unlicense -> http://unlicense.org
; Change log:     1.0.0/2024-04-21/just me            - Initial release
; ======================================================================================================================
; Prepares a GUI window to be scrollable.
; Parameters:
;     GuiObj            -  GUI object
;     Bars              -  Scroll bars to register:
;                          1 : horizontal
;                          2 : vertical
;                          3 : both
;                          Default: 3
;     Wheels            -  Register WM_MOUSEWHEEL / WM_MOUSEHWHEEL messages:
;                          1 : register WM_MOUSEHWHEEL for horizontal scrolling (reqires Win Vista+)
;                              If not HWHEEL is present, use Shift+WM_MOUSEWHEEL instead.
;                          2 : register WM_MOUSEWHEEL for vertical scrolling
;                          3 : register both
;                          Default: 0
;     DisableNoScroll   -  Disable the scroll bars instead of removing them if the whole client area is visible.
;                          False : Remove
;                          True  : Disable
;                          Default: True
; Return value:
;     None
; Notes:
;     On success, the function adds a property called 'ScrollInfo' to the Gui-object. ScrollInfo contains an object
;     containing the following keys:
;           Bars     -  parameter Bars passed to this function.
;           Wheels   -  parameter Wheels passed to this function
;           Disable  -  parameter DisableNoScroll passed to this function
;           LineH    -  default value in pixels used for horizontal scrolling by one unit (char)
;           LineV    -  default value in pixels used for vertical scrolling by one unit (line)
;           PosH     -  current horizontal scroll position
;           PosV     -  current vertical scroll position
;           TotalH   -  total height of the scrolling area
;           TotalW   -  total width of the scrolling area
;     You may change the values of LineH and/or LineV to adjust the amount of scrolling. You must not touch any other
;     property.
; ======================================================================================================================
ScrollGui_InitGui(GuiObj, Bars := 3, Wheels := 0, DisableNoScroll := True) {
   Static MouseVWheel := SysGet(75) ; SM_MOUSEWHEELPRESENT
   Static MouseHWheel := SysGet(91) ; SM_MOUSEHORIZONTALWHEELPRESENT
   Static ScrollH := 0, ScrollV := 0, WheelH := 0, WheelV := 0
   If !(GuiObj Is Gui)
      Throw TypeError("Paramweter GuiObj must be an GUI object!", -1, Type(GuiObj))
   If !(Type(Bars) = "Integer")
      Throw TypeError("Paramweter Bars must be an integer!", -1, Type(Bars))
   If (Bars < 1) || (Bars > 3)
      Throw ValueError("Paramweter Bars must be an integer between 1 and 3!", -1, Bars)
   If !(Type(Wheels) = "Integer")
      Throw TypeError("Paramweter Wheels must be an integer!", -1, Type(Wheels))
   If (Wheels < 0) || (Wheels > 3)
      Throw ValueError("Paramweter Wheels must be an integer between 0 and 3!", -1, Wheels)
   GuiObj.Opt((Bars & 1 ? "+" : "-") . "0x100000") ; WS_HSCROLL
   GuiObj.Opt((Bars & 2 ? "+" : "-") . "0x200000") ; WS_VSCROLL
   GuiObj.Opt("+Resize")
   If (Bars & 1) {
      If (ScrollH = 0) {
         OnMessage(0x0114, ScrollGui_Scroll) ; WM_HSCROLL
         ScrollH := 1
      }
      If (Wheels & 1){
         If (MouseHWheel) && (WheelH = 0) {
            OnMessage(0x020E, ScrollGui_Wheel) ; WM_MOUSEHWHEEL = 0x020E
            WheelH := 1
         }
         Else If (MouseVWheel) && (WheelV = 0)
            OnMessage(0x020A, ScrollGui_Wheel) ; WM_MOUSEWHEEL = 0x020A
            WheelV := 1
      }
   }
   If (Bars & 2) {
      If (ScrollV = 0) {
         OnMessage(0x0115, ScrollGui_Scroll) ; WM_VSCROLL
         ScrollV := 1
      }
      If (Wheels & 2) && (MouseVWheel) && (WheelV = 0) {
         OnMessage(0x020A, ScrollGui_Wheel) ; WM_MOUSEWHEEL = 0x020A
         WheelV := 1
      }
   }
   GuiObj.OnEvent("Size", ScrollGui_Size)
   Local DNS := DisableNoScroll ? 8 : 0
   GuiObj.ScrollInfo := {Bars: Bars, Wheels: Wheels, Disable: DNS, LineH: 6, LineV: 12, PosH: 0, PosV: 0}
}
; ======================================================================================================================
ScrollGui_Scroll(WP, LP, Msg, HWND) {
   Critical -1
   Local GuiObj := GuiFromHwnd(WinExist())
   If !GuiObj || !(GuiObj.Hwnd = HWND) || !GuiObj.HasProp("ScrollInfo")
      Return
   Local Bar := (Msg = 0x0115) ; SB_HORZ=0, SB_VERT=1
   Local SI := ScrollGui_GetScrollInfo(GuiObj, Bar)
   Local NewPos := SI.Pos
   Local LineStep := (Bar = 0 ? GuiObj.ScrollInfo.LineH : GuiObj.ScrollInfo.LineV)
   Switch (WP & 0xFFFF) {
      Case 0: NewPos -= LineStep    ; SB_LINEUP
      Case 1: NewPos += LineStep    ; SB_LINEDOWN
      Case 2: NewPos -= SI.Page     ; SB_PAGEUP
      Case 3: NewPos += SI.Page     ; SB_PAGEDOWN
      Case 4, 5: NewPos := WP >> 16 ; SB_THUMBTRACK, SB_THUMBPOSITION
      Default: Return
   }
   NewPos := Max(SI.Min, NewPos)
   NewPos := Min(SI.Max - SI.Page + 1, NewPos)
   Local X := (Bar = 0) ? SI.Pos - NewPos : 0
   Local Y := (Bar = 1) ? SI.Pos - NewPos : 0
   If (X || Y) {
      ; Scroll contents of window and invalidate uncovered area.
      DllCall("ScrollWindow", "Ptr", HWND, "Int", X, "Int", Y, "Ptr", 0, "Ptr", 0)
      ; Update scroll bar.
      DllCall("SetScrollPos", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", NewPos, "Int", 1)
      Switch Bar {
         Case 0: GuiObj.ScrollInfo.PosH := NewPos
         Case 1: GuiObj.ScrollInfo.PosV := NewPos
      }
   }
}
; ======================================================================================================================
ScrollGui_Wheel(WP, LP, Msg, HWND) {
   Static SCROLL_STEP := 10
   Static WheelScrollChars := GetWheelScrollChars()
   Static WheelScrollLines := GetWheelScrollLines()
   Critical -1
   Local GuiObj := GuiFromHwnd(HWND)
   If !GuiObj || !GuiObj.HasProp("ScrollInfo")
      Return
   Local WheelDelta := WP << 32 >> 48
   Local Bars := GuiObj.ScrollInfo.Bars
   Local Wheels := GuiObj.ScrollInfo.Wheels
   If ((Msg = 0x020A) && (Bars & 1) && (Wheels & 1) && (WP & 0x04)) {
      Msg := 0x020E
   }
   If ((Msg = 0x020E) && (Bars & 1) && (Wheels & 1)) || ((Msg = 0x020A) && (Bars & 2) && (Wheels & 2)) {
      Local Bar := (Msg = 0x020A)
      Local SI := ScrollGui_GetScrollInfo(GuiObj, Bar)
      Local NewPos := SI.Pos
      Local Dir := (WheelDelta < 0) ? 1 : -1
      Switch Bar {
         Case 0: NewPos += GuiObj.ScrollInfo.LineH * WheelScrollChars * Dir
         Case 1: NewPos += (WheelScrollLines = -1 ? SI.Page : GuiObj.ScrollInfo.LineV * WheelScrollLines) * Dir
      }
      NewPos := Max(SI.Min, NewPos)
      NewPos := Min(SI.Max - SI.Page + 1, NewPos)
      Local ScrollH := (Bar = 0) ? SI.Pos - NewPos : 0
      Local ScrollV := (Bar = 1) ? SI.Pos - NewPos : 0
      If (ScrollH || ScrollV) {
         ; Scroll contents of window and invalidate uncovered area.
         DllCall("ScrollWindow", "Ptr", GuiObj.Hwnd, "Int", ScrollH, "Int", ScrollV, "Ptr", 0, "Ptr", 0)
         ; Update scroll bar.
         DllCall("SetScrollPos", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", NewPos, "Int", 1)
         Switch Bar {
            Case 0: GuiObj.ScrollInfo.PosH := NewPos
            Case 1: GuiObj.ScrollInfo.PosV := NewPos
         }
      }
   }
   ; -------------------------------------------------------------------------------------------------------------------
   GetWheelScrollChars() {
      Local ScrollChars := 3 ; default
      DllCall("SystemParametersInfoW", "UInt", 0x006C, "UInt", 0, "UIntP", &ScrollChars, "UInt", 0)
      Return ScrollChars
   }
   GetWheelScrollLines() {
      Local ScrollLines := 3 ; default
      DllCall("SystemParametersInfoW", "UInt", 0x0068, "UInt", 0, "IntP", &ScrollLines, "UInt", 0)
      Return ScrollLines
   }
}
; ======================================================================================================================
ScrollGui_Size(GuiObj, MinMax, Width, Height) {
   Critical -1
   If (MinMax != -1) && GuiObj.HasProp("ScrollInfo")
      ScrollGui_UpdateBars(GuiObj, Width, Height)
}
; ======================================================================================================================
ScrollGui_GetScrollInfo(GuiObj, Bar) {
   If !(GuiObj Is Gui)
      Throw TypeError("Paramweter GuiObj must be an GUI object!", -1, Type(GuiObj))
   If !(Type(Bar) = "Integer")
      Throw TypeError("Paramweter Bar must be an integer!", -1, Type(Bar))
   If (Bar < 0) || (Bar > 1)
      Throw ValueError("Paramweter Bar must be an integer between 0 and 1!", -1, Bar)
   Local SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", 0x17, SI) ; cbSize, fMask: SIF_ALL
   If !DllCall("GetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", Bar, "Ptr", SI, "UInt")
      Throw Error("DllCall GetScrollInfo failed with error " . A_LastError, -1)
   Return {Min:  NumGet(SI,  8, "Int"),  ; nMin
           Max:  NumGet(SI, 12, "Int"),  ; nMax
           Page: NumGet(SI, 16, "UInt"), ; nPage
           Pos:  NumGet(SI, 20, "Int")}  ; nPos
}
;=======================================================================================================================
ScrollGui_GetTotalSize(GuiObj) {
   If !GuiObj.HasProp("ScrollInfo")
      Return False
   Local TotalW := 0, TotalH := 0
   Local GuiCtrl, X, Y, W, H
   For GuiCtrl In GuiObj {
      GuiCtrl.GetPos(&X, &Y, &W, &H)
      TotalW := Max(TotalW, W + X - 1)
      TotalH := Max(TotalH, H + Y - 1)
   }
   TotalW += GuiObj.MarginX
   TotalH += GuiObj.MarginY
   GuiObj.ScrollInfo.TotalW := TotalW
   GuiObj.ScrollInfo.TotalH := TotalH
   GuiObj.ScrollInfo.LineH := Max(6,  TotalW // 100)
   GuiObj.ScrollInfo.LineV := Max(12, TotalH // 100)
   GuiObj.Opt("+MaxSize" . TotalW . "x" . TotalH)
}
; ======================================================================================================================
ScrollGui_UpdateBars(GuiObj, Width, Height) {
   ; SIF_RANGE = 0x01, SIF_PAGE = 0x02, SIF_DISABLENOSCROLL = 0x08, SB_HORZ = 0, SB_VERT = 1
   If !GuiObj.HasProp("ScrollInfo")
      Return False
   Local DisableNoScroll := GuiObj.ScrollInfo.Disable
   If !GuiObj.ScrollInfo.HasProp("TotalW")
      ScrollGui_GetTotalSize(GuiObj)
   ; Calculate scrolling area.
   Local TotalW := GuiObj.ScrollInfo.TotalW
   Local TotalH := GuiObj.ScrollInfo.TotalH
   ; Initialize SCROLLINFO.
   Local Mask := 3 | GuiObj.ScrollInfo.Disable ; SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL?
   Local SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", Mask, SI) ; cbSize , fMask
   Local PosH := 0, PosV := 0, ScrollH := ScrollV := 0
   If (GuiObj.ScrollInfo.Bars & 1) { ; update the horizontal scroll bar
      NumPut("Int", TotalW, "Int", Width +1, SI, 12) ; nMax , nPage
      DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 0, "Ptr", SI, "Int", 1) ; SB_HORZ
      PosH := ScrollGui_GetScrollInfo(GuiObj, 0).Pos
      ScrollH := GuiObj.ScrollInfo.PosH - PosH
      GuiObj.ScrollInfo.PosH := PosH
   }
   If (GuiObj.ScrollInfo.Bars & 2) { ; update the vertical scroll bar
      NumPut("Int", TotalH, "UInt", Height + 1, SI, 12) ; nMax , nPage
      DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 1, "Ptr", SI, "Int", 1) ; SB_VERT
      PosV := ScrollGui_GetScrollInfo(GuiObj, 1).Pos
      ScrollV := GuiObj.ScrollInfo.PosV - PosV
      GuiObj.ScrollInfo.PosV := PosV
   }
   If (ScrollH || ScrollV)
      DllCall("ScrollWindow", "Ptr", GuiObj.Hwnd, "Int", ScrollH, "Int", ScrollV, "Ptr", 0, "Ptr", 0)
   Return True
}
; ======================================================================================================================

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 17 guests