Class_ScrollGUI - updated on 2015-03-13

Post your working scripts, libraries and tools for AHK v1.1 and older
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Class_ScrollGUI - updated on 2015-03-13

15 Jan 2020, 21:31

kczx3 wrote:
15 Jan 2020, 20:24
It’s probably just the sheer number of controls based on the fact that you’re mimicking an excel spreadsheet
Yeah I agree with you but let's hope someone smarter than me can think of a way to handle this. In my example, there's not an enourmous amount of controls and still it feels like there is 100 000 controls.
To be exact, there are about 1090 controls (99 rows * 11 cols).
Even my 5ghz processor is having issues so I guess there's some reason (- which is above my knowledge of how the dllcalls and stuff work in the class).
just me
Posts: 9407
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class_ScrollGUI - updated on 2015-03-13

16 Jan 2020, 11:55

Ok, I can reproduce the issue with a child GUI containing 99 * 12 edit controls without own message handlers or contgrol labels (Win 10 Pro 64 1903, AHK 1.1.32.00 U64). And I don't know, why it happens. I'd guess it has something to do with an overflooded message queue but I'm not able to degug such scenarios.

My test script:

Code: Select all

#NoEnv
#KeyHistory, 0
SetBatchLines, -1
ListLines, Off
Gui, Dummy:New
Gui, Child:New, +hwndHCHILD +ParentDummy
Gui, Margin, 10, 10
Loop, 99 {
   X := "xm"
   Y := A_Index = 1 ? "" : "y+-1"
   Loop, 12 {
      Gui, Add, Edit, %X% %Y% w100, Edit!
      X := "x+-1"
      Y := "yp"
   }
}
ScrollableResultats:= New ScrollGUI(HCHILD, 800, 600, "+Resize", 3, 4)
MainGuiTitle := "Finance D - "
ScrollableResultats.Show(MainGuiTitle)
Return
Esc::ExitApp

#Include Class_ScrollGUI.ahk
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Class_ScrollGUI - updated on 2015-03-13

16 Jan 2020, 18:04

I like how clean you can create a 1188 controls GUI :D

Good to know that it's not only reproduced on my computer in my specific script.
I gotta admit that I have no idea how to fix this either.
I've gone through the class but since its majorly dllCalls and numput numget etc I can't understand where I could help.
Only clue I might have is this:

Code: Select all

		For Key, Value In Values {
			If SIF.HasKey(Key) {
				Mask |= SIF[Key]
				NumPut(Value, SI, Off[Key], "UInt")
			}
		}
or this

Code: Select all

		While (HWND := DllCall("GetWindow", "Ptr", HWND, "UInt", CMD, "UPtr")) && (CMD := 2) {
			WinGetPos, X, Y, W, H, ahk_id %HWND%
			W += X, H += Y
			WinGet, Styles, Style, ahk_id %HWND%
			If (Styles & 0x10000000) { ; WS_VISIBLE
				If (L = "") || (X < L)
					L := X
				If (T = "") || (Y < T)
					T := Y
				If (R = "") || (W > R)
					R := W
				If (B = "") || (H > B)
					B := H
			}
			Else {
				If (LH = "") || (X < LH)
					LH := X
				If (TH = "") || (Y < TH)
					TH := Y
			}
		}
Would there be a way to put a sleep, 10 ms somewhere to slow it down maybe?
Or skip some fast happening chunks of data incoming?
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Class_ScrollGUI - updated on 2015-03-13

16 Jan 2020, 20:25

EDIT: never mind, I found something useable by Setting the line increment of scroll to the height of a table row.

Code: Select all

scrollable_UI.SetLine(2, TABLE_ROW_H-1)
Hey side-question:

How would you programmatically use ScrollGUI to follow the focused control when you want to navigate with arrow keys inside the scroll gui ?
Like how do you know when you're out of view and need to scroll up or down ?
I am trying with Send WheelUp Down but doesn't do what is expected because I don't when when the control is out of view.
Any idea?

Code: Select all

 ;#[HotKeys MainUI]
#if WinActive(MainGuiTitle)

Up::
Down::
focus_next_row()
return

;...
just me
Posts: 9407
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class_ScrollGUI - updated on 2015-03-13

17 Jan 2020, 06:24

DRocks wrote:Only clue I might have is this:
This must be called for every scroll positionn change. It shouldn't take much time.

DRocks wrote:or this
This is usually called only once when the SrollGUI will be created.

DRocks wrote: EDIT: never mind, I found something useable by Setting the line increment of scroll to the height of a table row.
SetLine(2, TABLE_ROW_H-1)
That's strange, because 2 isn't valid. Replacing it with 1 (vertical scroll bar) and using my Edit control's height doesn't work for me.

DRocks wrote:Like how do you know when you're out of view and need to scroll up or down ?
You could compare the sreen coordinates of the control with the screen coordinates of the client area of the ScrollGUI window.
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Class_ScrollGUI - updated on 2015-03-13

17 Jan 2020, 08:37

Thanks!
just me wrote:
17 Jan 2020, 06:24
DRocks wrote: EDIT: never mind, I found something useable by Setting the line increment of scroll to the height of a table row.
SetLine(2, TABLE_ROW_H-1)
That's strange, because 2 isn't valid. Replacing it with 1 (vertical scroll bar) and using my Edit control's height doesn't work for me.

Code: Select all

   ; ===================================================================================================================
   ; 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
	}
Maybe there's a typo cause at first I tried 1 and it didn't work then I re-read the comments in the class and saw vertical should be 2

Code: Select all

   ; Parameters:
   ;    SB          -  Scroll bar to set the value for:
   ;                   1 = horizontal
   ;                   2 = vertical
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Class_ScrollGUI - updated on 2015-03-13

17 Jan 2020, 14:10

I have a gui that uses AHK v2 and functions based on Lexikos' code. It struggles as well with your requirements.

EDIT: Here's a short clip of that gui that has quite a few controls and it is smooth for me.
scroll-gui.gif
scroll-gui.gif (805.86 KiB) Viewed 4618 times
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Class_ScrollGUI - updated on 2015-03-13

17 Jan 2020, 16:47

Yeah I think just me is also based on lexikos model for the crucial parts. Not sure though.
just me
Posts: 9407
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class_ScrollGUI - updated on 2015-03-13

18 Jan 2020, 08:31

DRocks wrote:
17 Jan 2020, 08:37
...
Sorry, my bad. I overlooked the

Code: Select all

      SB--
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Class_ScrollGUI - updated on 2015-03-13

04 Jul 2020, 18:03

Maybe someone will be useful.
+ You can add child windows.
+ Does not slow down when there are a lot of controls.

Code: Select all

#SingleInstance force
#NoEnv
SetBatchLines, -1 

Gui, New, +hwndhParentGUI
Gui, Color, Red
Gui, New, +hwndhGui +Parent%hParentGUI%

Loop 100
{
   i := A_Index
   Loop 5
   {
      If A_Index = 1 
         Gui, Add, Text, xm y+10 w21 h21 0x201, % i
      Else  
         Gui, Add, Text, x+10 w21 h21 yp 0x201, % i 
      Gui, Add, Edit, x+10 yp w55 hp r1, % A_Index
   }
} 
SG1 := New ScrollGUI(HGUI, 0, 200, "-Caption -Resize", 2, 2)
SG1.SetLine(2, 31) 

Gui, New, +hwndhGui +Parent%hParentGUI%
Loop 10
{
   i := A_Index
   Loop 5
   {
      If A_Index = 1 
         Gui, Add, Text, xm y+10 w22 0x201, % i  
      Else  
         Gui, Add, Text, x+10 w22 yp 0x201, % i 
      Gui, Add, Edit, x+10 yp w55 hp r1, % A_Index
   }
} 
SG2 := New ScrollGUI(HGUI, 330, 200, "-Caption -Resize", 3, 4)

SG1.Show("ScrollGUI1 Title", "x0 y0 NA")
SG2.Show("ScrollGUI2 Title", "x0 y" SG1.GuiSizeH + 1 " NA")

Gui, %hParentGui%:Add, Edit, % "+0x100000 +0x4 +0x80 -wrap w" SG1.GuiSizeW - SG2.GuiSizeW - 2
	. " h" SG2.GuiSizeH
	. " x" SG2.GuiSizeW + 2
	. " y" SG1.GuiSizeH + 1
	
Gui, %hParentGui%: Show, % "w" SG1.GuiSizeW " h" SG1.GuiSizeH + SG2.GuiSizeH + 1
Return

GuiClose:
	ExitApp


; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6316&sid=3d408106d4c70b431530247bb388a9ed
; https://github.com/AHK-just-me/Class_ScrollGUI

; 23:36 04.07.2020 Добавлены дочерние окна
; http://forum.script-coding.com/viewtopic.php?pid=140567#p140567

; 02:30 05.07.2020 ScrollWindow заменён на GuiShow
; http://forum.script-coding.com/viewtopic.php?pid=140580#p140580



