Capture mouse clicks on text boxes in a Win32 game - c++

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.

Related

What Function can I use to get the handle of a button?

the situation is as follows:
I have the handle for a window (which i got with the function FindWindowEx() ) and that window has 3 buttons. I would like to know how I can get the handle for 1 of the 3 buttons. I mean I know ppl can use spy++, but I am sure there have to be functions that can do it for me, so my questions are:
Question::
What function or functions can I use to get the handle of a button of a window (already knowing the handle for the window)?
Question2::
How do I get the Button's ID???
You can loop through children of that window with EnumChildWindow.
It lets you define a callback function to be called for every child of the window.
In the callback, you can check if the current child is the button you need.
For example, if you dinamically want to press an OK button, you can check if the window text equals OK. You can get the window text with GetWindowText.
If you know the position in the parent window you can use ChildWindowFromPoint.
For this to work you will probably have to check the windows status first (maximazed or current width-height) to be sure the button is right where you want.
An easy way may also be getting his position relative to another child of the window that's easier to retrieve. For example, if the button is always to the right of a text-box control, you can get coordinates of the text-box and use ChildWindowFromPoint passing those coordinates with something added in the x direction.

MFC Tab control without tabs?

I'm wanting to make something like a tab control, but without visible tabs at the top.
I would prefer to have the tabs selected from a list or tree at the left hand side of the page, something like this...
Selecting the list/tree item at the left changes everything on the right-hand side of the dialog.
I know I could do this by individually showing/hiding all the fields on the RHS, depending on the selected view, but this is unmanageable to design, when there are at least 10 different designs. C++ doesn't let me design groups and make them visible/invisible in one go. I would prefer to design them as totally separate dialog resources, and then bring them in, like a tab control.
I believe Windows Forms has a ContentControl, which is like a tab control without the tabs, which sounds perfect, but MFC doesn't seem to have this.
Is there a way to do this nicely? Or maybe even a 3rd party control to handle it?
In MFC you would do this by making a child modeless dialog for each group. For each dialog turn off the titlebar style and border style and it will blend in to the parent window instead of looking like a dialog. Create all the dialogs, then use ShowWindow to show/hide one at a time.
Minor detail: Put an invisible control (like a group box) on the parent window to serve as a landmark. When you create each dialog use MoveWindow to position and size it on the landmark.
Use window style WS_EX_CONTROLPARENT in the parent window to help with tab key navigation from parent to child.
Yes you can using DIALOG resources. Set the DIALOG Style to Child, Border to None, Title Bar to False. You can then add implementation classes/files for each DIALOG. The dialogs are then inserted/removed to and fro the parent as a child components by setting the containing window as the dialog's parent (i.e., SetParent)

can't change mfc controls order

I have a dialog box with a list box,slider and a button.
I tried to change the background color but I couldn't managed to change that, so i thought that if I add a "picture control" as a bitmap and put it in the background i will succed, but now the problem is that the "picture control" is on top of all the controls.
I tried to change the the tab control with Ctrl+d but it didn't change anything.
I also tried to use SetWindowPos to top or buttom but also it didn't change anything.
I noticed that if I click in the location of the button it's brought to the front as I want.
Is there any way to "click" all the controls at the begining? do i miss something in order to bring the control to the top?
If you need to change the background colour of the dialog box, you need to handle the WM_CTLCOLORDLG message and return the handle to a brush (if the brush is not a stock object, make sure you delete the brush after the dialog box is closed) -- or, you can process the WM_ERASEBKGND message and erase the background yourself.
I tried to change the the tab control with Ctrl+D but it didn't change anything. I also tried to use SetWindowPos to top or buttom but also it didn't change anything.
Ctrl+D does get you in reordering mode, however there is a more reliable way of checking. The dialog template is in text form in .RC file, where you can review the order of control with text editor and sort lines manually the way you wish. This will be the order of control creation and tab order as well. Sometimes it's even easier to reorder controls this way.
More to that, when your application is running, Spy++ SDK tool can enumerate windows and again it will give you window order for checking.
SetWindowPos with proper arguments changes Z-order of controls on runtime as well.

Best way to deal with child to parent mouse and keyboard events in a gui?

For my Gui I want to use the following system:
The way it works is that, if the widget under the mouse does not consume a mouse or kb event, it is passed to that widget's parent until it is consumed or the desktop is reached.
Just one thing puzzles me about it. Does that mean if a Button, for whatever reason has a Label as one of its children. If I click the label, would that not mean that my button, which is under the label would click (since a label does not consume the mouse), which is undesired in this case. Does that mean I'd have to do if(mouseEvent.source == this){do button stuff} ?
Thanks
If the label is a child widget, then yes, the label will attempt to eat the event, fail (as usually the label doesn't have a handler method) and thus pass the event back up to the button.
Chances are the easiest way to do this is to derive a subclass of the Label class, and override the handle function (assuming this is possible in your toolkit - which it should be in any decent toolkit). You can then use your handle function to capture mouse clicks, and pass any other event back up to the button.
Comparing pointers is probably a bad idea and is slightly dependent on the way the toolkit is implemented - for instance, it might deem the source as the button (because that's what it expects), not the label.
Though I find it highly strange that a Label is a widget in itself.....
It looks like you need a special kind of "Label" which consumes mouse events. You should be able to create a customized widget (derived from Label) that consumes mouse events for this specific case.
If that Label widget is from a third party that cannot be derived/subclassed, you should wrap the Label in another widget: A simple widget that consumes mouse events and has only one child, the original Label.

Scrollbar moves back after WM_VSCROLL

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.