Can't show/hide buttons in the main window of my C++ Win32 app [duplicate] - c++

This question already has answers here:
Access a variable from a different switch case (from WM_CREATE to WM_CTLCOLORSTATIC in the WinApi)
(2 answers)
Closed last month.
I have created a basic button in case: WM_CREATE in the windows procedure with the following.
/*The "new_game_button" is declared as type HWND at the
start of the windows procedure function but not initialized.*/
new_game_button = CreateWindow ( "BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, NULL, NULL, NULL);
My intent is to create an instructions and "start new game" button as the first thing in my simple tictactoe app. It will immediately show as expected if I give the parameter WS_VISIBLE.
Further in the same case:WM_CREATE if I use the lines
if (!start_Game){ //global variable default is false
ShowWindow( new_game_button, SW_SHOW);
}
The button will show as expected.
Outside of those two cases I cannot get the button to show at a later stage.
Further, if I use one of those two methods to show the button I can never get it to go away using
ShowWindow ( new_game_button, SW_HIDE);
Once the button is showing, it stays for the duration of the programs execution. Doesn't matter which case. Command/Create/Paint
I have tried using
if (start_Game){
ShowWindow( new_game_button, SW_HIDE);
UpdateWindow ( new_game_button );
//UpdateWindow ( hwnd ); tried this as well
}
inside case WM_CREATE.
I have also tried the same SW_HIDE line inside case: WM_COMMAND where a new game is generated (compiles but doesn't hide the button.)
I have tried declaring the button child window outside the WM_CREATE inside the windows procedure function. Then using WM_CREATE to show the window - works -- still WM_COMMAND will not hide the window.
I have also tried creating the button window inside of case:WM_PAINT which works to show the button but not to get rid of it. I have even tried DestroyWindow which just fails. [returns 0]
In trying to understand the behaviour of the button window - I have found that I cannot get
ShowWindow( new_game_button, SW_SHOW);
to work in the case:WM_COMMAND.

You said (in a code comment in the question).
new_game_button is declared as type HWND at the start of the windows procedure function but not initialized.
Each incoming message means a new call to your window procedure. Variables which are local to a function don't retain their value between calls unless they are marked static.
When your window procedure returned from processing WM_CREATE, you lost the value of new_game_button. When you try to use it during WM_COMMAND processing later, it is uninitialized and your program causes undefined behavior by passing it to ShowWindow.

Every comment helped me solve this which I appreciate. I am too new to give reputation sadly.
case WM_CREATE:
{
new_game_button = CreateWindow ("BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, (HMENU) 1, NULL, NULL);
if (!start_Game){
ShowWindow( new_game_button, SW_SHOW);
}
}
break;
After I had an ID for the dialog I am able to use GetDlgItem function to show or hide as I please.
new_game_button = GetDlgItem (hwnd, 1);
ShowWindow( new_game_button, SW_HIDE);

Related

How to update the current state for window after showing/hiding controls?

I'm a beginner and today is my first day in learning to create Windows application.
I have two buttons.
#define BUTTON_SW 1
#define BUTTON_SW2 2
HWND Button1;
HWND Button2;
Button1 = CreateWindow("button", "Enter", WS_VISIBLE | WS_CHILD, 215, 10, 40, 25, hwnd, HMENU(BUTTON_SW), NULL, NULL);
Button2 = CreateWindow("button", "You'll be gone", WS_VISIBLE | WS_CHILD, 260, 10, 95, 25, hwnd, HMENU(BUTTON_SW2), NULL, NULL);
When Button1 is clicked, how can I hide Button2 or make it lose its WS_VISIBLE flag and reflect current situation correctly, like this?
LONG style = GetWindowLong(Button2,GWL_STYLE);
style = style | WS_VISIBLE; // style = style & ~WS_VISIBLE
SetWindowLong(Button2,GWL_STYLE,style);
This works very well. However, once WS_VISIBLE flag is assigned, button still stays invisible until the first mouseclick on it.
Vice versa, when I use style = style & ~WS_VISIBLE; once WS_VISIBLE flag is removed, button becomes passive (unclickable) but stays visible.
How to fix this? Tried many things that I've found online but couldn't fix it. Also please don't suggest me to buy a decent book, I don't have the money for now.
(P.S: ShowWindow function with SW_HIDE/SW_SHOW somehow doesn't work for me, perhaps I'm using it wrong. Can you help me on how I can hide this Button2 correctly? I'm trying the following command, but nothing happens.)
ShowWindow(GetDlgItem(Button2, 2), SW_HIDE);
#Edit: I've noticed that when I minimize the app and maximize it
again, the state of button updates. But how will it automatically
update the state?
This should work
ShowWindow(Button2, SW_HIDE);
or
ShowWindow(GetDlgItem(DialogHWND, BUTTON_SW2), SW_HIDE);
GetDlgItem needs HWND of the parent window (dialog) as first argument.
In order to a window to reflect changes you must ask the OS to do it.
Learn about RedrawWindow and the invalidated area.
Note that some actions, like resizing or restoring from minimized, automatically makes the OS to invalidate the region and redraw it.
Use:
RedrawWindow(Button2,NULL,NULL,RDW_INVALIDATE | RDW_INTERNALPAINT);

How to add a button to a running Windows GUI program

Now I want to dynamically modify the GUI of a running WINDOWS program(assume this program is written in win32 API/MFC), for example, add a button to it's specific position.
But I'm not familiar with WINDOWS GUI programming.
So I want to ask if there is any normal way to implement this feature using win32 API or MFC.
If not, do I need any hacking tips?
You can dynamically create any Windows component by utilizing the CreateWindow function when processing (for example) a WM_COMMAND message inside your WndProc callback function. Or any other message for that matter. Provided that you have a button with an ID of IDC_BUTTON you can create a new button when clicked.
case WM_COMMAND: // process commands
switch (LOWORD(wParam))
{
case IDC_BUTTON: //check for our button ID
HWND hwndButton = CreateWindow(
L"BUTTON", // predefined class name
L"OK", // button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
75, // width
24, // height
hWnd, // parent handle
(HMENU)IDC_BUTTON2, // button ID
hInst, // module instance
NULL); // lparam, pointer not needed
break;
}

Switch between edit controls using Tab?

The Window is non DialogBox based so WS_TABSTOP doesn't work. Moreover I don't want to Tab through all the controls, I just want to Tab through few Edit controls.
What I did is I superclassed the Edit control and handled the WM_KEYDOWN message, switching between edit controls, by getting next window in the line thorugh ::GetWindow(hwnd,GW_HWNDNEXT); Also I would like to switch focus back to the first Edit control when I have reached the last one.
The Code doesn't work for when I have reached the last Edit control, the ::GetWindow simply returns the next window in the line(?), which happens to be a non superclassed edit control. And there are more hidden child windows(SW_HIDE).
Maybe if I know how to know the class name of the window's HWND ?
Note: Pure Win32 api, c++ oop.
else if ( ( int ) wParam == VK_TAB )
{
HWND nextInLine;
nextInLine = ::GetWindow ( hwnd, GW_HWNDNEXT );
if ( hwnd == NULL ) nextInLine = ::GetWindow ( hwnd, GW_HWNDPREV );
::SendMessage ( nextInLine, EM_SETSEL, ( WPARAM ) 0, ( LPARAM ) -1 );
::SetFocus ( nextInLine );
return 0;
}
You get keyboard navigation for free in any window by using the IsDialogMessage API call. To consume the service a window message loop has to be modified to include a call to IsDialogMessage and only pass the message on to regular message handling if it hasn't been handled by the dialog manager already.
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsDialogMessage(hwnd, &msg)) {
/* Already handled by dialog manager */
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Don't forget to set the WS_EX_CONTROLPARENT extended window style on the parent window, so that the dialog manager recurses into child windows.
It's possible to get away with just calling IsDialogMessage, but the result isn't quite 100% dialog-like. To make an ordinary window behave like a dialog:
Specify DLGWINDOWEXTRA as the cbWndExtra field of your WNDCLASS (don't forget to add on extra space you might already be using and offset your data's indexes)
Call DefDlgProc rather than DefWindowProc
Since this makes your window a dialog, you need to use the DWLP_USER window long instead of GWLP_USERDATA, if you're using that, when calling GetWindowLongPtr or SetWindowLongPtr.
(From memory, the main thing you get from doing the above is support for WM_NEXTDLGCTL, which I've found useful to use for supporting changing focus using the Enter key, using Method I described in http://support.microsoft.com/kb/102589.)
Then in your message pump, call IsDialogMessage for each dialog-like window in your message pump.
Finally, when creating controls for your dialog-like window, set the WS_TABSTOP window style for each window you want to participate in the tabbing, and set the WS_EX_CONTROLPARENT window exstyle (aka Control Parent in the resource editor) for child windows that contain dialog controls.

(C++/win32) Hide a window so that the user cannot alt-tab or switch to it

I'm currently using ShowWindow( hwnd, SW_HIDE ), but AltTab still seems to be able to switch to it after it's hidden.
Is there a way to completely hide a window without destroying it?
EDIT: I should add that using the WS_EX_TOOLBOX style doesn't help. With enough AltTab and ShowWindow(SW_SHOW), some strange things happen.
Try this code to hide window
I have try this code and hidden window will be not appear while you pressing Alt + Tab [ I am using win-xp]
To show window press Tab + Esc
HWND hwnd_win = GetForegroundWindow();
ShowWindow(hwnd_win,SW_HIDE);
while(1)
{
Sleep(1000);
if(GetAsyncKeyState(VK_ESCAPE|VK_TAB ))
break;
}
ShowWindow(hwnd_win,SW_SHOW);

Is it necessary to destroy a tooltip?

In my application I am handling the WM_HELP message and then creating a tooltip for a control using this method:
Taken from: http://msdn.microsoft.com/en-us/library/bb760252(v=vs.85).aspx
HWND CreateToolTip(int toolID, HWND hDlg, PTSTR pszText)
{
if (!toolID || !hDlg || !pszText)
{
return FALSE;
}
// Get the window of the tool.
HWND hwndTool = GetDlgItem(hDlg, toolID);
// Create the tooltip. g_hInst is the global instance handle.
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP |TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
g_hInst, NULL);
if (!hwndTool || !hwndTip)
{
return (HWND)NULL;
}
// Associate the tooltip with the tool.
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hDlg;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hwndTool;
toolInfo.lpszText = pszText;
SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
return hwndTip;
}
The tooltip vanishes as soon as I move my mouse pointer.
My questions are:
Is tooltip is destroyed or is it just hidden ?
If it is hidden then how to destroy it and when?
Thanks.
It's been a while since I've done any WinAPI programming but if my memory serves me...
The call to CreateWindowEx passes the hDlg as the hWndParent parameter meaning the dialog window is now the parent of the tooltip.
From the MSDN documentation on the DestroyWindow function it says:
If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.
So you can assume your tooltip window will be destroyed eventually. Be careful if you are calling CreateToolTip in response to every WM_HELP message as you will end up with a number of tooltip windows hanging around in memory until your dialog is closed and DestroyWindow is finally called.
As vz0 pointed out you could create the tooltip once, hang on to the window handle, then show the tooltip in response to the help message rather than creating it again.
In your comment to vz0's answer you said:
there are multiple ways in which a tooltip goes awya. example: mouse move, timeout etc.
All of those only result in the window being hidden so the handle to the tooltip is still valid and can be redisplayed using ShowWindow.
For every CreateWindowEx call you need a matching DestroyWindow call.
As an alternative, instead of creating and destroying the window every time you can use the ShowWindow call with SW_SHOW and SW_HIDE to show and hide the popup.
In my experience, I had to DestroyWindow() on the tooltip so an HFONT (font GDI resource) was properly released. There was a parent-child bond of the two windows at one time - but my system changes this at run-time and could be to blame. Probably no harm in doing it if your system generalizes it.