question

Cesar-0243 avatar image
0 Votes"
Cesar-0243 asked Cesar-0243 commented

How to get Scrollbar thumb position?

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:

193615-test.png


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
 }


windows-apic++
test.png (16.8 KiB)
· 14
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @Niele-0100,

This issue states that the scrollbar needs to be dynamically adjusted.


0 Votes 0 ·

Hi thank you, in the blog of your link he mention:

The logic behind the thumb size and position calculation I thought I covered in my scroll bar series

I have read all the 12 parts but i could find where he covered this :/



0 Votes 0 ·

Hi @Niele-0100,

Have you tried the formula and SetScrollInfo he mentioned?


0 Votes 0 ·
Show more comments

Hope this document is helpful to you. Processing the WM_HSCROLL and WM_VSCROLL Messages

 case WM_VSCROLL:
         // Get all the vertial scroll bar information.
         si.cbSize = sizeof(si);
         si.fMask = SIF_ALL;
         GetScrollInfo(hwnd, SB_VERT, &si);

     // Save the position for comparison later on.
     yPos = si.nPos;

     switch (LOWORD(wParam))
     {
            
         // User clicked the HOME keyboard key.
     case SB_TOP:
         si.nPos = si.nMin;
         break;

         // User clicked the END keyboard key.
     case SB_BOTTOM:
         si.nPos = si.nMax;
         break;

         // User clicked the top arrow.
     case SB_LINEUP:
         si.nPos -= 1;
         break;

         // User clicked the bottom arrow.
     case SB_LINEDOWN:
         si.nPos += 1;
         break;

         // User clicked the scroll bar shaft above the scroll box.
     case SB_PAGEUP:
         si.nPos -= si.nPage;
         break;

         // User clicked the scroll bar shaft below the scroll box.
     case SB_PAGEDOWN:
         si.nPos += si.nPage;
         break;

         // User dragged the scroll box.
     case SB_THUMBTRACK:
         si.nPos = si.nTrackPos;
         break;

     default:

         break;
     }

        

     // Set the position and then retrieve it.  Due to adjustments
     // by Windows it may not be the same as the value set.
     si.fMask = SIF_POS;
     SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
     GetScrollInfo(hwnd, SB_VERT, &si);

     if (si.nPos != yPos)
     {
         ScrollWindow(hwnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
         UpdateWindow(hwnd);
     }

     return 0;


0 Votes 0 ·

It's been a few days, has your problem been solved?

0 Votes 0 ·

@JunjieZhu-MSFT hi thank you for your time and support but it dont, what could help is the formula to calculate the thumb position according to the current selected item

0 Votes 0 ·

Do you mean this? For example, there are 20 rows of data in total, and you are on the fifth row, so the slider is at the quarter position, right?



0 Votes 0 ·
Show more comments

1 Answer

JunjieZhu-MSFT avatar image
0 Votes"
JunjieZhu-MSFT answered Cesar-0243 commented

Hello,
Welcome to Microsoft Q&A!

For the convenience of viewing the pictures, I will first post my test process here.


my calculation formula (floating point calculations):
BTW, The number of rows in listbox starts from 0.

 ListRowPos = ( ThumbPos - ArrowHeight ) / ( ScrollArea ) * TotalRows;

Test 1:
A total of 800 pieces of data, set the maximum range of the scroll bar to 800
Because the floating point number is rounded after calculation, there will be a deviation of one line.
202703-gif-2022-5-17-17-17-53.gif

Test 2:
A total of 800 pieces of data, set the maximum range of the scroll bar to 10
The slider slides smoothly, but the list slides very stiffly.
202731-gif-2022-5-17-17-25-39.gif

I hope my formula is helpful to you. My project is just a simple beta version, and the constant variables in it are all directly assigned. If you need, I can share the code in the txt document.

Thank you.


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hello thank you, ive been away from my computer this week, as soon i can test ill reply!

1 Vote 1 ·