• Advertisement
Sign in to follow this  

scroll bar woes (windows programming)

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to add scroll bars to my program by using the WS_VSCROLL and WS_HSCROLL on some of my windows. However, it seems that whenever I hold the mouse on the "thumb slider" or hold down one of the arrow buttons on the scroll bar, the scroll bar hijacks my program and doesn't allow anything else to happen. Animations stop (except the sliding animation of the scrollbar itself), input is ignored, and window messages don't get processed...in other words my main loop isn't looping. How do I get scroll bars to be nice, allowing input while they are active? I'm using visual c++ 6.0. Thanks in advance for any help.

Share this post


Link to post
Share on other sites
Advertisement
Post your code in WM_XSCROLL. Windows doesn't hijack
the message loop (it doesn't enter a scroll loop) for
scroll bars as it does with menus, so my guess is
you're doing something wrong in WM_XSCROLL. Can't
really tell without seeing some code. My WM_XSCROLL
code is pretty much always consistent... 1.) set
my scroll variables, 2.) adjust (clamp) scroll
variables, 3.) repaint window. 4.) return.

Share this post


Link to post
Share on other sites
Sure, here is my WM_XSCROLL handler


case WM_HSCROLL:
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_HORZ, &si);

if(LOWORD(wParam)==SB_LINERIGHT) si.nPos++;
if(LOWORD(wParam)==SB_LINELEFT) si.nPos--;
if(LOWORD(wParam)==SB_THUMBPOSITION) si.nPos = HIWORD(wParam);
if(LOWORD(wParam)==SB_THUMBTRACK) si.nPos = HIWORD(wParam);

SetScrollInfo(hwnd, SB_HORZ, &si, true);

break;
}
case WM_VSCROLL:
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_VERT, &si);

if(LOWORD(wParam)==SB_LINEDOWN) si.nPos++;
if(LOWORD(wParam)==SB_LINEUP) si.nPos--;
if(LOWORD(wParam)==SB_THUMBPOSITION) si.nPos = HIWORD(wParam);
if(LOWORD(wParam)==SB_THUMBTRACK) si.nPos = HIWORD(wParam);

SetScrollInfo(hwnd, SB_VERT, &si, true);

break;
}



I'm not sure I should have to manually "SetScrollInfo" the new values, but the scroll bars don't move otherwise.

Share this post


Link to post
Share on other sites
Ahh, it turns out the scroll bars are not the real culprit. The same thing happens when I click on the resize-border, or the bar at the top of the window.

The only unusual thing I can think of is that I have a parent window with two child windows that all use the same WNDCLASS, and the same message handler. Could that be the cause of my problems?

Share this post


Link to post
Share on other sites
can you post your window procedure? in general you usually
do create different window classes for parent/children,
but it's not a bad thing if the windows do the same things,
but just have different window styles. but yes, if your
window proc has static data, with multiple windows accessing
it, you can run into trouble (you can use the window extra
bytes from the WNDCLASS struct instead to store data unique
to each window).

Share this post


Link to post
Share on other sites
I've actually already posted 90% of my WNDPROC :)

But maybe I'm doing something terribly obvious causing this.


LRESULT CALLBACK myd3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_HSCROLL:
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_HORZ, &si);

if(LOWORD(wParam)==SB_LINERIGHT) si.nPos++;
if(LOWORD(wParam)==SB_LINELEFT) si.nPos--;
if(LOWORD(wParam)==SB_THUMBPOSITION) si.nPos = HIWORD(wParam);
if(LOWORD(wParam)==SB_THUMBTRACK) si.nPos = HIWORD(wParam);

SetScrollInfo(hwnd, SB_HORZ, &si, true);

break;
}
case WM_VSCROLL:
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_VERT, &si);

if(LOWORD(wParam)==SB_LINEDOWN) si.nPos++;
if(LOWORD(wParam)==SB_LINEUP) si.nPos--;
if(LOWORD(wParam)==SB_THUMBPOSITION) si.nPos = HIWORD(wParam);
if(LOWORD(wParam)==SB_THUMBTRACK) si.nPos = HIWORD(wParam);

SetScrollInfo(hwnd, SB_VERT, &si, true);

break;
}

}
return(DefWindowProc(hwnd, msg, wParam, lParam));
}




My main loop might be useful as well.

while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// else
// {
float currTime = (float)timeGetTime();
float timeDelta = (currTime - lastTime) * 0.001f;

ptr_display(timeDelta);

lastTime = currTime;
// }
}
return(msg.wParam);



The program behaves the same way whether I have the else commented out or not.

Share this post


Link to post
Share on other sites
Having done a little more testing, I am now even more thoroughly confused. I set it to display one message box every time it handles a WM_VSCROLL message, and a different message box every time it iterates through the main loop.

And, using the thumb-bar or holding the mouse down on one of the scroll bar arrows, I handle more vertical scroll bar messages than I do iterations through the main loop.

I am using if(peekmessage()), so how can I possibly handle more that one message per loop iteration??

Share this post


Link to post
Share on other sites
I doubt it solves your problem but in general when you handle a message your windowprov should return 0 and not DefWindowProc.

