 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
ahklerner
Joined: 26 Jun 2006 Posts: 1249 Location: USA
|
Posted: Sun Feb 10, 2008 8:24 pm Post subject: Scrollable Gui - Proof of Concept |
|
|
Many Thanks to the Guest Jamey in this post: http://www.autohotkey.com/forum/viewtopic.php?t=3730
If it originally came form someone else, let me know please.
This is just something I was playing with....maybe someone can make it better. Just posting for fun.
There are currently multiple bugs....tabbing through controls does not work....some issues with resizing....etc etc...
I do not care to really do anything more with it, so if some one makes enhancements, post them here, and I will refer to them from the first post.
Here is the code:
| Code: | DetectHiddenWindows, On
Gui, 1:+LastFound +0x200000 +Resize +0x2000000
hGui := WinExist()
Gui, 1:Add, Edit, r2 w150 , Edit 1
Gui, 1:Add, Edit, r2 w150 , Edit 2
Gui, 1:Add, Edit, r2 w150 , Edit 3
Gui, 1:Add, Edit, r2 w150 , Edit 4
Gui, 1:Add, Edit, ym r2 w150 , Edit 5
Gui, 1:Add, Edit, r2 w150 , Edit 6
Gui, 1:Add, Edit, r2 w150 , Edit 7
Gui, 1:Add, Edit, r2 w150 , Edit 8
Gui, 1:Add, Button, gGo, Go
Gui, 1:Show, Hide
ScrollInit()
Gui, 1:Show, h100
Return
ScrollInit() {
Global
VarSetCapacity(SCROLLBAR_INFO, 28, 0) ;Allocate SCROLLBAR_INFO structure and zero it
NumPut(28, &SCROLLBAR_INFO) ;Initialize its count-bytes parameter
NumPut(0x17, &SCROLLBAR_INFO + 4) ;Initialize the mask for what properties to get or set, SIF_ALL = 0x17
SetScrollBar(hGui, 0, 100, 10, 0)
C_Create(1)
GuiWinProc := RegisterCallback("GuiWindowProc", "" ; "" to avoid fast-mode for subclassing.
, 4, hGui) ; Must specify exact ParamCount when EventInfo parameter is present.
GuiWinProcOld := DllCall("SetWindowLong", UInt, hGui, Int, -4 ; -4 is GWL_WNDPROC
, Int, GuiWinProc, UInt) ; Return value must be set to UInt vs. Int.
ConWinProc := RegisterCallback("ConWinProc", "" ; "" to avoid fast-mode for subclassing.
, 4, hGui) ; Must specify exact ParamCount when EventInfo parameter is present.
ConWinProcOld := DllCall("SetWindowLong", UInt, hContainer, Int, -4 ; -4 is GWL_WNDPROC
, Int, ConWinProc, UInt) ; Return value must be set to UInt vs. Int.
}
C_Create(GuiNum,Height=0,Width=0) {
global hContainer, Container
Gui %GuiNum%:+LastFound
hGui := WinExist()
If !Height && !Width
WinGetPos,,, Width, Height, ahk_id %hGui%
Gui %GuiNum%:Add, Text,x0 y0 h%Height% w%Width% +0x4000000 +0x2000000 hwndhContainer vContainer
WinGet, CList, ControlListhWnd, ahk_id %hGui%
;MsgBox % CList
Loop, Parse, CList, `n
DllCall("SetParent", "uint", A_LoopField, "uint", hContainer)
}
GuiSize:
VScrollPixelsPerLine := A_GuiHeight / 100
Return
Esc::ExitApp
ConWinProc(hwnd, uMsg, wParam, lParam) {
global ConWinProcOld, GuiWinProcOld, GuiWinProc
;Critical
OldFormat := A_FormatInteger
SetFormat, Integer, Hex
MsgLst := WM_COMMAND := 0x111
MsgLst .= "," . WM_SYSCOMMAND := 0x112
uMsg += 0
SetFormat, Integer, %OldFormat%
if uMsg in %MsgLst%
{
ReturnVal := DllCall("CallWindowProcA", UInt, GuiWinProcOld, UInt, A_EventInfo, UInt, uMsg, UInt, wParam, UInt, lParam)
return ReturnVal
}
return DllCall("CallWindowProcA", UInt, ConWinProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
}
Go:
MsgBox
Return
GuiWindowProc(hwnd, uMsg, wParam, lParam) {
;Critical
OldFormat := A_FormatInteger
SetFormat, Integer, Hex
global GuiWinProcOld, GuiWinProc, VScrollPixelsPerLine, Container, hContainer
MsgLst := WM_VSCROLL := 0x115
uMsg += 0
SetFormat, Integer, %OldFormat%
if uMsg in %MsgLst%
{
global hGui ;Only handle messages for the window we want to scroll
if (hwnd != hGui)
return DllCall("CallWindowProcA", UInt, GuiWinProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
wParamWordLow := Mod(wParam, 0x10000)
wParamWordHigh := (wParam - wParamWordLow) / 0x10000
if (wParamWordLow = 5 or wParamWordLow = 8) ;SB_THUMBTRACK or SB_ENDSCROLL
return DllCall("CallWindowProcA", UInt, GuiWinProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
QueryScrollBar(hwnd, nMin, nMax, nPage, nPos, nTrackPos)
if (wParamWordLow = 7) ;SB_BOTTOM
a:= "" ; MsgBox, SB_BOTTOM
else if (wParamWordLow = 6) ;SB_TOP
a:= "" ; MsgBox, SB_TOP
else if (wParamWordLow = 1) { ;SB_LINEDOWN
SetScrollBar(hwnd, nMin, nMax, nPage, NewPos := nPos+1)
GuiControl,1:Move, Container, % "y" . -NewPos * VScrollPixelsPerLine
}else if (wParamWordLow = 0) { ;SB_LINEUP
SetScrollBar(hwnd, nMin, nMax, nPage, NewPos := nPos-1)
GuiControl,1:Move, Container, % "y" . -NewPos * VScrollPixelsPerLine
}else if (wParamWordLow = 3) { ;SB_PAGEDOWN
SetScrollBar(hwnd, nMin, nMax, nPage, NewPos := nPos+nPage)
GuiControl,1:Move, Container, % "y" . -NewPos * VScrollPixelsPerLine
}else if (wParamWordLow = 2) { ;SB_PAGEUP
SetScrollBar(hwnd, nMin, nMax, nPage, NewPos := nPos-nPage)
GuiControl,1:Move, Container, % "y" . -NewPos * VScrollPixelsPerLine
}else if (wParamWordLow = 4) { ;SB_THUMBPOSITION
SetScrollBar(hwnd, nMin, nMax, nPage, NewPos := wParamWordHigh)
GuiControl,1:Move, Container, % "y" . -NewPos * VScrollPixelsPerLine
}
; ToolTip wParamWordLow = %wParamWordLow%`nContainerY = %ContainerY%`nVScrollPixelsPerLine = %VScrollPixelsPerLine%`nhwnd = %hwnd%`nnMin = %nMin%`nnMax = %nMax%`nnPage = %nPage%`nnPos = %nPos%`nnTrackPos = %nTrackPos% ;`nMsgLst= |%MsgLst%|
return DllCall("CallWindowProcA", UInt, GuiWinProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
}
; Otherwise (since above didn't return), pass all unhandled events to the original WindowProc.
; SetFormat, Integer, %OldFormat%
return DllCall("CallWindowProcA", UInt, GuiWinProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
}
QueryScrollBar(hwnd, ByRef nMin, ByRef nMax, ByRef nPage, ByRef nPos, ByRef nTrackPos)
{
;Win32 API: BOOL GetScrollInfo( HWND hwnd, int fnBar, LPSCROLLINFO lpsi )
global SCROLLBAR_INFO
bSuccess := DllCall("GetScrollInfo", UInt, hwnd, Int, 1, UInt, &SCROLLBAR_INFO) ;SB_VERT = 1
if (!bSuccess)
return false
nMin := NumGet(&SCROLLBAR_INFO, 8)
nMax := NumGet(&SCROLLBAR_INFO, 12)
nPage := NumGet(&SCROLLBAR_INFO, 16)
nPos := NumGet(&SCROLLBAR_INFO, 20)
nTrackPos := NumGet(&SCROLLBAR_INFO, 24)
return true
}
;---------------------------------------------------------------------------------------------------------------
SetScrollBar(hwnd, nMin, nMax, nPage, nPos)
{
;Win32 API: int SetScrollInfo( HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, BOOL fRedraw )
global SCROLLBAR_INFO
NumPut(nMin, &SCROLLBAR_INFO + 8) ;Min
NumPut(nMax, &SCROLLBAR_INFO + 12) ;Max
NumPut(nPage, &SCROLLBAR_INFO + 16) ;Page
NumPut(nPos, &SCROLLBAR_INFO + 20) ;Pos
iReturnPos := DllCall("SetScrollInfo", UInt, hwnd, Int, 1, UInt, &SCROLLBAR_INFO, Int, true) ;SB_VERT = 1
return (iReturnPos == nPos)
}
;---------------------------------------------------------------------------------------------------------------
GuiClose:
ExitApp
return
;---------------------------------------------------------------------------------------------------------------
|
_________________
ʞɔпɟ əɥʇ ʇɐɥʍ |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2737 Location: Australia, Qld
|
Posted: Mon Feb 11, 2008 2:50 am Post subject: |
|
|
Here is my attempt (based on some C++ code I wrote long ago.)
| Code: | #NoEnv
OnMessage(0x115, "OnScroll") ; WM_VSCROLL
OnMessage(0x114, "OnScroll") ; WM_HSCROLL
Gui, +Resize +0x300000 ; WS_VSCROLL | WS_HSCROLL
Loop 8
Gui, Add, Edit, R5 W400, Edit %A_Index%
Gui, Add, Button,, Do absolutely nothing
Gui, Show, W200 H200
Gui, +LastFound
GroupAdd, MyGui, % "ahk_id " . WinExist()
return
GuiSize:
UpdateScrollBars(A_Gui, A_GuiWidth, A_GuiHeight)
return
GuiClose:
ExitApp
#IfWinActive ahk_group MyGui
WheelUp::
WheelDown::
+WheelUp::
+WheelDown::
; SB_LINEDOWN=1, SB_LINEUP=0, WM_HSCROLL=0x114, WM_VSCROLL=0x115
OnScroll(InStr(A_ThisHotkey,"Down") ? 1 : 0, 0, GetKeyState("Shift") ? 0x114 : 0x115, WinExist())
return
#IfWinActive
UpdateScrollBars(GuiNum, GuiWidth, GuiHeight)
{
static SIF_RANGE=0x1, SIF_PAGE=0x2, SIF_DISABLENOSCROLL=0x8, SB_HORZ=0, SB_VERT=1
Gui, %GuiNum%:Default
Gui, +LastFound
; Calculate scrolling area.
Left := Top := 9999
Right := Bottom := 0
WinGet, ControlList, ControlList
Loop, Parse, ControlList, `n
{
GuiControlGet, c, Pos, %A_LoopField%
if (cX < Left)
Left := cX
if (cY < Top)
Top := cY
if (cX + cW > Right)
Right := cX + cW
if (cY + cH > Bottom)
Bottom := cY + cH
}
Left -= 8
Top -= 8
Right += 8
Bottom += 8
ScrollWidth := Right-Left
ScrollHeight := Bottom-Top
; Initialize SCROLLINFO.
VarSetCapacity(si, 28, 0)
NumPut(28, si) ; cbSize
NumPut(SIF_RANGE | SIF_PAGE, si, 4) ; fMask
; Update horizontal scroll bar.
NumPut(ScrollWidth, si, 12) ; nMax
NumPut(GuiWidth, si, 16) ; nPage
DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_HORZ, "uint", &si, "int", 1)
; Update vertical scroll bar.
; NumPut(SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL, si, 4) ; fMask
NumPut(ScrollHeight, si, 12) ; nMax
NumPut(GuiHeight, si, 16) ; nPage
DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_VERT, "uint", &si, "int", 1)
if (Left < 0 && Right < GuiWidth)
x := Abs(Left) > GuiWidth-Right ? GuiWidth-Right : Abs(Left)
if (Top < 0 && Bottom < GuiHeight)
y := Abs(Top) > GuiHeight-Bottom ? GuiHeight-Bottom : Abs(Top)
if (x || y)
DllCall("ScrollWindow", "uint", WinExist(), "int", x, "int", y, "uint", 0, "uint", 0)
}
OnScroll(wParam, lParam, msg, hwnd)
{
static SIF_ALL=0x17, SCROLL_STEP=10
bar := msg=0x115 ; SB_HORZ=0, SB_VERT=1
VarSetCapacity(si, 28, 0)
NumPut(28, si) ; cbSize
NumPut(SIF_ALL, si, 4) ; fMask
if !DllCall("GetScrollInfo", "uint", hwnd, "int", bar, "uint", &si)
return
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "uint", hwnd, "uint", &rect)
new_pos := NumGet(si, 20) ; nPos
action := wParam & 0xFFFF
if action = 0 ; SB_LINEUP
new_pos -= SCROLL_STEP
else if action = 1 ; SB_LINEDOWN
new_pos += SCROLL_STEP
else if action = 2 ; SB_PAGEUP
new_pos -= NumGet(rect, 12, "int") - SCROLL_STEP
else if action = 3 ; SB_PAGEDOWN
new_pos += NumGet(rect, 12, "int") - SCROLL_STEP
else if action = 5 ; SB_THUMBTRACK
new_pos := NumGet(si, 24, "int") ; nTrackPos
else if action = 6 ; SB_TOP
new_pos := NumGet(si, 8, "int") ; nMin
else if action = 7 ; SB_BOTTOM
new_pos := NumGet(si, 12, "int") ; nMax
else
return
min := NumGet(si, 8, "int") ; nMin
max := NumGet(si, 12, "int") - NumGet(si, 16) ; nMax-nPage
new_pos := new_pos > max ? max : new_pos
new_pos := new_pos < min ? min : new_pos
old_pos := NumGet(si, 20, "int") ; nPos
x := y := 0
if bar = 0 ; SB_HORZ
x := old_pos-new_pos
else
y := old_pos-new_pos
; Scroll contents of window and invalidate uncovered area.
DllCall("ScrollWindow", "uint", hwnd, "int", x, "int", y, "uint", 0, "uint", 0)
; Update scroll bar.
NumPut(new_pos, si, 20, "int") ; nPos
DllCall("SetScrollInfo", "uint", hwnd, "int", bar, "uint", &si, "int", 1)
} |
The main differences are:
- OnMessage is used rather than subclassing the window.
- SB_THUMBTRACK is handled instead of SB_THUMBPOSITION, so the controls scroll in real-time (before you release the button.)
- Resizing is handled better.
- Tabbing works, though it doesn't scroll automatically (so the control tabbed to may not be visible.)
- ScrollWindow() is used to move all of the controls.
Bug: The horizontal scroll bar isn't accounted for until the next resize after it is shown. (This is usually only noticeable when restoring the window after maximizing.)
Updated to support mouse wheel.
Last edited by Lexikos on Wed Feb 20, 2008 3:15 am; edited 1 time in total |
|
| Back to top |
|
 |
ahklerner
Joined: 26 Jun 2006 Posts: 1249 Location: USA
|
Posted: Mon Feb 11, 2008 2:58 am Post subject: |
|
|
Well now, That is just freaking awesome!!!!!
Thanks for sharing. _________________
ʞɔпɟ əɥʇ ʇɐɥʍ |
|
| Back to top |
|
 |
AdamPash
Joined: 27 Sep 2007 Posts: 25 Location: http://lifehacker.com
|
Posted: Wed Feb 20, 2008 1:20 am Post subject: |
|
|
| This really is incredible, thanks a lot. It's perfect for a script I'm putting together right now. One question, though: Is it possible to get scrolling to work with the mouse scroll wheel? Or even from the keyboard with the up/down arrows? |
|
| Back to top |
|
 |
engunneer
Joined: 30 Aug 2005 Posts: 6847 Location: Pacific Northwest, US
|
Posted: Wed Feb 20, 2008 1:35 am Post subject: |
|
|
Adam, Is your code based on lexiKos' or ahklerner's code? _________________
Unless otherwise noted, all code is untested.
Common Answers: 1.(Loops, Viruses, etc.) 2. Search 3.RTFM |
|
| Back to top |
|
 |
AdamPash
Joined: 27 Sep 2007 Posts: 25 Location: http://lifehacker.com
|
Posted: Wed Feb 20, 2008 1:37 am Post subject: |
|
|
| Ah, sorry about that. It's based on lexiKos'. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2737 Location: Australia, Qld
|
Posted: Wed Feb 20, 2008 3:16 am Post subject: |
|
|
| I originally tried catching WM_MOUSEWHEEL, but apparently that is only sent to the focused control. I've updated the script to support the mouse wheel, via hotkeys. |
|
| Back to top |
|
 |
Wdb
Joined: 27 Feb 2006 Posts: 15 Location: Italy
|
Posted: Thu Feb 21, 2008 3:36 pm Post subject: |
|
|
| lexiKos wrote: | | Here is my attempt (based on some C++ code I wrote long ago.) |
This is a very good job lexiKos, thank you!
And is it possible to retrieve the absolute coordinates of the displayed page, specially when I scroll down the wheel mouse ??? (i.e: if the page dimension exceed the screen widht?) |
|
| Back to top |
|
 |
AdamPash
Joined: 27 Sep 2007 Posts: 25 Location: http://lifehacker.com
|
Posted: Fri Feb 22, 2008 12:10 am Post subject: |
|
|
That mouse scroll update worked like a charm, thanks a lot lexiKos!
I also included the up and down keys with the rest of the hotkeys to scroll the window using those (there's user input where that'll be a problem with my GUI window, so there's no concern for conflict). So now it just looks like this:
| Code: | WheelUp::
WheelDown::
+WheelUp::
+WheelDown::
Up::
Down::
; SB_LINEDOWN=1, SB_LINEUP=0, WM_HSCROLL=0x114, WM_VSCROLL=0x115
OnScroll(InStr(A_ThisHotkey,"Down") ? 1 : 0, 0, GetKeyState("Shift") ? 0x114 : 0x115, WinExist())
return |
|
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2737 Location: Australia, Qld
|
Posted: Fri Feb 22, 2008 12:22 am Post subject: |
|
|
| Wdb wrote: | | And is it possible to retrieve the absolute coordinates of the displayed page, specially when I scroll down the wheel mouse ??? (i.e: if the page dimension exceed the screen widht?) | You could get the position of the scroll bar using GetScrollPos or similar. There is no "page" - ScrollWindow just offsets each control by the difference in scroll bar position (when it moves.) |
|
| Back to top |
|
 |
Wdb
Joined: 27 Feb 2006 Posts: 15 Location: Italy
|
Posted: Fri Feb 22, 2008 7:38 am Post subject: |
|
|
| lexiKos wrote: | | Wdb wrote: | | And is it possible to retrieve the absolute coordinates of the displayed page, specially when I scroll down the wheel mouse ??? (i.e: if the page dimension exceed the screen widht?) | You could get the position of the scroll bar using GetScrollPos or similar. There is no "page" - ScrollWindow just offsets each control by the difference in scroll bar position (when it moves.) |
Ok, thank you.
Another question:
what happens if I de-comment your statements NumPut:
| Code: |
; Update vertical scroll bar.
; NumPut(SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL, si, 4) ; fMask
|
|
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2737 Location: Australia, Qld
|
Posted: Fri Feb 22, 2008 9:45 am Post subject: |
|
|
| That adds the SIF_DISABLENOSCROLL flag, which causes the scroll bar to be disabled rather than hidden when it is not needed. |
|
| Back to top |
|
 |
automaticman
Joined: 27 Oct 2006 Posts: 372
|
Posted: Fri Feb 22, 2008 2:20 pm Post subject: |
|
|
| A zoomable GUI (=ZUI), proof of concept would be also interesting. |
|
| Back to top |
|
 |
YokoiL
Joined: 18 Jun 2008 Posts: 3
|
Posted: Thu Jun 19, 2008 10:30 am Post subject: |
|
|
| Quote: | | Tabbing works, though it doesn't scroll automatically (so the control tabbed to may not be visible.) |
Is there anyway to make it so that you can use tab and it scrolls to where the cursor is? |
|
| Back to top |
|
 |
Dra_Gon
Joined: 25 May 2007 Posts: 313
|
Posted: Tue Dec 02, 2008 2:01 am Post subject: |
|
|
Only saw this when SKAN pointed it out, but it looks great!
Ciao,
Dra'Gon _________________
For a good laugh {hopefully} >> megamatts.50megs.com
My WritersCafe profile>>
http://www.writerscafe.org/writers/BlueDragonFire/ |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|