Link to home
Start Free TrialLog in
Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Get rectangle of scroll thumb!

Ah hello.

Quite a simple query this one, I hope:

I have a scrollbar derived from CScrollbar.  In this case, it is a vertical scrollbar.  I want to get the window rectangle of the scroll thumb (the bit we can drag up and down/left and right) so I can paint a colour over it.  (See http://msdn.microsoft.com/en-us/library/ms997557.aspx#scroll32_topic2)

I can get the rect of the, say, up arrow, like this:

CRect rcWnd, rcArrow;
// Get rect of whole scrollbar
GetWindowRect ( &rcWnd ); ScreenToClient ( &rcWnd );

// Get "height" of scroll button
int nHeight = GetSystemMetrics ( SM_CYVSCROLL );

rcArrow.left = 0;
rcArrow.right = rcWnd.right;      
rcArrow.bottom = nHeight;
rcArrow.top = 0;

And similar methods for the horizontal scrolling.

Once I have the arrow rectangles and the thumb rectangle, I can get the rectangle of shafts above and below the thumb

Can someone help by providing a code sample please?

TIA
SOLUTION
Avatar of romanm
romanm

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

Thank `you for the reply.  Unfortunately, the code did not work.  I always get the height returned as 16; rest of the dimensions are equally curious (see image)

Please if you would download this sample project (~50KB) to see if you can see what the problem is: http://www.yousendit.com/download/Y2ovTmZhV3JOQnhFQlE9PQ

TIA

EG.JPG
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of DanRollins
With modern scrollbars, the size of the thumb is proportional to the amount of data that is visible in the scrollable portion of the window.  For instance, if 10% of the data is visible, then the thumb will occupy 10% of the scrollbar shaft.
The easiest way to obtain the correct values is to use the
    GetScrollInfo Function
    http://msdn.microsoft.com/en-us/library/bb787583(VS.85).aspx
The SCROLLINFO structure will be populated with everything you need to know.  For instance put this in an AppWizard-generated SDI with a RichEdit View:
 void CMainFrame::OnAppAbout()
{
     // MessageBox("hi");
     CWnd*p = GetActiveView();
     SCROLLINFO rSI;
     p->GetScrollInfo(SB_VERT, &rSI, SIF_ALL );
}
Breakpoint after the GetScrollInfo call.  Try a number of variations:  Tall window, short window, window showing a large file, window showing a small file.   You'll see that the value in rSI->nMax shows the height of the complete document, rSI->nPage shows the height of the visible area,  rSI->nPos shows the location of the top of the thumb.  The height of the thumb itself is nPage -- but with certain limits (once lower than a certain minimum, it stays that size and then disappears altogether and it also disappears when the entire file is visible.)
Avatar of mrwad99

ASKER

Dan, thanks for the comment, but that does not work.  The call to GetScrollInfo() always fails.  I have read the documentation and cannot see why this is: I thought initially that the scrollbar belongs to the mainframe, not the view, so tried that, and it still failed.

Any ideas?

romanm; thanks - that appears to work.   Will wait for any comments from Dan before closing
It should be easy enough to find out which window owns the scrollbar that you are interested in painting!  Use Spy++ if needed.  
If you are using the Win32 API rather than the MFC function, be sure to populate
    SCROLLINFO.cbSize
Avatar of mrwad99

ASKER

romanm: I am sorry but your code does not work.  It is ok when the thumb is at the top, but otherwise it gives incorrect results.  See below.

OK this is really getting annoying now.
Dan/romanm:
I got the SCROLLINFO approach working, and am playing with a rich edit SDI (see second screenshot).  GetScrollInfo() gives the same values as romanm gets via individual function calls.  Please take a look at the screenshot below.
As you can see, I have labelled up the dimensions.  My page is 242 "units" and my scrollbar is 243 pixels high.  OK then.
My first question is "What the heck units are the values in the SCROLLINFO?"  They don't appear to be pixels - the current position of the top of the scrollbar is "71" but I have measured it on the image (in red) and it is 48 pixels!
So, I try and get some sort of "ratio" going: SCROLLINFO units to pixels:
 static int nHeight = GetSystemMetrics ( SM_CYVSCROLL );
 SCROLLINFO rSI;
 VERIFY ( GetScrollInfo ( SB_VERT, &rSI ) );
 CRect rcWnd; GetClientRect ( rcWnd );
 double dRatio =  ( rcWnd.Height() - ( 2 * nHeight ) ) / ( double ) rSI.nPage;
dRatio is the ratio of pixels of the scrollbar (not including the up/down arrows, hence subtracting twice the height of the vertical scroll arrow) to "SCROLLINFO" units.  This works out as 0.871: so, .0871 pixels is one SCROLLINFO unit.
OK then.  It figures then that the top of the scrollbar is
 double dTop = dRatio * rSI.nPos;
~62 pixels.  Nope.  Still not right.
????
Please someone tell me what is going on, my head is spinning.
TIA

SDI.JPG
Problem.JPG
The center of the thumb is the focal point for your measurements.  The thumb's size is really only an indication of the proportion of visible to not-visible data.   So the top and bottom will vary but the center will always be there.
Avatar of mrwad99

ASKER

>> The center of the thumb is the focal point for your measurements.

OK, so now we are after the *center* of the thumb.  There is no function/argument for getting that though, so how do you propose I get that?

Thanks.
You have chosen a particularly difficult task.  Several articles indicate that one can't really "skin" a standard scrollbar and that the best route is to replace it entirely.  The source code here:

   Custom Scrollbar Library  ("Cool Scrollbars")
   http://www.codeproject.com/KB/dialog/coolscroll.aspx
may include all of the required calculations.  But be sure to read the bottom part, which describes some of the complications with skinning.
There are a number of other codeProject articles that are worth reading:
    http://www.codeproject.com/info/search.aspx?artkw=scrollbar&sbo=kw
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

Thanks, I will look at these links, then close this question.
Avatar of mrwad99

ASKER

OK, points split based on effort.  Many thanks all :o)
Avatar of mrwad99

ASKER

OK, I have just got back to this, and have found that your calculations don't work,apart from in the example you showed.

Look at the screenshot below if you will, and the values that I have obtained via GetScrollInfo.

You can see that in the third image, *no way* is the document scrolled; there is not even a scrollbar visible!

This is ridiculous now.  There just does not appear to be any way to get the scrollbar location reliably.

Do you have anything to say on this Dan, do you want more points, or are you just as confused (and probably as sick of this) as I am?

1.JPG
2.JPG
3.JPG
These are all special cases.  Either the window is taller than the document (1 and 3) so there is no thumb at all, or the thumb is "pinned" at the bottom and/or has reached its arbitrarily-selected maximum height (2).  In such cases, the programmers had to decide on how to handle the situation and there were a number of options available to them.  Since they do the calculations and they also draw the control, they can decide which option to use in which cases --  as long as they are internally consistant.
Avatar of mrwad99

ASKER

Ah right.  Thanks for that :)