Scrollbar moves back after WM_VSCROLL - c++

I have a window with its own H and V scrolling. I'm handling the event like this:
case WM_VSCROLL:
SetScrollPos(hWnd, SB_VERT, (int)HIWORD(wParam), TRUE);
break;
all I want is for the position of the scroll bar to stay once I release my mouse but what it's doing is just going back to the top after. What am I doing wrong?
Thanks

The wParam parameter of the WM_VSCROLL message is either SB_TOP, SB_BOTTOM, SB_PAGEUP, SB_PAGEDOWN, SB_LINEUP, SB_LINEDOWN, SB_THUMBPOSITION, or SB_THUMBTRACK, where the names ought to explain themselves.
SB_TOP and SB_BOTTOM means that the scrolling window is to go to the top or bottom, respectively. These messages can be sent by right-clicking a vertical scroll bar and selecting "Top" and "Bottom". (Look in Windows Notepad, Win XP+, for instance.)
SB_PAGEUP and SB_PAGEDOWN means a page (screen) up or down. These are sent if you click somwhere on the scrollbar beside on the thumb or the up or down arrows, or if you use the scrollbar's right-click menu.
SB_LINEUP and SB_LINEDOWN are sent when the user clicks the up and down buttons on the scrollbar, or selects the appropriate right-click menu commands.
SB_THUMBTRACK is sent continuously when the user scrolls by dragging the thumb of the scrollbar.
SB_THUMBPOSITION is sent when the user has released the thumb.
See the MSDN article WM_VSCROLL for more information.
So, when you receive a WM_VSCROLL message, you first need to do the scrolling itself. If, for instance, you are writing a text editor, then you need to redraw the text, but with a different row at the top of the window. Then you need to update the scrollbar to its new position, preferably by means of SetScrollInfo, but you can also use the old SetScrollPos function.

In the case section, the system is processing a WM_VSCROLL message. It will run the default window procedure after your SetScrollPos. In the default window procedure, the system itself will set the scroll bar's thumb position. So, although SetScrollPos takes effects, the system change the thumb position after that anyway. I think you should do your SetScrollPos after calling the default window procedure, i.e., maybe after returning this funciton, and then you can SetScrollPos.

Related

Allow clicks to pass through window(hit-test transparency) on a non-transparent window

I have a layered window that I want all clicks to pass through no matter where the mouse is located. Some parts of it are color keyed, and others are not. Clicks pass through the window whenever the mouse is on a transparent part but whenever the mouse is on a non-transparent part, the window captures the click. An easy solution would be just to add the WS_EX_TRANSPARENT flag to the window but I DO NOT want to do that. I tried returning -1 on WM_NCHITTEST in WndProc since WM_NCHITTEST is called every time the mouse enters a non-transparent zone but that didn't work and clicks still didn't pass through non-color keyed areas of the window.
Thanks in advance

Capture mouse clicks on text boxes in a Win32 game

Using C++, I am making a Tic-Tac-Toe game using the Win32 API. To mark a square (X or O) I want the player to click the square which then changes to an X or O.
What I am doing right now is having a button click event which turns a static text box to X or O. However, when I place the button on top of the text box and make it not visible, I can't click it.
What I really need is an invisible button that still functions. So it's not set WS_VISIBLE, but you can still click it.
Is this possible or is there another way around this problem?
I can see a couple of reasonable possibilities here.
The first and most obvious would be to skip using a button at all, and just have the underlying window process the WM_LBUTTONDOWN message, and set the "X" or "O" in the correct location. For this, you don't even need static controls -- you can just detect the mouse clicks directly on the parent window, and draw your "X" or "O" in the corresponding square.
Another possibility would be a button that's marked as "visible", but happens to be transparent. IMO, this is a fairly poor choice though. To do it, you'd need to either create a transparent button control on your own, or subclass a button control to disable its drawing.
At least IMO, the obvious route would be to skip using the static control at all. Instead, just use the buttons directly -- a button normally has a caption. Start with that caption as an empty string. When the button is clicked, change its caption to "X" or "O" as appropriate. It should probably also disable itself in response to the button click, so clicking it again won't have any further effect.
There's no way to make an invisible button that still functions. Imagine all of the ways that could be abused if it were possible! Not to mention how confusing to have invisible, yet functional, UI.
What Mark Ransom posted is exactly right: you need to get your existing control to respond to mouse click events, just like a button does. Then you can do whatever you want in response to clicks. You don't need a button just to be clickable.
You say that you have a "static text box", but I'm not really sure what that is. There are text boxes (which are not static), and then there are static controls (which can display text). I'm going to assume that you have the latter.
In that case, you don't need to handle the WM_LBUTTONDOWN and WM_LBUTTONUP messages directly, which would require that you subclass the control. Although that's probably the best approach design-wise (separation of responsibilities and all that), it's also a lot more trouble.
Instead, you can handle the click events from the parent's window procedure by setting the SS_NOTIFY style for your static control (you can do this either in the Dialog Editor or in your call to CreateWindow, depending on how you create the control). This causes the control to notify its parent in four cases: when it is clicked (STN_CLICKED), when it is double-clicked (STN_DBLCLK), when it is enabled (STN_ENABLE), and when it is disabled (STN_DISABLE).
So at the parent, you need to process WM_COMMAND messages. The message you're looking for will have a HIWORD(wParam) of STN_CLICKED (indicating that a static control with the SS_NOTIFY style has been clicked), a LOWORD(wParam) corresponding to your static control's ID (set either in the Dialog Editor or specified as the hMenu parameter in your call to CreateWindow), and an lParam containing a handle to your static control.
If you use SW_HIDE, it doesn't just make the window invisible but makes it behave like that too. What you really wanted is probably just make the button transparent. I never did that, you may find this or this helpful.
You may just scrap the textbox just use the button, i mean a button-looking checkbox with ownerdraw or bitmaps. Or scrapping the button and handle the mouse events Like Mark suggests.

