# Scroll bars

This topic is 4485 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I am using C++ with the Win32 API. I am having a bit of a problem with scroll bars. When the application boots, there should not be any scroll bars. When a bitmap is loaded, and the bitmap is larger than the client area of the screen, then I need to include scroll bars. When I load a bitmap that is larger than the client area, the scroll bars are not showing as they are supposed to. Here is the code:
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static int cur_xpos;
static int cur_ypos;
static SCROLLINFO HScrollInfo;
static SCROLLINFO VScrollInfo;

switch(iMsg)
{
case WM_CREATE:
cur_xpos = 0;
HScrollInfo.cbSize = sizeof(SCROLLINFO);
HScrollInfo.nMin = 0;
HScrollInfo.nMax = 1000;
HScrollInfo.nPage = 100;
HScrollInfo.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL;
SetScrollInfo(hWnd,SB_HORZ,&HScrollInfo,false);
cur_ypos = 0;
VScrollInfo.cbSize = sizeof(SCROLLINFO);
VScrollInfo.nMin = 0;
VScrollInfo.nMax = 1000;
VScrollInfo.nPage = 100;
VScrollInfo.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL;
SetScrollInfo(hWnd,SB_VERT,&VScrollInfo,false);

hDC = GetDC(hWnd);
hpen = CreatePen(PS_SOLID,2,RGB(0,0,255));
old_pen = (HPEN)SelectObject(hDC,hpen);
hbrush = (HBRUSH)GetStockObject(NULL_BRUSH);
old_brush = (HBRUSH)SelectObject(hDC,hbrush);

return 0;
case WM_HSCROLL:
switch(LOWORD(wParam))
{
case SB_LINELEFT:
cur_xpos = cur_xpos - 1;
break;

case SB_LINERIGHT:
cur_xpos = cur_xpos + 1;
break;

case SB_THUMBPOSITION:
cur_xpos = HIWORD(wParam);
break;

default:
break;
}
HScrollInfo.cbSize = sizeof(SCROLLINFO);
GetScrollInfo(hWnd, SB_HORZ, &HScrollInfo);

if(cur_xpos != HScrollInfo.nPos)
{
if(cur_xpos > HScrollInfo.nMax)
cur_xpos = HScrollInfo.nMax;
else if(cur_xpos < HScrollInfo.nMin)
cur_xpos = HScrollInfo.nMin;

HScrollInfo.nPos = cur_xpos;

SetScrollInfo(hWnd, SB_HORZ, &HScrollInfo, true);

InvalidateRect(hWnd,NULL,TRUE);
}
return 0;

case WM_VSCROLL:
switch(LOWORD(wParam))
{
case SB_LINELEFT:
cur_ypos = cur_ypos - 1;
break;

case SB_LINERIGHT:
cur_ypos = cur_ypos + 1;
break;

case SB_THUMBPOSITION:
cur_ypos = HIWORD(wParam);
break;

default:
break;
}
VScrollInfo.cbSize = sizeof(SCROLLINFO);
GetScrollInfo(hWnd, SB_VERT, &VScrollInfo);

if(cur_ypos != VScrollInfo.nPos)
{
if(cur_ypos > VScrollInfo.nMax)
cur_ypos = VScrollInfo.nMax;
else if(cur_ypos < VScrollInfo.nMin)
cur_ypos = VScrollInfo.nMin;

VScrollInfo.nPos = cur_ypos;

SetScrollInfo(hWnd, SB_VERT, &VScrollInfo, true);

InvalidateRect(hWnd,NULL,TRUE);
}
return 0;
case SOMECASE:
//if the bitmap has a larger width than the cleint area
if (LargerWidth == true)
{
HScrollInfo.fMask = SIF_PAGE | SIF_RANGE; // not with SIF_DISABLENOSCROLL
SetScrollInfo(hWnd,SB_HORZ,&HScrollInfo,true);
InvalidateRect(hWnd,NULL,true); //?
UpdateWindow(hWnd); //?
}
//and same if it has a larger height, just with VScrollInfo

}
}


Thank you for your time, Dev578 [Edited by - dev578 on October 11, 2005 4:46:59 PM]

##### Share on other sites
The Win32 UI has two kinds of scroll bars : a standard scroll bar and a scroll bar control. The first is created with the main application window if you specify WS_HSCROLL or WS_VSCROLL as parameters when creating the window. The second(the scroll bar control) is a separate window that has a window handle of its own, unlike the standard scroll bar.
I understand you want to add the scroll bars only when loading an image that is larger than the client area of your main window : thus you should use scroll bar controls. You need to create them with CreateWindowEx and pass SBS_* styles as parameters to window style. When calling SetScrollInfo be sure to specify the scroll bar control handle, not the handle of the main window.

Hope it helps.