; ======================================================================================================================
; Namepace:       ScrollGUI
; Function:       Create a scrollable GUI as a parent for GUI windows.
; Tested with:    AHK 1.1.19.02
; Tested on:      Win 8.1 (x64)
; Change log:     1.0.00.00/2015-02-06/just me        -  initial release on ahkscript.org
;                 1.0.01.00/2015-02-08/just me        -  bug fixes
;                 1.1.00.00/2015-02-09/just me        -  bug fixes and mouse wheel handling
; License:        The Unlicense -> http://unlicense.org
; ======================================================================================================================
Class ScrollGUI {
   Static Instances := []
   ; ===================================================================================================================
   ; __New          Creates a scrollable parent window (ScrollGUI) for the passed GUI.
   ; Parameters:
   ;    HGUI        -  HWND of the GUI 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 (doesn't really make sense).
   ;    Height      -  Height of the client area of the ScrollGUI.
   ;                   Pass 0 to set the client area to the height of the child GUI (doesn't really make sense).
   ;    ----------- Optional:
   ;    GuiOptions  -  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
   ;                   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
   ;                   Add 8 to require the Ctrl key as modifier for wheel messages which shall be processed by the
   ;                   ScrollGUI. Unmodified wheel messages will be passed to the child GUI in this case.
   ; Return values:
   ;    On failure:    False
   ; Remarks:
   ;    The rect of the child GUI is determined using the 'AutoSize' option of the 'Gui, Show' command, after
   ;    '-Caption' is applied to the child GUI.
   ;    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 captured to scroll the ScrollGUI.
   ;    You won't be able to use the wheel to scroll child GUI controls unless Ctrl is required as modifier.
   ; ===================================================================================================================
   __New(HGUI, Width, Height, GuiOptions := "", ScrollBars := 3, Wheel := 0) {
      Static SB_HORZ := 0, SB_VERT = 1
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
      Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
      Static WS_HSCROLL := "0x100000", WS_VSCROLL := "0x200000"
      RequireCtrl := False
      If (Wheel & 8) {
         RequireCtrl := True
         Wheel &= (8 - 1)
      }
      If ((ScrollBars <> 1) && (ScrollBars <> 2) && (ScrollBars <> 3))
      || ((Wheel <> 0) && (Wheel <> 1) && (Wheel <> 2) && (Wheel <> 3) && (Wheel <> 4))
         Return False
      If !DllCall("User32.dll\IsWindow", "Ptr", HGUI, "UInt")
         Return False
      VarSetCapacity(RC, 16, 0)
      ; Child GUI
      If !This.AutoSize(HGUI, GuiW, GuiH)
         Return False
      Gui, %HGUI%:-Caption -Resize
      Gui, %HGUI%:Show, w%GuiW% h%GuiH% Hide
      MaxH := GuiW
      MaxV := GuiH
      ; Gui, %HGUI%:Show, AutoSize Hide
      ; DllCall("User32.dll\GetWindowRect", "Ptr", HGUI, "Ptr", &RC)
      ; MaxH := NumGet(RC, 8, "Int") - NumGet(RC, 0, "Int")
      ; MaxV := Numget(RC, 12, "Int") - NumGet(RC, 4, "Int")
      LineH := Ceil(MaxH / 20)
      LineV := Ceil(MaxV / 20)
      ; ScrollGUI
      If (Width = 0)
         Width := MaxH
      If (Height = 0)
         Height := MaxV
      MX := MY := Styles := ""
      If (ScrollBars & 1) {
         MX := MaxH + 1
         Styles .= " +" . WS_HSCROLL
      }
      If (ScrollBars & 2) {
         Styles .= " +" . WS_VSCROLL
         MY := MaxV + 1
      } 
      Gui, New, %GuiOptions% %Styles% +hwndHWND
      Gui, %HWND%:Show, w%Width% h%Height% Hide
      If (MX <> "") || (MY <> "")
         Gui, %HWND%:+MaxSize%MX%x%MY%
      DllCall("User32.dll\GetClientRect", "Ptr", HWND, "Ptr", &RC)
	  PageH := NumGet(RC, 8, "Int") + 1
      PageV := Numget(RC, 12, "Int") + 1 
      ; Instance variables
      This.HWND := HWND
      This.HGUI := HGUI
      This.Width := Width
      This.Height := Height
      This.RequireCtrl := RequireCtrl
      This.UseShift := False
      If (ScrollBars & 1) {
         This.SetScrollInfo(SB_HORZ, {Max: MaxH, Page: PageH, Pos: 0})
         OnMessage(WM_HSCROLL, "ScrollGUI.On_WM_Scroll")
         If (Wheel & 1)
            OnMessage(WM_MOUSEHWHEEL, "ScrollGUI.On_WM_Wheel")
         Else If (Wheel & 4) {
            OnMessage(WM_MOUSEWHEEL, "ScrollGUI.On_WM_Wheel")
            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 (ScrollBars & 2) {
         This.SetScrollInfo(SB_VERT, {Max: MaxV, Page: PageV, Pos: 0})
         OnMessage(WM_VSCROLL, "ScrollGUI.On_WM_Scroll")
         If (Wheel & 6)
            OnMessage(WM_MOUSEWHEEL, "ScrollGUI.On_WM_Wheel")
         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
	  WinGet, GuiStyle, Style, ahk_id %HGUI%
	  If (GuiStyle & 0x40000000)  ; WS_CHILD
	  {
         WS_POPUP := 0x80000000, WS_CHILD := 0x40000000
	  	 Gui, %HWND%:+%WS_CHILD% -%WS_POPUP%
		 This.hParentGui := DllCall("GetParent", "Ptr", HGUI)
	  	 DllCall("SetParent", "Ptr", HWND, "Ptr", This.hParentGui)
	  } 
	  WinGetPos, X, Y, W, H, ahk_id %HWND% 
      This.GuiSizeX := X
      This.GuiSizeY := Y
      This.GuiSizeW := W
      This.GuiSizeH := H
      Gui, %HGUI%:+parent%HWND%
      Gui, %HGUI%:Show, x0 y0
      This.Instances[HWND] := &This
   }
   ; ===================================================================================================================
   ; __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")
      W := This.Width
      H := This.Height
      Gui, % This.HWND . ":Show", %ShowOptions% w%W% h%H%, %Title%
      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.Instances.HasKey(This.HWND) {
         Gui, % This.HWND . ":Destroy"
         This.Instances.Remove(This.HWND, "")
         Return True
      }
   }
   ; ===================================================================================================================
   ; AdjustToParent Adjust the scroll bars to the new parent dimensions.
   ; Parameters:
   ;    Width       -  New width of the client area of the ScrollGUI in pixels.
   ;                   Default: 0 -> current width
   ;    Height      -  New height of the client area of the ScrollGUI in pixels.
   ;                   Default: 0 -> current height
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; Remarks:
   ;    Call this method whenever the dimensions of the parent GUI have changed, e.g. after the GUI was resized,
   ;    restored or maximized. If either Width or Height is zero, both values will be set to the current dimensions.
   ; ===================================================================================================================
   AdjustToParent(Width := 0, Height := 0) {
      If (Width = 0) || (Height = 0) {
         VarSetCapacity(RC, 16, 0)
         DllCall("User32.dll\GetClientRect", "Ptr", This.HWND, "Ptr", &RC)
         Width := NumGet(RC, 8, "Int")
         Height := Numget(RC, 12, "Int")
      }
      SH := SV := 0
      If This.ScrollH {
         If (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 {
         If (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.HWND, "Int", SH, "Int", SV, "Ptr", 0, "Ptr", 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 client area of the child GUI is determined using the 'AutoSize' option of a 'Gui, Show' command.
   ; ===================================================================================================================
   AdjustToChild() {
      Static WS_HSCROLL := 0x100000, WS_VSCROLL := 0x200000
      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
      MX := This.ScrollH ? MaxH + 1 : ""
      MY := This.ScrollV ? MaxV + 1 : ""
      If (MX <> "") || (MY <> "") {
         Gui, % This.HWND . ":+MaxSize" . MX . "x" . MY
         W := ((MX <> "") && (MX < PrevW)) ? "w" . MX : ""
         H := ((MY <> "") && (MY < PrevH)) ? "h" . MY : ""
         If (W || H ) {
            Gui, % This.HWND . ":Show", %W% %H%
            If (W) {
               This.Width := MX
               This.SetScrollInfo(0, {Page: MX + 1})
            }
            If (H) {
               This.Height := MY
               This.SetScrollInfo(1, {Page: MY + 1})
            }
         }
      }
      ; Gui, % This.HGUI . ":Show", x%XC% y%YC% AutoSize
      ; DllCall("User32.dll\GetWindowRect", "Ptr", This.HGUI, "Ptr", &RC)
      ; MaxH := NumGet(RC, 8, "Int") - NumGet(RC, 0, "Int")
      ; MaxV := Numget(RC, 12, "Int") - NumGet(RC, 4, "Int")
      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.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) {
      Static SB_HORZ := 0, SB_VERT = 1
      SB--
      If (SB <> SB_HORZ) && (SB <> SB_VERT)
         Return False
      If (SB = SB_HORZ)
         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) {
      Static SB_HORZ := 0, SB_VERT = 1
      SB--
      If (SB <> SB_HORZ) && (SB <> SB_VERT)
         Return False
      If (SB = SB_HORZ)
         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) {
      Static SB_HORZ := 0, SB_VERT = 1
      SB--
      If (SB <> SB_HORZ) && (SB <> SB_VERT)
         Return False
      If (SB = SB_HORZ)
         This.PageH := Page
      Else
         This.PageV := Page
      Return This.SetScrollInfo(SB, {Page: Page})
   }
   ; ===================================================================================================================
   ; Methods for internal or system use!!!
   ; ===================================================================================================================
   AutoSize(HGUI, ByRef Width, ByRef Height) {
      DHW := A_DetectHiddenWindows
      DetectHiddenWindows, On
      VarSetCapacity(RECT, 16, 0)
      Width := Height := 0
      HWND := HGUI
      CMD := 5 ; GW_CHILD
      L := T := R := B := LH := TH := ""
      While (HWND := DllCall("GetWindow", "Ptr", HWND, "UInt", CMD, "UPtr")) && (CMD := 2) {
         WinGetPos, X, Y, W, H, ahk_id %HWND%
         W += X, H += Y
         WinGet, Styles, Style, ahk_id %HWND%
         If (Styles & 0x10000000) { ; WS_VISIBLE
            If (L = "") || (X < L)
               L := X
            If (T = "") || (Y < T)
               T := Y
            If (R = "") || (W > R)
               R := W
            If (B = "") || (H > B)
               B := H
         }
         Else {
            If (LH = "") || (X < LH)
               LH := X
            If (TH = "") || (Y < TH)
               TH := Y
         }
      }
      DetectHiddenWindows, %DHW%
      If (LH <> "") {
         VarSetCapacity(POINT, 8, 0)
         NumPut(LH, POINT, 0, "Int")
         DllCall("ScreenToClient", "Ptr", HGUI, "Ptr", &POINT)
         LH := NumGet(POINT, 0, "Int")
      }
      If (TH <> "") {
         VarSetCapacity(POINT, 8, 0)
         NumPut(TH, POINT, 4, "Int")
         DllCall("ScreenToClient", "Ptr", HGUI, "Ptr", &POINT)
         TH := NumGet(POINT, 4, "Int")
      }
      NumPut(L, RECT, 0, "Int"), NumPut(T, RECT,  4, "Int")
      NumPut(R, RECT, 8, "Int"), NumPut(B, RECT, 12, "Int")
      DllCall("MapWindowPoints", "Ptr", 0, "Ptr", HGUI, "Ptr", &RECT, "UInt", 2)
      Width := NumGet(RECT, 8, "Int") + (LH <> "" ? LH : NumGet(RECT, 0, "Int"))
      Height := NumGet(RECT, 12, "Int") + (TH <> "" ? TH : NumGet(RECT,  4, "Int"))
      Return True
   }
   ; ===================================================================================================================
   GetScrollInfo(SB, ByRef SI) {
      Static SI_SIZE := 28
      Static SIF_ALL := 0x17
      VarSetCapacity(SI, SI_SIZE, 0)
      NumPut(SI_SIZE, SI, 0, "UInt")
      NumPut(SIF_ALL, SI, 4, "UInt")
      Return DllCall("User32.dll\GetScrollInfo", "Ptr", This.HWND, "Int", SB, "Ptr", &SI, "UInt")
   }
   ; ===================================================================================================================
   SetScrollInfo(SB, Values) {
      Static SI_SIZE := 28
      Static SIF := {Max: 0x01, Page: 0x02, Pos: 0x04}
      Static Off := {Max: 12, Page: 16, Pos: 20}
      Static SIF_DISABLENOSCROLL := 0x08
      Mask := 0
      VarSetCapacity(SI, SI_SIZE, 0)
      NumPut(SI_SIZE, SI, 0, "UInt")
      For Key, Value In Values {
         If SIF.HasKey(Key) {
            Mask |= SIF[Key]
            NumPut(Value, SI, Off[Key], "UInt")
         }
      }
      If (Mask) {
         NumPut(Mask | SIF_DISABLENOSCROLL, SI, 4, "UInt")
         Return DllCall("User32.dll\SetScrollInfo", "Ptr", This.HWND, "Int", SB, "Ptr", &SI, "UInt", 1, "UInt")
      }
      Return False
   }
   ; ===================================================================================================================
   On_WM_Scroll(LP, Msg, HWND) {
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115 
	   
      If ScrollGUI.Instances.HasKey(HWND) {
         Instance := Object(ScrollGUI.Instances[HWND])
         If ((Msg = WM_HSCROLL) && Instance.ScrollH)
         || ((Msg = WM_VSCROLL) && Instance.ScrollV)
            Return Instance.Scroll(This, LP, Msg, HWND)
      }
   }
   ; ===================================================================================================================
   Scroll(WP, LP, Msg, HWND) {
      Static SB_LINEMINUS := 0, SB_LINEPLUS := 1, SB_PAGEMINUS := 2, SB_PAGEPLUS := 3, SB_THUMBTRACK := 5
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
		Static i := 0
      If (LP <> 0)
         Return 
      SB := (Msg = WM_HSCROLL ? 0 : 1) ; SB_HORZ : SB_VERT
      SC := WP & 0xFFFF
      SD := (Msg = WM_HSCROLL ? This.LineH : This.LineV)
      SI := 0
      If !This.GetScrollInfo(SB, SI)
         Return 
		PA := PN := NumGet(SI, 20, "Int")
		
      If (SC = SB_LINEMINUS)
         PN := PA - SD
      Else If (SC = SB_LINEPLUS)
         PN := PA + SD
      Else If (SC = SB_PAGEMINUS)
         PN := PA - NumGet(SI, 16, "UInt")
      Else If (SC = SB_PAGEPLUS)
         PN := PA + NumGet(SI, 16, "UInt")
      Else If (SC = SB_THUMBTRACK)
         PN := NumGet(SI, 24, "Int")
      If (PA = PN)
         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) { 
		If 0
         {
	         HS := VS := 0
	         If (Msg = WM_HSCROLL)
	            HS := PA - PN
	         Else
	            VS := PA - PN  
	         DllCall("User32.dll\ScrollWindow", "Ptr", This.HWND, "Int", HS, "Int", VS, "Ptr", 0, "Ptr", 0)
			; SW_SCROLLCHILDREN := 0x1
			; SW_INVALIDATE := 0x2
			; SW_ERASE := 0x4
			; SW_SMOOTHSCROLL := 0x10
	        ; DllCall("User32.dll\ScrollWindowEx", "Ptr", This.HWND, "Int", HS, "Int", VS, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Int", 0x10)
         } 
		 Else 
         { 
			This.GetScrollInfo((Msg = WM_HSCROLL), SI)
			c := NumGet(SI, 20, "Int")
	         If (Msg = WM_HSCROLL)
	            op := "NA y" -c " x" -PN
	         Else
	            op := "NA x" -c " y" -PN
			  Gui, % This.HGUI . ":Show", % op
         }
      }
      Return 0
   }
   
   ; ===================================================================================================================
   On_WM_Wheel(LP, Msg, HWND) {
      Static MK_CONTROL := 0x0008
      Static MK_SHIFT := 0x0004
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
      Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
      ; HWND := WinExist("A") 
      If ScrollGUI.Instances.HasKey(HWND) {
         Instance := Object(ScrollGUI.Instances[HWND])
         If (Instance.RequireCtrl && (This & MK_CONTROL)) || (!Instance.RequireCtrl && !(This & MK_CONTROL))
            If (Instance.WheelH && (Msg = WM_MOUSEHWHEEL))
            || (Instance.WheelH && ((Msg = WM_MOUSEWHEEL) && Instance.UseShift && (This & MK_SHIFT)))
            || (Instance.WheelV && (Msg = WM_MOUSEWHEEL))
               Return Instance.Wheel(This, LP, Msg, HWND)
      }
   }
   ; ===================================================================================================================
   Wheel(WP, LP, Msg, H) {
      Static MK_SHIFT := 0x0004
      Static SB_LINEMINUS := 0, SB_LINEPLUS := 1
      Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
      If (Msg = WM_MOUSEWHEEL) && (WP & MK_SHIFT) && This.UseShift
         Msg := WM_MOUSEHWHEEL
      MSG := (Msg = WM_MOUSEWHEEL ? WM_VSCROLL : WM_HSCROLL)
      SB := ((WP >> 16) > 0x7FFF) || (WP < 0) ? SB_LINEPLUS : SB_LINEMINUS
      Return This.Scroll(SB, 0, MSG, H)
   }
}

serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Class_ScrollGUI - updated on 2015-03-13

05 Jul 2020, 07:16

Added an example with Resize.
This should work with examples too just me.

Code: Select all



#SingleInstance force
#NoEnv
SetBatchLines, -1 

Gui, New, +hwndhParentGUI +LabelMain +Resize
Gui, Color, Red
Gui, New, +hwndhGui1 +Parent%hParentGUI%

Loop 10
{
   i := A_Index
   Loop 10
   {
      If A_Index = 1 
         Gui, Add, Text, xm y+10 w21 h21 0x201, % i
      Else  
         Gui, Add, Text, x+10 w21 h21 yp 0x201, % i
      Gui, Add, Edit, x+10 yp w55 hp r1, % A_Index
   }
} 
SG1 := New ScrollGUI(HGUI1, 0, 0, "-Caption -Resize", 3, 4)
SG1.SetLine(2, 31) 
SG1.Show("ScrollGUI1 Title", "x0 y0 NA")

Gui, New, +hwndhGui2 +Parent%hParentGUI%
Loop 10
{
   i := A_Index
   Loop 5
   {
      If A_Index = 1 
         Gui, Add, Text, xm y+10 w22 0x201, % i  
      Else  
         Gui, Add, Text, x+10 w22 yp 0x201, % i 
      Gui, Add, Edit, x+10 yp w55 hp r1, % A_Index
   }
} 
SG2 := New ScrollGUI(HGUI2, 0, 0, "-Caption -Resize", 3, 4)
SG2.SetLine(2, 31) 
SG2.Show("ScrollGUI2 Title", "x0 y" SG1.GuiSizeH + 1 " NA")

Gui, %hParentGui%:Add, Edit, % "vEdit1 +0x100000 +0x4 +0x80 -wrap"
	
Gui, %hParentGui%: Show, % "NA Hide w" 640 " h" 480
Gui, %hParentGui%: Show
Return

MainSize:   
	If (A_EventInfo = 1)
		Return

	SG1Height := (A_GuiHeight / 2 - SG1.SizeHSCROLL)
	Gui, % SG1.hwnd ": Show", % "x0 y0 w" A_GuiWidth - SG1.SizeVSCROLL " h" SG1Height
	Gui, % SG2.hwnd ": Show", % "x0 y" SG1Height + 1 + SG1.SizeHSCROLL " w" A_GuiWidth / 2 " h" A_GuiHeight - SG1Height - 1 - SG1.SizeHSCROLL * 2

	SG1.AdjustToParent()
	SG2.AdjustToParent()
	
	GuiControl, %hParentGui%:MoveDraw, Edit1, % "" 
	. " x" SG2.GuiSizeW + 2 
	. " y" SG1.GuiSizeH + 1 
	. " w" SG1.GuiSizeW - SG2.GuiSizeW - 2
	. " h" SG2.GuiSizeH   
	Return
	
GuiClose:
	ExitApp




; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6316&sid=3d408106d4c70b431530247bb388a9ed
; https://github.com/AHK-just-me/Class_ScrollGUI

; 16:50 05.07.2020 add GetClientPos & ControlGetPos
; 16:03 05.07.2020 add SysGet

; 02:30 05.07.2020 ScrollWindow заменён на GuiShow
; http://forum.script-coding.com/viewtopic.php?pid=140580#p140580

; 23:36 04.07.2020 Добавлены дочерние окна
; http://forum.script-coding.com/viewtopic.php?pid=140567#p140567




; ======================================================================================================================
; Namepace:       ScrollGUI
; Function:       Create a scrollable GUI as a parent for GUI windows.
; Tested with:    AHK 1.1.19.02
; Tested on:      Win 8.1 (x64)
; Change log:     1.0.00.00/2015-02-06/just me        -  initial release on ahkscript.org
;                 1.0.01.00/2015-02-08/just me        -  bug fixes
;                 1.1.00.00/2015-02-09/just me        -  bug fixes and mouse wheel handling
; License:        The Unlicense -> http://unlicense.org
; ======================================================================================================================
Class ScrollGUI {
   Static Instances := []
   Static SM_CXVSCROLL := ScrollGUI.SysGet(2), SM_CYHSCROLL := ScrollGUI.SysGet(3)
   
   ; ===================================================================================================================
   ; __New          Creates a scrollable parent window (ScrollGUI) for the passed GUI.
   ; Parameters:
   ;    HGUI        -  HWND of the GUI 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 (doesn't really make sense).
   ;    Height      -  Height of the client area of the ScrollGUI.
   ;                   Pass 0 to set the client area to the height of the child GUI (doesn't really make sense).
   ;    ----------- Optional:
   ;    GuiOptions  -  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
   ;                   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
   ;                   Add 8 to require the Ctrl key as modifier for wheel messages which shall be processed by the
   ;                   ScrollGUI. Unmodified wheel messages will be passed to the child GUI in this case.
   ; Return values:
   ;    On failure:    False
   ; Remarks:
   ;    The rect of the child GUI is determined using the 'AutoSize' option of the 'Gui, Show' command, after
   ;    '-Caption' is applied to the child GUI.
   ;    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 captured to scroll the ScrollGUI.
   ;    You won't be able to use the wheel to scroll child GUI controls unless Ctrl is required as modifier.
   ; ===================================================================================================================
   __New(HGUI, Width, Height, GuiOptions := "", ScrollBars := 3, Wheel := 0) {
      Static SB_HORZ := 0, SB_VERT = 1
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
      Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
      Static WS_HSCROLL := "0x100000", WS_VSCROLL := "0x200000"
	  
      RequireCtrl := False
      If (Wheel & 8) {
         RequireCtrl := True
         Wheel &= (8 - 1)
      }
      If ((ScrollBars <> 1) && (ScrollBars <> 2) && (ScrollBars <> 3))
      || ((Wheel <> 0) && (Wheel <> 1) && (Wheel <> 2) && (Wheel <> 3) && (Wheel <> 4))
         Return False
      If !DllCall("User32.dll\IsWindow", "Ptr", HGUI, "UInt")
         Return False
      VarSetCapacity(RC, 16, 0)
      ; Child GUI
      If !This.AutoSize(HGUI, GuiW, GuiH)
         Return False
      Gui, %HGUI%:-Caption -Resize
      Gui, %HGUI%:Show, w%GuiW% h%GuiH% Hide
      MaxH := GuiW
      MaxV := GuiH
      ; Gui, %HGUI%:Show, AutoSize Hide
      ; DllCall("User32.dll\GetWindowRect", "Ptr", HGUI, "Ptr", &RC)
      ; MaxH := NumGet(RC, 8, "Int") - NumGet(RC, 0, "Int")
      ; MaxV := Numget(RC, 12, "Int") - NumGet(RC, 4, "Int")
      LineH := Ceil(MaxH / 20)
      LineV := Ceil(MaxV / 20)
      ; ScrollGUI
      If (Width = 0)
         Width := MaxH
      If (Height = 0)
         Height := MaxV
      MX := MY := Styles := ""
	  this.SizeWSCROLL := this.SizeHSCROLL := 0
      If (ScrollBars & 1) {
         MX := MaxH + 1
         Styles .= " +" . WS_HSCROLL
		 this.SizeHSCROLL := this.SM_CYHSCROLL
      }
      If (ScrollBars & 2) {
         Styles .= " +" . WS_VSCROLL
         MY := MaxV + 1
		 this.SizeVSCROLL := this.SM_CXVSCROLL
      } 
      Gui, New, %GuiOptions% %Styles% +hwndHWND
      Gui, %HWND%:Show, w%Width% h%Height% Hide
      If (MX <> "") || (MY <> "")
         Gui, %HWND%:+MaxSize%MX%x%MY%
      DllCall("User32.dll\GetClientRect", "Ptr", HWND, "Ptr", &RC)
	  PageH := NumGet(RC, 8, "Int") + 1
      PageV := Numget(RC, 12, "Int") + 1 
      ; Instance variables
      This.HWND := HWND
      This.HGUI := HGUI
      This.Width := Width
      This.Height := Height
      This.RequireCtrl := RequireCtrl
      This.UseShift := False
      If (ScrollBars & 1) {
         This.SetScrollInfo(SB_HORZ, {Max: MaxH, Page: PageH, Pos: 0})
         OnMessage(WM_HSCROLL, "ScrollGUI.On_WM_Scroll")
         If (Wheel & 1)
            OnMessage(WM_MOUSEHWHEEL, "ScrollGUI.On_WM_Wheel")
         Else If (Wheel & 4) {
            OnMessage(WM_MOUSEWHEEL, "ScrollGUI.On_WM_Wheel")
            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 (ScrollBars & 2) {
         This.SetScrollInfo(SB_VERT, {Max: MaxV, Page: PageV, Pos: 0})
         OnMessage(WM_VSCROLL, "ScrollGUI.On_WM_Scroll")
         If (Wheel & 6)
            OnMessage(WM_MOUSEWHEEL, "ScrollGUI.On_WM_Wheel")
         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
	  WinGet, GuiStyle, Style, ahk_id %HGUI%
	  If (GuiStyle & 0x40000000)  ; WS_CHILD
	  {
         WS_POPUP := 0x80000000, WS_CHILD := 0x40000000
	  	 Gui, %HWND%:+%WS_CHILD% -%WS_POPUP%
		 This.hParentGui := DllCall("GetParent", "Ptr", HGUI)
	  	 DllCall("SetParent", "Ptr", HWND, "Ptr", This.hParentGui)
		 this.GetClientPos(This.hParentGui, left, top)
		 This.ParentClientX := left
		 This.ParentClientY := top
	  }    
	  WinGetPos, , , W, H, ahk_id %HWND%
	  This.GuiSizeW := W
      This.GuiSizeH := H
      Gui, %HGUI%:+parent%HWND%
      Gui, %HGUI%:Show, x0 y0
      This.Instances[HWND] := &This
   }
   ; ===================================================================================================================
   ; __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")
      W := This.Width
      H := This.Height
      Gui, % This.HWND . ":Show", %ShowOptions% w%W% h%H%, %Title%
      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.Instances.HasKey(This.HWND) {
         Gui, % This.HWND . ":Destroy"
         This.Instances.Remove(This.HWND, "")
         Return True
      }
   }
   SysGet(N) {
      SysGet, OutputVar, %N% 
      Return OutputVar
   }
	GetClientPos(hwnd, ByRef left, ByRef top, ByRef w := "", ByRef h := "") {
		Static _ := VarSetCapacity(pwi, 60, 0)
		DllCall("GetWindowInfo", "Ptr", hwnd, "Ptr", &pwi)
		left := NumGet(pwi, 20, "Int") - NumGet(pwi, 4, "Int")
		top := NumGet(pwi, 24, "Int") - NumGet(pwi, 8, "Int")
		w := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		h := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
   ; ===================================================================================================================
   ; AdjustToParent Adjust the scroll bars to the new parent dimensions.
   ; Parameters:
   ;    Width       -  New width of the client area of the ScrollGUI in pixels.
   ;                   Default: 0 -> current width
   ;    Height      -  New height of the client area of the ScrollGUI in pixels.
   ;                   Default: 0 -> current height
   ; Return values:
   ;    On success: True
   ;    On failure: False
   ; Remarks:
   ;    Call this method whenever the dimensions of the parent GUI have changed, e.g. after the GUI was resized,
   ;    restored or maximized. If either Width or Height is zero, both values will be set to the current dimensions.
   ; ===================================================================================================================
   AdjustToParent(Width := 0, Height := 0) {
      If (Width = 0) || (Height = 0) {
         VarSetCapacity(RC, 16, 0)
         DllCall("User32.dll\GetClientRect", "Ptr", This.HWND, "Ptr", &RC)
         Width := NumGet(RC, 8, "Int")
         Height := Numget(RC, 12, "Int") 
      } 
	  If This.hParentGui
	  { 
	     ControlGetPos, GuiX, GuiY, GuiW, GuiH, , %  "ahk_id" This.HWND 
	     This.GuiPosX := GuiX - This.ParentClientX
	     This.GuiPosY := GuiY - This.ParentClientY
	     This.GuiSizeW := GuiW
	     This.GuiSizeH := GuiH
	  }
      SH := SV := 0
      If This.ScrollH {
         If (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 {
         If (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.HWND, "Int", SH, "Int", SV, "Ptr", 0, "Ptr", 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 client area of the child GUI is determined using the 'AutoSize' option of a 'Gui, Show' command.
   ; ===================================================================================================================
   AdjustToChild() {
      Static WS_HSCROLL := 0x100000, WS_VSCROLL := 0x200000
      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
      MX := This.ScrollH ? MaxH + 1 : ""
      MY := This.ScrollV ? MaxV + 1 : ""
      If (MX <> "") || (MY <> "") {
         Gui, % This.HWND . ":+MaxSize" . MX . "x" . MY
         W := ((MX <> "") && (MX < PrevW)) ? "w" . MX : ""
         H := ((MY <> "") && (MY < PrevH)) ? "h" . MY : ""
         If (W || H ) {
            Gui, % This.HWND . ":Show", %W% %H%
            If (W) {
               This.Width := MX
               This.SetScrollInfo(0, {Page: MX + 1})
            }
            If (H) {
               This.Height := MY
               This.SetScrollInfo(1, {Page: MY + 1})
            }
         }
      }
      ; Gui, % This.HGUI . ":Show", x%XC% y%YC% AutoSize
      ; DllCall("User32.dll\GetWindowRect", "Ptr", This.HGUI, "Ptr", &RC)
      ; MaxH := NumGet(RC, 8, "Int") - NumGet(RC, 0, "Int")
      ; MaxV := Numget(RC, 12, "Int") - NumGet(RC, 4, "Int")
      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.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) {
      Static SB_HORZ := 0, SB_VERT = 1
      SB--
      If (SB <> SB_HORZ) && (SB <> SB_VERT)
         Return False
      If (SB = SB_HORZ)
         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) {
      Static SB_HORZ := 0, SB_VERT = 1
      SB--
      If (SB <> SB_HORZ) && (SB <> SB_VERT)
         Return False
      If (SB = SB_HORZ)
         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) {
      Static SB_HORZ := 0, SB_VERT = 1
      SB--
      If (SB <> SB_HORZ) && (SB <> SB_VERT)
         Return False
      If (SB = SB_HORZ)
         This.PageH := Page
      Else
         This.PageV := Page
      Return This.SetScrollInfo(SB, {Page: Page})
   }
   ; ===================================================================================================================
   ; Methods for internal or system use!!!
   ; ===================================================================================================================
   AutoSize(HGUI, ByRef Width, ByRef Height) {
      DHW := A_DetectHiddenWindows
      DetectHiddenWindows, On
      VarSetCapacity(RECT, 16, 0)
      Width := Height := 0
      HWND := HGUI
      CMD := 5 ; GW_CHILD
      L := T := R := B := LH := TH := ""
      While (HWND := DllCall("GetWindow", "Ptr", HWND, "UInt", CMD, "UPtr")) && (CMD := 2) {
         WinGetPos, X, Y, W, H, ahk_id %HWND%
         W += X, H += Y
         WinGet, Styles, Style, ahk_id %HWND%
         If (Styles & 0x10000000) { ; WS_VISIBLE
            If (L = "") || (X < L)
               L := X
            If (T = "") || (Y < T)
               T := Y
            If (R = "") || (W > R)
               R := W
            If (B = "") || (H > B)
               B := H
         }
         Else {
            If (LH = "") || (X < LH)
               LH := X
            If (TH = "") || (Y < TH)
               TH := Y
         }
      }
      DetectHiddenWindows, %DHW%
      If (LH <> "") {
         VarSetCapacity(POINT, 8, 0)
         NumPut(LH, POINT, 0, "Int")
         DllCall("ScreenToClient", "Ptr", HGUI, "Ptr", &POINT)
         LH := NumGet(POINT, 0, "Int")
      }
      If (TH <> "") {
         VarSetCapacity(POINT, 8, 0)
         NumPut(TH, POINT, 4, "Int")
         DllCall("ScreenToClient", "Ptr", HGUI, "Ptr", &POINT)
         TH := NumGet(POINT, 4, "Int")
      }
      NumPut(L, RECT, 0, "Int"), NumPut(T, RECT,  4, "Int")
      NumPut(R, RECT, 8, "Int"), NumPut(B, RECT, 12, "Int")
      DllCall("MapWindowPoints", "Ptr", 0, "Ptr", HGUI, "Ptr", &RECT, "UInt", 2)
      Width := NumGet(RECT, 8, "Int") + (LH <> "" ? LH : NumGet(RECT, 0, "Int"))
      Height := NumGet(RECT, 12, "Int") + (TH <> "" ? TH : NumGet(RECT,  4, "Int"))
      Return True
   }
   ; ===================================================================================================================
   GetScrollInfo(SB, ByRef SI) {
      Static SI_SIZE := 28
      Static SIF_ALL := 0x17
      VarSetCapacity(SI, SI_SIZE, 0)
      NumPut(SI_SIZE, SI, 0, "UInt")
      NumPut(SIF_ALL, SI, 4, "UInt")
      Return DllCall("User32.dll\GetScrollInfo", "Ptr", This.HWND, "Int", SB, "Ptr", &SI, "UInt")
   }
   ; ===================================================================================================================
   SetScrollInfo(SB, Values) {
      Static SI_SIZE := 28
      Static SIF := {Max: 0x01, Page: 0x02, Pos: 0x04}
      Static Off := {Max: 12, Page: 16, Pos: 20}
      Static SIF_DISABLENOSCROLL := 0x08
      Mask := 0
      VarSetCapacity(SI, SI_SIZE, 0)
      NumPut(SI_SIZE, SI, 0, "UInt")
      For Key, Value In Values {
         If SIF.HasKey(Key) {
            Mask |= SIF[Key]
            NumPut(Value, SI, Off[Key], "UInt")
         }
      }
      If (Mask) {
         NumPut(Mask | SIF_DISABLENOSCROLL, SI, 4, "UInt")
         Return DllCall("User32.dll\SetScrollInfo", "Ptr", This.HWND, "Int", SB, "Ptr", &SI, "UInt", 1, "UInt")
      }
      Return False
   }
   ; ===================================================================================================================
   On_WM_Scroll(LP, Msg, HWND) {
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115 
	   
      If ScrollGUI.Instances.HasKey(HWND) {
         Instance := Object(ScrollGUI.Instances[HWND])
         If ((Msg = WM_HSCROLL) && Instance.ScrollH)
         || ((Msg = WM_VSCROLL) && Instance.ScrollV)
            Return Instance.Scroll(This, LP, Msg, HWND)
      }
   }
   ; ===================================================================================================================
   Scroll(WP, LP, Msg, HWND) {
      Static SB_LINEMINUS := 0, SB_LINEPLUS := 1, SB_PAGEMINUS := 2, SB_PAGEPLUS := 3, SB_THUMBTRACK := 5
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
		Static i := 0
      If (LP <> 0)
         Return 
      SB := (Msg = WM_HSCROLL ? 0 : 1) ; SB_HORZ : SB_VERT
      SC := WP & 0xFFFF
      SD := (Msg = WM_HSCROLL ? This.LineH : This.LineV)
      SI := 0
      If !This.GetScrollInfo(SB, SI)
         Return 
		PA := PN := NumGet(SI, 20, "Int")
		
      If (SC = SB_LINEMINUS)
         PN := PA - SD
      Else If (SC = SB_LINEPLUS)
         PN := PA + SD
      Else If (SC = SB_PAGEMINUS)
         PN := PA - NumGet(SI, 16, "UInt")
      Else If (SC = SB_PAGEPLUS)
         PN := PA + NumGet(SI, 16, "UInt")
      Else If (SC = SB_THUMBTRACK)
         PN := NumGet(SI, 24, "Int")
      If (PA = PN)
         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) { 
		 If 0
         {
	         HS := VS := 0
	         If (Msg = WM_HSCROLL)
	            HS := PA - PN
	         Else
	            VS := PA - PN  
	         DllCall("User32.dll\ScrollWindow", "Ptr", This.HWND, "Int", HS, "Int", VS, "Ptr", 0, "Ptr", 0)
			; SW_SCROLLCHILDREN := 0x1
			; SW_INVALIDATE := 0x2
			; SW_ERASE := 0x4
			; SW_SMOOTHSCROLL := 0x10
	        ; DllCall("User32.dll\ScrollWindowEx", "Ptr", This.HWND, "Int", HS, "Int", VS, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Int", 0x10)
         } 
		 Else 
         {
			This.GetScrollInfo((Msg = WM_HSCROLL), SI)
			c := NumGet(SI, 20, "Int")
			If (Msg = WM_HSCROLL)
				op := "NA y" -c " x" -PN
			Else
				op := "NA x" -c " y" -PN
			Gui, % This.HGUI . ":Show", % op
         }
      }
      Return 0
   }
   
   ; ===================================================================================================================
   On_WM_Wheel(LP, Msg, HWND) {
      Static MK_CONTROL := 0x0008
      Static MK_SHIFT := 0x0004
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
      Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
      ; HWND := WinExist("A") 
      If ScrollGUI.Instances.HasKey(HWND) {
         Instance := Object(ScrollGUI.Instances[HWND])
         If (Instance.RequireCtrl && (This & MK_CONTROL)) || (!Instance.RequireCtrl && !(This & MK_CONTROL))
            If (Instance.WheelH && (Msg = WM_MOUSEHWHEEL))
            || (Instance.WheelH && ((Msg = WM_MOUSEWHEEL) && Instance.UseShift && (This & MK_SHIFT)))
            || (Instance.WheelV && (Msg = WM_MOUSEWHEEL))
               Return Instance.Wheel(This, LP, Msg, HWND)
      }
   }
   ; ===================================================================================================================
   Wheel(WP, LP, Msg, H) {
      Static MK_SHIFT := 0x0004
      Static SB_LINEMINUS := 0, SB_LINEPLUS := 1
      Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
      Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
      If (Msg = WM_MOUSEWHEEL) && (WP & MK_SHIFT) && This.UseShift
         Msg := WM_MOUSEHWHEEL
      MSG := (Msg = WM_MOUSEWHEEL ? WM_VSCROLL : WM_HSCROLL)
      SB := ((WP >> 16) > 0x7FFF) || (WP < 0) ? SB_LINEPLUS : SB_LINEMINUS
      Return This.Scroll(SB, 0, MSG, H)
   }
}


AshleyM0101
Posts: 14
Joined: 24 Feb 2020, 21:43

Re: Class_ScrollGUI - updated on 2015-03-13

14 Nov 2020, 17:40

Any ideas how to integrate this amazing script created from AfterLemon into Class_ScrollGUI? (Source: https://autohotkey.com/board/topic/93997-list-all-ahk-scripts-in-directory-in-gui/)

I do not have much experience with guis.
I have tried everything I could think of but I'm having no luck adding a scrollbar to this gui.

Code: Select all

#SingleInstance force
#Persistent
SetBatchLines -1
SysGet, Size, MonitorWorkArea
GuiRight := SizeRight - 147
Button_Right := SizeRight - 147
Button_Bottom := SizeBottom - 31
Gui, 1: Color, cFFFFFF
Loop, *
{
   If (A_LoopFileName <> "AfterLemonScriptLauncher.ahk")
   {
      A_IndexCount := A_Index
      If A_IndexCountMinus
         A_IndexCount -= A_IndexCountMinus
      YPos := A_IndexCount * 25 - 20
      StringTrimRight, FileName%A_IndexCount%, A_LoopFileName, 4
      RunPath%A_IndexCount% := A_LoopFileFullPath
      Gui, 1: Add, Button, w110 h20 x5 y%YPos% gRun, % FileName%A_IndexCount%
      Gui, 1: Add, Button, w20 h20 x120 Disabled y%YPos% vFileName2%A_IndexCount%, K
      YPos%A_IndexCount% := YPos . "," . FileName%A_IndexCount%
   }
   else
   {
      A_IndexCountMinus++
      continue
   }
}
YPos += 50
GuiBottom := SizeBottom - YPos - 1
TitlePos := YPos - 21
ButtonPos := YPos - 25
Gui, 1: Font, w700 c000000
Gui, 1: Add, Text, w90 h20 x30 y%TitlePos% Center gDrag, Utilities
Gui, 1: Font, c000000
Gui, 1: Add, Button, w20 h20 x5 y%ButtonPos%, &-
Gui, 1: Add, Button, w20 h20 x120 y%ButtonPos%, &X
Gui, 1: +AlwaysOnTop +E0x08000000 -Caption +ToolWindow +Border
Gui, 1: Show, NoActivate w145 h%YPos% x%GuiRight% y%GuiBottom%, Main Window
return

Drag:
   PostMessage, 0xA1, 2,,, A
return

Run:
   Loop
   {
   If (A_GuiControl = FileName%A_Index%)
   {
      RunPath := RunPath%A_Index%
      Run, "%RunPath%",,, ProgRun%A_Index%
      ProcessRun := A_Index
      break
   }
   }
   GuiControl, Enable, FileName2%ProcessRun%
   Gui, 1: Show, NoActivate w145 h%YPos% x%GuiRight% y%GuiBottom%, Main Window
return

ButtonK:
   StringTrimLeft, RunningName, A_GuiControl,9
   FileNameKill := ProgRun%RunningName%
   Process, Close, % FileNameKill
   GuiControl, Disable, FileName2%RunningName%
return

Button-:
   Gui, 1: Cancel
   Gui, 2: Color, cFFFFFF
   Gui, 2: Font, w700 c000000
   Gui, 2: Add, Text, w90 h20 x30 y9 Center gDrag, Utilities
   Gui, 2: Font, c000000
   Gui, 2: Add, Button, w20 h20 x5 y5, &+
   Gui, 2: Add, Button, w20 h20 x120 y5, &X
   Gui, 2: -Caption +AlwaysOnTop +E0x08000000 +Border
   Gui, 2: Show, NoActivate w145 h30 x%Button_Right% y%Button_Bottom%, Minimized
return

2Button+:
   Gui, 2: Destroy
   Gui, 1: Show, NoActivate w145 h%YPos% x%GuiRight% y%GuiBottom%, Main Window
return

ButtonX:
2ButtonX:
ExitApp
Additional info about the AfterLemon script:
Description from AfterLemon: Place this small script into a directory with other .ahk scripts and it will enumerate a list with links to run, and killswitches.
I love this script because I can drop it in any folder containing ahk's and it automagically collects all ahk's in the folder. Super useful for whenever I create new ahk scripts without having to manually create a button for each one and I don't have to remember a bunch of hotkeys to launch different scripts. I also modified the script to not take focus away from any active window so that each button can be clicked to run a script to act on the active window if desired (NoActivate parameter). I'm not sure if that functionality can remain intact with the scrollbar added.
AfterLemon's script adds more buttons automatically starting from the bottom the more ahk files it finds in a directory. The problem I have is I have created too many ahk scripts to fit nicely within the gui and the buttons overflow over the top of the screen and are inaccessible, see example below.
image.png
image.png (85.48 KiB) Viewed 2933 times
This is what I have so far and having no luck:

Code: Select all

#NoEnv
#SingleInstance force
#Persistent
#Include Class_ScrollGUI.ahk
SetBatchLines, -1
; ----------------------------------------------------------------------------------------------------------------------
; ChildGUI 1
Gui, new, +hwndHGUI +Resize
#SingleInstance force
#Persistent
SetBatchLines -1
SysGet, Size, MonitorWorkArea
GuiRight := SizeRight - 147
Button_Right := SizeRight - 147
Button_Bottom := SizeBottom - 31
Gui, 1: Color, cFFFFFF
Loop, *
{
   If (A_LoopFileName <> "AfterLemonScriptLauncher.ahk")
   {
      A_IndexCount := A_Index
      If A_IndexCountMinus
         A_IndexCount -= A_IndexCountMinus
      YPos := A_IndexCount * 25 - 20
      StringTrimRight, FileName%A_IndexCount%, A_LoopFileName, 4
      RunPath%A_IndexCount% := A_LoopFileFullPath
      Gui, 1: Add, Button, w110 h20 x5 y%YPos% gRun, % FileName%A_IndexCount%
      Gui, 1: Add, Button, w20 h20 x120 Disabled y%YPos% vFileName2%A_IndexCount%, K
      YPos%A_IndexCount% := YPos . "," . FileName%A_IndexCount%
   }
   else
   {
      A_IndexCountMinus++
      continue
   }
}
YPos += 50
GuiBottom := SizeBottom - YPos - 1
TitlePos := YPos - 21
ButtonPos := YPos - 25
Gui, 1: Font, w700 c000000
Gui, 1: Add, Text, w90 h20 x30 y%TitlePos% Center gDrag, Utilities
Gui, 1: Font, c000000
Gui, 1: Add, Button, w20 h20 x5 y%ButtonPos%, &-
Gui, 1: Add, Button, w20 h20 x120 y%ButtonPos%, &X
Gui, 1: +AlwaysOnTop +E0x08000000 -Caption +ToolWindow +Border
Gui, 1: Show, NoActivate w145 h%YPos% x%GuiRight% y%GuiBottom%, Main Window
return

Drag:
   PostMessage, 0xA1, 2,,, A
return

Run:
   Loop
   {
   If (A_GuiControl = FileName%A_Index%)
   {
      RunPath := RunPath%A_Index%
      Run, "%RunPath%",,, ProgRun%A_Index%
      ProcessRun := A_Index
      break
   }
   }
   GuiControl, Enable, FileName2%ProcessRun%
   Gui, 1: Show, NoActivate w145 h%YPos% x%GuiRight% y%GuiBottom%, Main Window
return

ButtonK:
   StringTrimLeft, RunningName, A_GuiControl,9
   FileNameKill := ProgRun%RunningName%
   Process, Close, % FileNameKill
   GuiControl, Disable, FileName2%RunningName%
return

Button-:
   Gui, 1: Cancel
   Gui, 2: Color, cFFFFFF
   Gui, 2: Font, w700 c000000
   Gui, 2: Add, Text, w90 h20 x30 y9 Center gDrag, Utilities
   Gui, 2: Font, c000000
   Gui, 2: Add, Button, w20 h20 x5 y5, &+
   Gui, 2: Add, Button, w20 h20 x120 y5, &X
   Gui, 2: -Caption +AlwaysOnTop +E0x08000000 +Border
   Gui, 2: Show, NoActivate w145 h30 x%Button_Right% y%Button_Bottom%, Minimized
return

2Button+:
   Gui, 2: Destroy
   Gui, 1: Show, NoActivate w145 h%YPos% x%GuiRight% y%GuiBottom%, Main Window
return

ButtonX:
2ButtonX:
ExitApp
; Create ScrollGUI1 with both horizontal and vertical scrollbars and scrolling by mouse wheel
Global SG1 := New ScrollGUI(HGUI, 400, 400, "+Resize +LabelGui1", 3, 4)
; Show ScrollGUI1
SG1.Show("ScrollGUI1", "y0 xcenter")
; ----------------------------------------------------------------------------------------------------------------------
; ChildGUI 2
Gui, New, +hwndHGUI2
Gui, Margin, 20, 20
Gui, Font, s32
Gui, Add, Text, xm Border Hidden vTX1, Test
Gui, Add, Text, x+m yp w460 h300 Center 0x200 Border Section, GUI number 2
Gui, Font
Gui, Add, Button, xs wp gShowHide, Show/Hide additional controls.
Gui, Font, s32
Gui, Add, Text, ys wp h300 Center 0x200 Border Hidden vTX2, Hidden Text 1
Gui, Add, Text, xs wp h300 Center 0x200 Border Hidden vTX3, Hidden Text 2
Gui, Add, Text, xs wp h300 Center 0x200 Border Hidden vTX4, Hidden Text 3
; Create ScrollGUI2 with both horizontal and vertical scrollbars
SG2 := New ScrollGUI(HGUI2, 600, 200, "+Resize +LabelGui2")
; Show ScrollGUI2
SG2.Show("ScrollGUI2", "x0 yCenter")
Return
; ----------------------------------------------------------------------------------------------------------------------
ShowHide:
   GuiControlGet, V, %HGUI2%:Visible, TX1
   GuiControl, %HGUI2%:Hide%V%, TX1
   GuiControl, %HGUI2%:Hide%V%, TX2
   GuiControl, %HGUI2%:Hide%V%, TX3
   GuiControl, %HGUI2%:Hide%V%, TX4
   SG2.AdjustToChild()
Return
; ----------------------------------------------------------------------------------------------------------------------
Gui1Close:
Gui1Escape:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------
Gui1Size:
Return
Gui2Size:
Return
; ----------------------------------------------------------------------------------------------------------------------
Gui2Close:
Gui2Escape:
   SG2 := ""
Return
User avatar
HiSoKa
Posts: 480
Joined: 27 Jan 2020, 15:43

Re: Class_ScrollGUI - updated on 2015-03-13

11 Nov 2022, 09:51

Thank you very much @just me for this great work.
My problem with this class is that it GUI autoresize according to controls size not according to size which i wrote.
How can I avoid that
For example i need gui like this Size:

Code: Select all

gui, 2:show, y470 x230 h225 w1110
I write this code to get like gui above, But it does not work, and SG2 is created according to the size of the controls which in it.

Code: Select all

SG2 := New ScrollGUI(HGUI2, 1110, 225, "+Resize +LabelGui2", 3, 4)
SG2.Show("ScrollGUI2", "y470 x230")
just me
Posts: 9407
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class_ScrollGUI - updated on 2015-03-13

12 Nov 2022, 04:07

@HiSoKa

Code: Select all

   ; 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.
It's not designed to specify a width or height larger than the child window's control area. Only smaller values are supported.
User avatar
HiSoKa
Posts: 480
Joined: 27 Jan 2020, 15:43

Re: Class_ScrollGUI - updated on 2015-03-13

12 Nov 2022, 04:58

I didn't notice these Remark ,Thanks..
now i try to use something like Gui,hide Gui, Cancel Gui, Destroy...etc with you Sample..
But I couldn't figure out how to use them with it..
For example, how can if I press Esc Exit SG1 ?
And ^Ctrl to bring back the SG1.
This is my attempt...

Code: Select all

ESC::
   SG1 := ""
return
^ESC::
   Global SG1 := New ScrollGUI(HGUI, 400, 400, "+Resize +LabelGui1", 3, 4)
   SG1.Show("ScrollGUI1", "y0 xcenter")
Or in other word how can I use Show Hide Destroy..etc with SG1 for example.
To get such result for SG1

Code: Select all

gui, show, w500 h500

ESC::
gui, hide
return

^ESC::
gui, show
The above code works normally with normal GUI as you can see, But I could not do these same commands on SG1 for some reason.
just me
Posts: 9407
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class_ScrollGUI - updated on 2015-03-13

12 Nov 2022, 11:27

Hi @HiSoKa,

something like this should work:

Code: Select all

Esc::
Gui, % SG1.Hwnd . ": Hide"
Return
^Esc::
Gui, % SG1.Hwnd . ": Show"
Return
User avatar
HiSoKa
Posts: 480
Joined: 27 Jan 2020, 15:43

Re: Class_ScrollGUI - updated on 2015-03-13

12 Nov 2022, 12:02

It's working now, Thank you
User avatar
HiSoKa
Posts: 480
Joined: 27 Jan 2020, 15:43

Re: Class_ScrollGUI - updated on 2015-02-13

06 Dec 2022, 17:32

evilC wrote:
15 Feb 2015, 06:13
Well, I just sat down and spent 8 hours ripping apart your code.
I *kind* of understand how it works, but some of the code still escapes me a bit lol.

I did manage to re-write it though, and it all seems to work. I made the following changes:
  • No global functions / stuff stored in Instances - Everything is properly encapsulated.
  • Messages bound directly to the class.
  • Does not create a child window - applies the scrollbars to the specified GUI.
  • Gui Size event trapped by Message instead of GuiSize:
  • Not implemented Constructor properly yet, but you do not really need it. You no longer have to specify size.
  • Size limiting feature gone for now (I don't know how you did it).
  • A bunch of functions gone (SetPage etc), I am not sure if they were needed - I may be calculating stuff more often than i need to, I dunno.
Note the dependencies at the start of the script, Don't forget to use the special AHK build!

Code: Select all

; REQUIRES AHK TEST BUILD from HERE: http://ahkscript.org/boards/viewtopic.php?f=24&t=5802
; DEPENDENCIES:
; _Struct():  https://raw.githubusercontent.com/HotKeyIt/_Struct/master/_Struct.ahk - docs: http://www.autohotkey.net/~HotKeyIt/AutoHotkey/_Struct.htm
; sizeof(): https://raw.githubusercontent.com/HotKeyIt/_Struct/master/sizeof.ahk - docs: http://www.autohotkey.net/~HotKeyIt/AutoHotkey/sizeof.htm
; WinStructs: https://github.com/ahkscript/WinStructs
#SingleInstance force
#NoEnv

#include <_Struct>
#include <WinStructs>
;#include *i <SkinSharp>

SetBatchLines, -1

ScrollGui := new _CScrollGui()

Esc::
Gui1Close:
Gui1Escape:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------

class _CScrollGui {
	__New(){
		static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
		static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
		
		Gui, new, hwndhParent
		Gui, % hParent ":Show", w400 h400
		
		Gui, new, % "hwndhwnd -Border -Resize +Parent" hParent
		this._Scroll_H := 1
		this._Scroll_V := 1
		this._Scroll_UseShift := False

		this._hwnd := hwnd
		Loop 20 {
			x := (A_Index -1) * 20
			Gui, Add, Text, x%x%, Test %A_Index%
		}  
		Gui, Show, x100 y100 w200 h200
		
		this.AdjustToChild()
		
		fn := bind(this._Wheel, this)
		OnMessage(WM_MOUSEWHEEL, fn)
		
		fn := bind(this._Scroll, this)
		OnMessage(WM_VSCROLL, fn)
		OnMessage(WM_HSCROLL, fn)
		
		fn := bind(this.AdjustToParent, this)
		OnMessage(0x0005, fn)
	}
	
	AdjustToParent(){
		Static SB_HORZ := 0, SB_VERT = 1
		static SIF_PAGE := 0x2
		
		WindowRECT := this._GetClientRect()
		CanvasRECT := this._GetClientSize()
		Width := WindowRECT.Right
		Height := WindowRECT.Bottom
		If (A_EventInfo <> 1) {
			SH := SV := 0
			If This._Scroll_H {
				If (Width <> This._Scroll_Width) {
					lpsi := this._BlankScrollInfo()
					lpsi.fMask := SIF_PAGE
					lpsi.nPage := Width + 1
					This._SetScrollInfo(SB_HORZ, lpsi)

					This._Scroll_Width := Width
					This._GetScrollInfo(SB_HORZ, SI)
					PosH := SI.nPos
					SH := This._Scroll_PosH - PosH
					This._Scroll_PosH := PosH
				}
			}
			If This._Scroll_V {
				If (Height <> This._Scroll_Height) {
					lpsi := this._BlankScrollInfo()
					lpsi.fMask := SIF_PAGE
					lpsi.nPage := Height + 1
					This._SetScrollInfo(SB_VERT, lpsi)
					
					This._Scroll_Height := Height
					This._GetScrollInfo(SB_VERT, SI)
					PosV := SI.nPos
					SV := This._Scroll_PosV - PosV
					This._Scroll_PosV := PosV
				}
			}
			if (SV || SH){
				this._ScrollWindow(SH, SV)
			}
		}
	}
	
	AdjustToChild(){
		Static SB_HORZ := 0, SB_VERT = 1
		static SIF_ALL := 0x17
		
		WindowRECT := this._GetClientRect()
		CanvasRECT := this._GetClientSize()
		if (!this._Scroll_Width || !this._Scroll_Height){
			Width := WindowRECT.Right
			Height := WindowRECT.Bottom
		}
		this.MaxH := WindowRECT.Right
		this.MaxV := WindowRECT.Bottom
		this.LineH := Ceil(this.MaxH / 20)
		this.LineV := Ceil(this.MaxV / 20)
		
		lpsi := this._BlankScrollInfo()
		lpsi.fMask := SIF_ALL
		
		lpsi.nMin := 0
		lpsi.nMax := CanvasRECT.Bottom
		lpsi.nPage := WindowRECT.Bottom
		this._SetScrollInfo(SB_VERT, lpsi)
		
		lpsi.nMax := CanvasRECT.Right
		lpsi.nPage := WindowRECT.Right
		this._SetScrollInfo(SB_HORZ, lpsi)
		
		this._Scroll_Width := Width
		this._Scroll_Height := Height
	}
	
	_GetScrollInfo(fnBar, ByRef lpsi){
		static SIF_ALL := 0x17
		; https://msdn.microsoft.com/en-us/library/windows/desktop/bb787583%28v=vs.85%29.aspx
		lpsi := this._BlankScrollInfo()
		lpsi.fMask := SIF_ALL
		r := DllCall("User32.dll\GetScrollInfo", "Ptr", this._hwnd, "Int", fnBar, "Ptr", lpsi[], "UInt")
		Return r
	}

	_SetScrollInfo(fnBar, ByRef lpsi, fRedraw := 1){
		; https://msdn.microsoft.com/en-us/library/windows/desktop/bb787595%28v=vs.85%29.aspx
		return DllCall("User32.dll\SetScrollInfo", "Ptr", this._hwnd, "Int", fnBar, "Ptr", lpsi[], "UInt", fRedraw, "UInt")
	}
	
	_ScrollWindow(XAmount, YAmount){
		; https://msdn.microsoft.com/en-us/library/windows/desktop/bb787591%28v=vs.85%29.aspx
		return DllCall("User32.dll\ScrollWindow", "Ptr", this._hwnd, "Int", XAmount, "Int", YAmount, "Ptr", 0, "Ptr", 0)
	}

	; Returns a RECT describing the size of the window
	_GetClientRect(){
		lpRect := new _Struct(WinStructs.RECT)
		DllCall("User32.dll\GetClientRect", "Ptr", This._HWND, "Ptr", lpRect[])
		return lpRect
	}

	; Returns a RECT encompassing all GuiControls and GUIs that are a child of this GUI
	_GetClientSize(){
		DHW := A_DetectHiddenWindows
		DetectHiddenWindows, On
		
		Width := Height := 0
		HWND := this._HWND
		L := T := R := B := LH := TH := ""
		CMD := 5 ; GW_CHILD
		While (HWND := DllCall("GetWindow", "Ptr", HWND, "UInt", CMD, "UPtr")) && (CMD := 2) {
			WinGetPos, X, Y, W, H, % "ahk_id " HWND
			W += X, H += Y
			WinGet, Styles, Style, % "ahk_id " HWND
			If (Styles & 0x10000000) { ; WS_VISIBLE
			If (L = "") || (X < L)
				L := X
			If (T = "") || (Y < T)
				T := Y
			If (R = "") || (W > R)
				R := W
			If (B = "") || (H > B)
				B := H
		}
		Else {
			If (LH = "") || (X < LH)
			LH := X
			If (TH = "") || (Y < TH)
				TH := Y
			}
		}
		DetectHiddenWindows, % DHW
		If (LH <> "") {
			POINT := new _Struct(WinStructs.POINT)
			POINT.x := LH
			DllCall("ScreenToClient", "Ptr", this._HWND, "Ptr", POINT[])
			LH := POINT.x
		}
		If (TH <> "") {
			POINT := new _Struct(WinStructs.POINT)
			POINT.y := TH
			DllCall("ScreenToClient", "Ptr", this._HWND, "Ptr", POINT[])
			TH := POINT.y
		}
		RECT := new _Struct(WinStructs.RECT)
		RECT.Left := L
		RECT.Right := R
		RECT.Top := T
		RECT.Bottom := B
		DllCall("MapWindowPoints", "Ptr", 0, "Ptr", this._HWND, "Ptr", RECT[], "UInt", 2)
		Width := RECT.Right + (LH <> "" ? LH : RECT.Left)
		Height := RECT.Bottom + (TH <> "" ? TH : RECT.Top)

		ret := new _Struct(WinStructs.RECT)
		ret.Right := Width
		ret.Bottom := Height
		return ret
	}
	
	
	_Scroll(WP, LP, Msg, HWND) {
		;ToolTip, % "wp: " WP ", lp: " LP ", msg: " msg ", h: " hwnd
		Static SB_LINEMINUS := 0, SB_LINEPLUS := 1, SB_PAGEMINUS := 2, SB_PAGEPLUS := 3, SB_THUMBTRACK := 5
		Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
		Static SIF_POS := 0x4
		
		If (LP <> 0) {
			Return
		}
		SB := (Msg = WM_HSCROLL ? 0 : 1) ; SB_HORZ : SB_VERT
		SC := WP & 0xFFFF
		SD := (Msg = WM_HSCROLL ? This.LineH : This.LineV)
		SI := 0
		If (!This._GetScrollInfo(SB, SI)){
			Return
		}
		PA := PN := SI.nPos
		If (SC = SB_LINEMINUS) {
			PN := PA - SD
		} Else If (SC = SB_LINEPLUS) {
			PN := PA + SD
		} Else If (SC = SB_PAGEMINUS) {
			PN := PA - SI.nPage
		} Else If (SC = SB_PAGEPLUS) {
			PN := PA + SI.nPage
		} Else If (SC = SB_THUMBTRACK) {
			PN := SI.nTrackPos
		} 
		If (PA = PN) {
			Return 0
		}
		
		lpsi := this._BlankScrollInfo()
		lpsi.fMask := SIF_POS
		lpsi.nPos := PN
		this._SetScrollInfo(SB, lpsi)
		
		This._GetScrollInfo(SB, SI)
		PN := SI.nPos
		If (SB = 0) {
			This._Scroll_PosH := PN
		} Else {
			This._Scroll_PosV := PN
		}
		If (PA <> PN) {
			HS := VS := 0
		}
		If (Msg = WM_HSCROLL) {
			HS := PA - PN
		} Else {
			VS := PA - PN
		}
		this._ScrollWindow(HS,VS)
		Return 0
   }

	_Wheel(WP, LP, Msg, H) {
		Static MK_SHIFT := 0x0004
		Static SB_LINEMINUS := 0, SB_LINEPLUS := 1
		Static WM_MOUSEWHEEL := 0x020A, WM_MOUSEHWHEEL := 0x020E
		Static WM_HSCROLL := 0x0114, WM_VSCROLL := 0x0115
		If (Msg = WM_MOUSEWHEEL) && This._Scroll_UseShift && (WP & MK_SHIFT) {
			Msg := WM_MOUSEHWHEEL
		}
		MSG := (Msg = WM_MOUSEWHEEL ? WM_VSCROLL : WM_HSCROLL)
		SB := ((WP >> 16) > 0x7FFF) || (WP < 0) ? SB_LINEPLUS : SB_LINEMINUS
		Return this._Scroll(sb, 0, MSG, H)
	}
	
	_BlankScrollInfo(){
		lpsi := new _Struct(WinStructs.SCROLLINFO)
		lpsi.cBsize := sizeof(WinStructs.SCROLLINFO)
		return lpsi
	}
}

bind(fn, args*) {  ; bind v1.2
	 try bound := fn.bind(args*)  ; Func.Bind() not yet implemented.
	 return bound ? bound : new BoundFunc(fn, args*)
}

class BoundFunc {
	 __New(fn, args*) {
		  this.fn := IsObject(fn) ? fn : Func(fn)
		  this.args := args
	 }
	 __Call(callee, args*) {
		  if (callee = "" || callee = "call" || IsObject(callee)) {  ; IsObject allows use as a method.
				fn := this.fn, args.Insert(1, this.args*)
				return %fn%(args*)
		  }
	 }
}
Hello @evilC Thank you for this wonderful code, Because it is exactly what I want,
and of course thanks to the author of this post "Just me :mrgreen: "
But my question is how can I use

Code: Select all

Loop 20 {
x := (A_Index -1) * 20
Gui, Add, Text, x%x%, Test %A_Index%
}
Outside the class, Because I want to make a scrollbar for some gui elemnts and I want the scrollbar to appear next to the wanted elements (Like Image Bellow) and not on the entire GUI side thats mean scrollbar should work for some gui elements not for all..
Scrollable Child Gui.png
Scrollable Child Gui.png (34.02 KiB) Viewed 1885 times
And the code you wrote fits me perfectly, but I don't know how to deal with the class, I tried to move the code Bellow

Code: Select all

		Loop 20 {
			Gui, Add, Text, x20, Test %A_Index%
		}
		Gui, Show, hwndhwnd x100 y100 w200 h200
Out of class, but it didn't work.
It would also be great if could replace <_Struct> and <WinStructs> with Class_ScrollGUI
Thanks in advance..
User avatar
lmstearn
Posts: 681
Joined: 11 Aug 2016, 02:32
Contact:

Re: Class_ScrollGUI - updated on 2015-03-13

09 Jan 2023, 00:38

Bit late @HiSoKa, but here goes, scrolling adjusts the position of the entire form and controls to the viewport.
There a a few ways around it, one is to use a borderless child window of the same dimensions as the parent, or original, client window. Start off with all the controls and scrollbars in there, and move any controls out to the parent that are not to be scrolled. Looking at the above graphic, just resize the child form to suit, making it easy if control arrangement is rectangular.
Else, try transparency (or transcol on the background colour) with Winset applied to the child (or sibling) window.
:arrow: itros "ylbbub eht tuO kaerB" a ni kcuts m'I pleH

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 76 guests