Help with this issue

Here is the problem:
The way the GUI system I'm using works is as follows:
A widget can listen to mouse events. The listeners can consume an event they are listening to and as a result, the widget they were listening to will not receive the event, even if it was intended for them, only the listener will have received it.
The problem comes in here:
A scrollpane has a ListBox inside. The listbox can be scrolled. The Scrollpane can also be scrolled. What happens right now is when I mousewheel and the widget under the mouse is the listbox, both the listbox and the scrollpane move. The only solution I see is that the scrollpane consumes all mousewheel events, but then there is no way for the ListBox to ever be scrolled.
The behavior I desire is for the ListBox to scroll when it has focus, but if I did this, it would not work because for example if a radio button inside the scrollpane is focused, I still want the scrollpane to scroll, it is only for widgets with scrollbars such as textbox and listbox where this is not desired.
Thanks
Also, the gui system I'm using is my own which I'm developing.
The usual way to deal with this is that the ListBox only consumes the event if it actually scrolls. If you place the mouse in the listbox and use the scrollwheel the listbox scrolls until it reaches its scroll limit. After that further moves of the wheel cause the scrollpane to scroll.
Obviously there are variants on that - the important thing is to decide what you actually want to happen.
You also need another way of scrolling the scrollpane, so that if the user explicitly wants to scroll it they can, without having to scroll to the end of the ListBox. Scrollbars on the ScrollPane would be one way. You should also make sure there is a way of scrolling the ListBox without using the mouse wheel.

How to get the window position and update to other windows?

I have 2 dialog boxes in which I will display 1 dialogbox at a time..If I click NEXT in the first dialog box,I will hide the first dialog box and display the second dialog and vice versa...Now say If I move the dialog box after clicking NEXT in the first dialog..and when I click BACK(in the second dialog) ...it goes back to its previous position(to diaplay the first dialog box)..so I have decided to get the current window's position and update to the other window position so that it doesnt move even If I click next/back..I am not sure how to get the windows position and update to other..please help me if you guys know about this..
You can create an OnMove handler for WM_MOVE messages to detect when your window moves. In the handler, you can either move the other window directly with MoveWindow, or you can send a private message to the window (something in the WM_APP range would be best) and let it move itself. Use GetWindowRect to get the width and height to pass to MoveWindow.

Constraining window position to desktop working area

I want to allow a user to drag my Win32 window around only inside the working area of the desktop. In other words, they shouldn't be able to have any part of the window extend outside the monitor(s) nor should the window overlap the taskbar.
I'd like to do it in a way that does cause any stuttering. Handling WM_MOVE messages and calling MoveWindow() to reposition the window if it goes off works, but I don't like the flickering effect that's caused by MoveWindow().
I also tried handling WM_MOVING which prevents the need to call MoveWindow() by altering the destination rectangle before the move actually happens. This resolves the flickering problem, but another issue I run into is that the cursor some times gets aways from the window when a drag occurs allowing the user to drag the window around while the cursor is not even inside the window.
How do I constrain my window without running into these issues?
Windows are, ultimately, positioned via the SetWindowPos API.
SetWindowPos starts by validating its parameters by sending the window being sized or moved a WM_WINDOWPOSCHANGING message, and then a WM_WINDOWPOSCHANGED message notifying the window proc of the changed size and/or position.
DefWindowProc handling of these messages is to, in turn, send WM_GETMINMAXINFO and then WM_SIZE or WM_MOVE messages.
Anyway, handle WM_WINDOWPOSCHANGING to filter both user, and code, based attempts to position a window out of bounds.
Keep in mind that users with multi-monitor setups may have a desktop that extends into negative x- and y-coordinates, or that is not rectangular. Also, some users use alternative window managers such as LiteStep, which implement virtual desktops by moving them off-screen; if you try to fight this, your application will break for these users.
You can do this by handling the WM_MOVING message and changing the RECT pointed to by the lParam.
lParam: Pointer to a RECT structure with the current position of the window, in screen coordinates. To change the position of the drag rectangle, an application must change the members of this structure.
you may also want to handle WM_ENTERSIZEMOVE to know when the window is beginning to move, and WM_EXITSIZEMOVE
WM_GETMINMAXINFO is what you seem to be looking for.