Share this post


Link to post
Share on other sites
Thanks, I changed the breaks to return(0)'s, but I'm still having the same problem.

Share this post


Link to post
Share on other sites
Well, the WM_XSCROLL messages never even appear in my main loop. The scroll bars must be off doing their own thing that I can't do anything about.

If someone knows how to fix this "modal" (not sure that's the right word) behavior of scroll bars I'd be grateful...but for now I'll just use createwindow to get my scroll bars.


edit: Forget it, windows created with the "scroll bar" class do exactly the same thing. I get ripped out of my main loop whenever a window owned by the same process is being moved, activated, selected, etc.

Perhaps it is time for me to look into multithreading.

[Edited by - bjle on March 4, 2005 4:17:10 PM]

Share this post


Link to post
Share on other sites
hmm strange. if you post everything (at least a template
that reproduces the behavior), i'll take a look at it
tonight b4 i hit the sack. scroll bars should never go
modal.

looking at your code, there is one thing i noticed...
that you are not using GetScrollInfo and SetScrollInfo
properly (unless you set the ranges somewhere else).


SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;

// ok here you are getting the current scroll bar
// position, but nowhere in your code have i seen
// you call SetScrollInfo to set the ranges yet.
// more than likely, si.nPos is random junk.
GetScrollInfo(hwnd, SB_HORZ, &si);

// more than likely you are adjusting random
// junk here write out some text statements
// to a text file or the window caption to see
// what these values are
if(LOWORD(wParam)==SB_LINERIGHT) si.nPos++;
if(LOWORD(wParam)==SB_LINELEFT) si.nPos--;
if(LOWORD(wParam)==SB_THUMBPOSITION) si.nPos = HIWORD(wParam);
if(LOWORD(wParam)==SB_THUMBTRACK) si.nPos = HIWORD(wParam);

// what about the ranges? where do you set them?
SetScrollInfo(hwnd, SB_HORZ, &si, true);


Typically, what I do to handle scrolling, is I divide it
into four or five functions. They handle everything and
anything you can possibly want to do with scroll bars:

InitScrollers() - Called to initialize scrolling parameters immediately after a project has been is created or opened. Here I set the ranges and the initial positions.

FreeScrollers() - Called after a project is closed to zero out scrolling information and disable scrollers.

RecomputeScrollers() - Called to recompute scrolling parameters when the window is resized. The difference between this function and InitScrollers() is that InitScrollers() sets the initial scroller positions to (0,0), while RecomputeScrollers() tries to keep them the same (sometimes they have to be clamped when you extend the window beyond scrollable ranges).

AdjustScrollers(x, y) - Positions the scrollers at (x, y).

OffsetScrollers(x, y) - Positions the scrollers at (vscroll_origin + y, hscroll_origin + x).

Here is a sample from my mosaic program:


void CMosaicObject::InitScrollers(void)
{
// must have valid project
if(!IsProjectValid()) return;

// enable/disable scroll bars
long full_w = (long)(tile_w*tile_c);
if(full_w > bitmap_dx) client->EnableScrollBar(SB_HORZ, ESB_ENABLE_BOTH);
else client->EnableScrollBar(SB_HORZ, ESB_DISABLE_BOTH);

long full_h = (long)(tile_h*tile_r);
if(full_h > bitmap_dy) client->EnableScrollBar(SB_VERT, ESB_ENABLE_BOTH);
else client->EnableScrollBar(SB_VERT, ESB_DISABLE_BOTH);

// set origins to zero
row_origin = 0;
col_origin = 0;

// set scrolling extremes
row_origin_min = 0;
col_origin_min = 0;
row_origin_max = (long)(tile_r - bitmap_dy/tile_h);
col_origin_max = (long)(tile_c - bitmap_dx/tile_w);

// adjust scrolling extremes (if necessary)
if(row_origin_max < row_origin_min) row_origin_max = row_origin_min;
if(col_origin_max < col_origin_min) col_origin_max = col_origin_min;

// adjust scroll origin (if necessary)
clamp(row_origin, row_origin_min, row_origin_max);
clamp(col_origin, col_origin_min, col_origin_max);

// set scroll bar parameters
SCROLLINFO scrollinfo;
scrollinfo.cbSize = sizeof(SCROLLINFO);
scrollinfo.fMask = SIF_RANGE | SIF_POS;
scrollinfo.nMin = col_origin_min;
scrollinfo.nMax = col_origin_max;
scrollinfo.nPage = 0;
scrollinfo.nPos = col_origin;
scrollinfo.nTrackPos = 0;
client->SetScrollInfo(SB_HORZ, &scrollinfo, TRUE);

scrollinfo.cbSize = sizeof(SCROLLINFO);
scrollinfo.fMask = SIF_RANGE | SIF_POS;
scrollinfo.nMin = row_origin_min;
scrollinfo.nMax = row_origin_max;
scrollinfo.nPage = 0;
scrollinfo.nPos = row_origin;
scrollinfo.nTrackPos = 0;
client->SetScrollInfo(SB_VERT, &scrollinfo, TRUE);

// repaint window
Refresh();
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement