I have created a checkbox in WinAPI using the following code:
HWND checkbox = CreateWindowEx(NULL, "BUTTON", "Click Me!", WS_CHILD | WS_VISIBLE | BS_CHECKBOX, 10, 10, 60, 20, hWnd, NULL, hInstance, NULL);
I expected the checkbox to change its state automatically when clicked, however it did not!
I did not find any example on MSDN, so how can I make the checkbox change its state when clicked? should I handle the WM_COMMAND message and see what state it is in, and then change its state to the opposite one?
Use the BS_AUTOCHECKBOX style instead of BS_CHECKBOX.
Button Styles
BS_AUTOCHECKBOX
Creates a button that is the same as a check box, except that the check state automatically toggles between checked and cleared each time the user selects the check box.
Button States
Elements of a Button State
A button's state can be characterized by its focus state, push state, and check state.
...
Check State
...
The system automatically changes the check state of an automatic button, but the application must change the check state of a non-automatic button.
Changes to a Button State
When the user selects a button, it is generally necessary to change one or more of the button's state elements. The system automatically changes ... the check state for all automatic buttons. The application must make all other state changes, taking into account the button's type, style, and current state.
Related
with following code:
XGrabPointer(d, root, False, ButtonPressMask
, GrabModeAsync, GrabModeAsync, None,
None, CurrentTime);
I just specify with button press event, but when running other applications can't get any other mouse event such as mouse move.
Is it what this function designed to be? or with something I made wrong understanding. like parameter owner_events, I can't understand well.
If owner_events is False, all generated pointer events are reported with respect to grab_window and are reported only if selected by event_mask. If owner_events is True and if a generated pointer event would normally be reported to this client, it is reported as usual. Otherwise, the event is reported with respect to the grab_window and is reported only if selected by event_mask. For either value of owner_events, unreported events are discarded.
with explaination of owner_event, it looks like I need to register two event type: ButtonPressMask|PointerMotionMask and owner_events True? but that doesn't work either.
The key is in the last sentence of the description you posted:
For either value of owner_events, unreported events are discarded.
I.e. it doesn't matter if owner_events is True or False, events that are not handled are discarded. The subtelty of owner_events is to which window the events are delivered: if owner_events == False all pointer events matching the mask are sent to the grabbing window, even if the event is in other windows that belong to you application (Client in X parlance); coordinates are relative to the grabbing window too. If owner_events == True events are reported to any window of your application, but not to other applications.
XGrabPointer really grabs all pointer events, and this is very strong. It is normally only used for transient (temporary) windows like popups, expanding dropdown windows, etc. The reason is to keep track of clicks outside of the window so you can close the transient. I've used in a color selector popup: when the users clicks on the "choose color" button a popup appears, I do a XGrabPointer (..False..), so I get all click events. If a user clicks outside of my popup window I close the window as if the user did not make a selection. Without XGrabPointer I would not know this happened and the popup would remain open until the user clicked in it. The XGrabPointer is immediately removed when the popup closes.
I did a SetFocus to a button in a dialog. The button gets the dashed outline. When the user presses the return key, the dialog get a IDOK message rather than a message from the button were I set the focus. The same thing happens under other circumstances.
Why is this happening? And how can I cause the return to act as a button press?
Plain c++ windows app, no MFC, no NET.
Feature, not a bug. The [Enter] key operates the button that's marked as the default button for a dialog. Either with the DEFPUSHBUTTON in the .rc file or the BS_DEFPUSHBUTTON style flag. Which is typically the "OK" button so getting IDOK back is expected. The [Escape] key is special that way too, typically the [Cancel] button. This is bound to ring a bell if you think back on how you used dialogs before.
You click a button that has the focus by pressing the space bar instead.
In another SO question I found KB article that might help you:
If a dialog box or one of its controls currently has the input focus,
then pressing the ENTER key causes Windows to send a WM_COMMAND
message with the idItem (wParam) parameter set to the ID of the
default command button. If the dialog box does not have a default
command button, then the idItem parameter is set to IDOK by default.
When an application receives the WM_COMMAND message with idItem set to
the ID of the default command button, the focus remains with the
control that had the focus before the ENTER key was pressed. Calling
GetFocus() at this point returns the handle of the control that had
the focus before the ENTER key was pressed. The application can check
this control handle and determine whether it belongs to any of the
edit controls in the dialog box. If it does, then the user was
entering data into one of the edit controls and after doing so,
pressed ENTER. At this point, the application can send the
WM_NEXTDLGCTL message to the dialog box to move the focus to the next
control.
According to MSDN,
Dialog Box Keyboard Interface
The system provides a special keyboard interface for dialog boxes that carries out special processing for several keys. The interface generates messages that correspond to certain buttons in the dialog box or changes the input focus from one control to another. Following are the keys used in this interface and their respective actions.
...
ENTER: Sends a WM_COMMAND message to the dialog box procedure. The wParam parameter is set to IDOK or control identifier of the default push button.
Since the system intercepts and processes ENTER key pressed directly through the dialog, you'll need to handle it in your dialog box procedure by calling GetFocus() to first see which control has the focus, and perform the appropriate action for that particular control.
I have a property sheet with several pages. Most of the pages have one or more edit controls.
Most controls are initialized not from the page dialogs but from the dialog that created the property sheet; some however are initialized in the page dialogs and they behave the same.
Everything starts out fine. One can move between the pages. None of the controls have the input focus.
If one clicks on one of the edit controls in a property sheet page establishing input focus one can modify the control. Again all seems in order.
If one then moves to a different property page, the first edit control in that page gets the input focus AND all the text in that control gets selected! This behavior applies to all the pages except one having an edit control with read only style. After that one can move back to other pages and the initial nothing selected no input focus behavior is restored.
All of the pages handle the PSN_QUERYINITIALFOCUS notification and return zero through the SetWindowLong mechanism.
Is this expected behavior?
And why isn't some control given focus initially?
My primary interest here is to somehow kill the selection. I have tried killing the selection with EM_SETSEL in the PSN_SETACTIVE notification to no avail.
The MSDN says the following under PSN_QUERYINITIALFOCUS "Otherwise, return zero and focus will go to the default control." How do I go about setting a control as default?
I find the the actions described above bizarre! I would still like to know
if they are normal.
why no control receives the focus initially.
I was able to kill the selection by adding code to the property sheet pages to handle the WM_COMMAND/EN_SETFOCUS message for any edit controls. I do not know if other controls
send EN_SETFOCUS messages.
case EN_SETFOCUS:
{
char cn[16];
HWND H = (HWND) lParam;
GetClassName (H, cn, 15);
if (strcmp (cn,"Edit") == 0)
{
SendMessage (H, EM_SETSEL, -1, 0);
}
return true;
}
I presume it would be possible to save any selection in an EN_KILLFOCUS handler and restore it
in the EN_SETFOCUS handler but doing so for an unknown number of controls would be tedious.
I'm working on a Windows project with a simple dialog created with CreateWindowEx() it contains multiple panes loaded with CreateDialog() to load the layout from a resource file. On the child panes there are a number of controls including text boxes and buttons which I would like to use TAB to navigate around but all I get is the Windows 'bing' telling me that the key does not do anything. My message loop looks like this:
while( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
{
if( !IsDialogMessage(0, &msg) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
And each control window has WS_TABSTOP set in the style as well as the owner pane having WS_EX_CONTROLPARENT set.
Is there anything else I need to do to make the tab key work?
Thanks,
J
Try this:
http://support.microsoft.com/kb/71450 (How To Use One IsDialogMessage() Call for Many Modeless Dialogs)
You panes are modeless dialogs, and IsDialogMessage is responsible for handling Tab keys. I hope that this article exactly matches your case.
The WS_TABSTOP Style
The WS_TABSTOP style specifies the controls to which the user can move by pressing the TAB key or SHIFT+TAB keys.
When the user presses TAB or SHIFT+TAB, the system first determines whether these keys are processed by the control that currently has the input focus. It sends the control a WM_GETDLGCODE message, and if the control returns DLGC_WANTTAB, the system passes the keys to the control. Otherwise, the system uses the GetNextDlgTabItem function to locate the next control that is visible, not disabled, and that has the WS_TABSTOP style. The search starts with the control currently having the input focus and proceeds in the order in which the controls were createdthat is, the order in which they are defined in the dialog box template. When the system locates a control having the required characteristics, the system moves the input focus to it.
If the search for the next control with the WS_TABSTOP style encounters a window with the WS_EX_CONTROLPARENT style, the system recursively searches the window's children.
An application can also use GetNextDlgTabItem to locate controls having the WS_TABSTOP style. The function retrieves the window handle of the next or previous control having the WS_TABSTOP style without moving the input focus.
Source: MSDN.
if( !IsDialogMessage(0, &msg) )
The first argument should not be NULL, it must be the handle of a dialog. Painful here of course.
What notification code is sent with the wm_command message to the dialog box procedure when a check box changes state?
And more importantly, where would I look in the msdn to find the notification codes for various controls?
Note that Check boxes and Radio buttons are Buttons. So they send click and double click messages, BN_CLICKED and BN_DOUBLECLICKED.
If you use MFC, then you can examine the check state with CButton::GetCheck method.
Otherwise you send the BM_GETCHECK message to the control: SendMessage(button_handle, BM_GETCHECK, 0, 0);
SendMessage can return
BST_CHECKED Button is checked.
BST_INDETERMINATE Button is grayed, indicating an indeterminate state
(applies only if the button has the BS_3STATE or BS_AUTO3STATE style).
BST_UNCHECKED Button is cleared
If the button has a style other than those listed, the return value is zero.
If you use the Visual Studio, the easiest way to get a list of events/messages a control can send is to go to Resource/Design view, right click a control and select Events.
For a list of common controls see: Control Library
(in the page you'll see a popup menu with the controls if you hover the cursor on the Control Library link)
It's BN_CLICKED. The bottom of the page links to the button messages.