I'm working on creating a 'dummy' ScrollBar to replace the original Listbox Scrollbar, then I can customize its shape/colors, etc, for this, I need the information about each item index relative to the thumb position.
I'm calling GetScrollbarInfo and SetScrollInfo in a loop that moves the thumb around and get its position:
While (I <= M) {
NumPut(I, SI, 20, "Int") ; nPos
DllCall("SetScrollInfo", "Ptr", hWnd, "UInt", 1, "Ptr", &SI, "UInt", 0, "Int")
DllCall("GetScrollBarInfo", "Ptr", hWnd, "Int", 0xFFFFFFFB, "Ptr", &SBI)
VSB[I, "THT"] := NumGet(SBI, 24, "Int") ; thumb top
VSB[I, "THB"] := NumGet(SBI, 28, "Int") ; thumb bottom
I++
}
However when there are many items in a Listbox, GetScrollBarInfo
starts returning a different top position than where it currently is:
TopIndex 100
reports Thumb Top
at 33, but its really at 29
as seen in the image below:
Also deducting the bottom - top (41-33) we have 8, why 8 if the thumb height is 17?
Why does this happen? when the are just a few items it does report each position correctly.
OBS:
----
The language in the script below is AutoHotkey
I tried to get some help in the AutoHotkey
forum but its a very specific question related to WinApi
.
I'm adding the tag c++
to see if I can target more people and get any kind of help, so answers in c++ are also welcome.
The relevant code is only inside of the function GetVScrollBarPositions
and it's all commented.
Text := ""
Gui, Color, 0
Loop, 200
Text .= A_Index . "A|"
Gui, +E0x02000000 +E0x00080000
Gui, Add, Listbox, w100 r5 +VScroll hWndhWnd, %Text%
GuiControlGet, P, Pos, %hWnd%
Gui, Add, Text, xm, ListBox Height: %Ph%
Gui, Show, w300 h356, Test
Return
GuiClose:
ExitApp
F2::
S := A_TickCount
VSB := GetVScrollBarPositions(hWnd)
T := A_TickCount - S
Gui, Result:New, +Owner1
Gui, Add, Text, xm w250, Range Min:
Gui, Add, Text, x+0 yp w100, % VSB.Min
Gui, Add, Text, xm w250, Range Max:
Gui, Add, Text, x+0 yp w100, % VSB.Max
Gui, Add, Text, xm w250, Page Size:
Gui, Add, Text, x+0 yp w100, % VSB.Page
Gui, Add, Text, xm w250, SB Top:
Gui, Add, Text, x+0 yp w100, % VSB.SBT
Gui, Add, Text, xm w250, SB Bottom:
Gui, Add, Text, x+0 yp w100, % VSB.SBB
Gui, Add, Text, xm w250, Arrow Height:
Gui, Add, Text, x+0 yp w100, % VSB.ABH
Gui, Add, ListView, xm w350 r10, Item Index|Thumb Top|Thumb Bottom
I := VSB.Min
M := VSB.Max
While (I <= M) {
LV_Add("", I, VSB[I, "THT"], VSB[I, "THB"])
I++
}
Gui, Show, , Vertical Scroll Bar Info (%T% ms)
Return
GetVScrollBarPositions(hWnd) {
VarSetCapacity(SI, 28, 0) ; SCROLLINFO structure
NumPut(28, SI, 0, "UInt") ; cbSize
NumPut(0x17, SI, 4, "UInt") ; fMask = SIF_ALL
If !DllCall("GetScrollInfo", "Ptr", hWnd, "Int", 1, "Ptr", &SI)
Return False
VSB := {}
VSB.Min := NumGet(SI, 8, "Int") ; range min
VSB.Max := NumGet(SI, 12, "Int") ; range max
VSB.Page := NumGet(SI, 16, "Int") ; page size
Pos := NumGet(SI, 20, "Int") ; current pos
VarSetCapacity(SBI, 60, 0)
NumPut(60, SBI, 0, "Int")
DllCall("GetScrollBarInfo", "Ptr", hWnd, "Int", 0xFFFFFFFB, "Ptr", &SBI)
VSB.SBT := NumGet(SBI, 8, "Int") ; scroll bar top
VSB.SBB := NumGet(SBI, 16, "Int") ; scroll bar bottom
VSB.ABH := NumGet(SBI, 20, "Int") ; arrow button height
NumPut(4, SI, 4, "Int") ; fMask = SIF_POS
I := VSB.Min
M := VSB.Max
While (I <= M) {
NumPut(I, SI, 20, "Int") ; nPos
DllCall("SetScrollInfo", "Ptr", hWnd, "UInt", 1, "Ptr", &SI, "UInt", 0, "Int")
DllCall("GetScrollBarInfo", "Ptr", hWnd, "Int", 0xFFFFFFFB, "Ptr", &SBI)
VSB[I, "THT"] := NumGet(SBI, 24, "Int") ; thumb top
VSB[I, "THB"] := NumGet(SBI, 28, "Int") ; thumb bottom
I++
}
NumPut(Pos, SI, 20, "Int") ; restore the original pos
DllCall("SetScrollInfo", "Ptr", hWnd, "UInt", 1, "Ptr", &SI, "UInt", 1, "Int")
Return VSB
}