##### Share on other sites
If I do use a scroll bar control, I see myself running into the same problem, and going through a lot more trouble to get to the same problem. Either way, you still have to use a SCROLLINFO structure, and call SetScrollInfo() to change it. Everything about the scroll works fine as I have it now, I am just having problems with the SIF_DISABLENOSCROLL flag. It works in that at the beggining, the scroll is not there. When I try to make the scroll bar visible when the bitmap is larger than the client area of the window, it will not show up. I should just be able to use ScrollInfo.fMask = SIF_PAGE | SIF RANGE; and NOT SIF_DISABLENOSCROLL, and it "should" recreate the scroll bar, but visible. I posted all the important code dealing with the scroll bar above, I still do not see why it will not work. If I make a scroll bar control, I have to do a lot of code changing, and I think the same problem will happen. There must be a way to do what I am trying to do with a standard control bar. Anyone that could help me out would be greatly appreciated.

Thank you,

Dev578

##### Share on other sites
Another odd find. When I re-size the window, the scroll bars show up. Can anyone come up with some kind of explanation? It doesn't make sense, I still don't see why this scroll bar isn't working the way it should (described above). If anyone could assist in solving this, I would greatly appreciate it.

Thank you,

Dev578

##### Share on other sites
in your SOMECASE case, after you load the bitmap, i see this:

HScrollInfo.fMask = SIF_PAGE | SIF_RANGE; // not with SIF_DISABLENOSCROLLSetScrollInfo(hWnd,SB_HORZ,&HScrollInfo,true);

HScrollInfo.nMin = 0;HScrollInfo.nMax = 1000;HScrollInfo.nPage = 100;

When you load an image, you must reset the range.
nMin should be 0,
nMax should be (width of bitmap - width of client area).

You also never respond to the WM_SIZE message. You have to
recompute scrollers whenever a window is resized. This includes
recomputing the range, and then clamping the current position to
that range, and perhaps even disabling scrolling if you enlarge
the window far enough.

When it comes to scrolling, I always do the following to
make scrolling easily managable:

I have 5 functions to handle scrolling.

1.) InitScrollers() -> Called when a new image or project or whatever
it is that i'm loading. This function sets up the range, current position,
and then calls SetScrollInfo.

2.) FreeScrollers() -> Called when I don't need scrollers. Basically
just sets all the parameters in SetScrollInfo to zero and then disables
scroll bars.

3.) RecomputeScrollers() -> Called whenever the window is resized. When
a window is resized you must adjust your range and position (though not
always, but sometimes it needs to be clamped to the new range when you
enlarge a window). You should also check here the size of the client
window cuz u may need to disable scrolling. Then it calls SetScrollInfo
again.

4.) OffsetScrollers(int x, int y) -> Call from within WM_XSCROLL usually
for to offset nPos by x and y. If x and y go beyond nMax, you must clamp
them to (0, nMax). Then it calls SetScrollInfo again.

5.) AdjustScrollers(int x, int y) -> Sets the nPos to (x, y), then clamps
it to the ranges, and then calls SetScrollInfo again.

5 functions. Works for everything and doesn't clog up your window
procedure. Lemme know if u want a code example using it.

EDIT:
BTW, you don't need 2 SCROLLINFO objects. You can reuse one. Most of the
time they are used together and the flags and values are the same except
for nPos, nMin, and nMax. Just a little efficiency tip ;).

##### Share on other sites
I have found scroll bars to be some of the most difficult things to implement correctly, and get the behavior you want. Having said that, I believe I have gotten the behavior I want, and I have done so through a simple wrapper. If you are interested, you can download the example, step through the code, and see how I turn the scrollbars on and off, and handle all the positioning. Even though the code is simple, it is a bit to grok, as it is complicated, if that makes sense. The wrapper is available here:

http://www.codeproject.com/library/DWinLib.asp

Everything is in the sample code download. Look in the AppWindow unit, at the 'updateScrolls', 'wScrollHor', 'wScrollVer', & 'scrollPosChanged' routines. As this is wrapped, those are all the programmer has to deal with within their own code. (Other than moving the scrollbars around during the WM_SIZE or WM_WINDOWPOSCHANGING handlers).

David

##### Share on other sites
Quote:
 Original post by Anonymous PosterI have found scroll bars to be some of the most difficult things to implement correctly, and get the behavior you want.David

I agree with, David. A good example on using scroll bars can be found in Charles Petzold's Programming Windows, Fifth Edition book.

##### Share on other sites
Quote:
 Another odd find. When I re-size the window, the scroll bars show up.

This makes me think that you might need to call SetWindowPos with the flag SWP_FRAMECHANGED. Something like:

SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);

##### Share on other sites
Thank you very much yadango, that was helpful. Obviously, Rating++:) Thank you to everyone else who helped out as well.