Detect mouse click outside child window - c++

I want to destroy a child window when user click somewhere outside its window. I tried to use SetCapture() to detect mouse click. Here is the code:
HWND textbox;
//IN case WM_CREATE:
CreateWindowEx(NULL, L"BUTTON", L"button!",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 150, 40, hwnd,
(HMENU)IDC_TEXTBOX, NULL, NULL);
textbox = CreateWindowEx(
NULL, L"EDIT", NULL,
WS_CHILD | WS_VISIBLE | ES_MULTILINE | WS_BORDER,
100, 100, 300, 200, hwnd, (HMENU)ID_TEXTBOX, NULL, NULL
);
SetWindowText(textbox, L"the initial text");
//IN CASE WM_ONLBUTTONDOWN:
if (textbox != NULL) {
if (SetCapture(textbox) == NULL) {
ReleaseCapture();
DestroyWindow(textbox);
textbox = NULL;
}
}
The window did get destroyed when i clicked outside its region. HOWEVER, when i click the button it didn't get destroyed as i expected. I want the child window to get destroyed when user clicks WHEREVER outside its window. Why did my code fail? And how do i do this right?
EDIT: Here is a screenshot to make things clear. The window only have an edit window with initial text and a button. As mentioned above, the child window disappears when i click outside its window but when i click the button (which is also outside window), the edit window remains.

According to this thread, I find the EN_KILLFOCUS notification which will work for you in the Edit Control Document.

Related

WinAPI Creating a second dialogbox after clicking a button control on the first dialogbox and destroying the first

I'm trying to make a second dialogbox prompt the user after they click OK on the first dialogbox while destroying the first dialogbox in the process.
This is my first dialogbox that pops up after the user click a button on the main window itself.
void displayDialogW(HWND hWnd)
{
HWND hDlg = CreateWindowW(L"myDialogClass", L"Enter Desired Width", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 150, 300, 150, hWnd, NULL, NULL, NULL);
CreateWindowW(L"static", L"Width: ", WS_VISIBLE | WS_CHILD | WS_BORDER, 30, 20, 100, 20, hDlg, NULL, NULL, NULL);
CreateWindowW(L"edit", L"...", WS_VISIBLE | WS_CHILD | WS_BORDER, 80, 20, 180, 20, hDlg, NULL, NULL, NULL);
CreateWindowW(L"button", L"OK", WS_VISIBLE | WS_CHILD, 120, 60, 30, 30, hDlg, (HMENU)5, NULL, NULL);
TCHAR buff[1024];
GetWindowText(hDlg, buff, 1024);
desiredWidth = _wtoi(buff);
EnableWindow(hWnd, false);
}
The second dialogbox is more or less the same as the first but I'm not sure how to manipulate the button on the first dialogbox to make sure it opens the second dialogbox and destroys the first window at the same time.
I found a function called DestroyWindow but it needs a hDlg input so I can't exactly put it in my dialogprodecure command function. So, I'm not too sure how I would go about this.
The second dialog cannot have the first dialog as a parent if that's going to be destroyed right away. You could, instead, open the second dialog with the parent set to the same parent as the first one, then the first dialog can be safely destroyed.
case IDOK: // assuming hWnd is first dialog
{
createSecondDialog(GetWindow(hWnd, GW_OWNER)); // open second dialog
DestroyWindow(hWnd); // close first dialog
}
This is using GetWindow(hWnd, GW_OWNER) rather than GetParent(hWnd) since displayDialogW creates a window with WS_OVERLAPPED style, and in that case what is being passed into the CreateWindowW call must be the owner of the new window (per the docs for owned windows).
DestroyWindow:
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.
You can hide the parent window after opening the child window, like this:
case ID_BUTTON1:
{
displayDialogW(hWnd);
SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
}
Updated:
From A window can have a parent or an owner but not both,
Note that changing a window’s parent or owner is not a normal
operation.
But if you must destroy the parent window, then you can implement it according to Reinstate Monica's comment, using SetParent.

Can't change the background color of windows which are inside another window

I want to change the background color of a STATIC window, both - on load and change it on runtime. So far I have been able to change the color the following way:
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(200, 200, 20));
SetBkColor(hdcStatic, RGB(10, 10, 10));
SetBkMode(hdcStatic, TRANSPARENT);
return (INT_PTR)CreateSolidBrush(RGB(30, 30, 30));
}
Everything works fine and the background color gets changed, except for any STATIC windows, which are inside another static window:
HWND mainContainer = CreateWindowEx
(
0,
_TEXT("STATIC"),
"",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_SOLID,
10, 10, 500, 500,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWLP_HINSTANCE),
NULL
);
HWND subItem = CreateWindowEx
(
0,
_TEXT("STATIC"),
"SubItem",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_SOLID,
10, 10, 100, 100,
mainContainer,
NULL,
(HINSTANCE)GetWindowLong(mainContainer, GWLP_HINSTANCE),
NULL
);
In this case the mainContainer color gets changed, but not the background color for subItem. Any ideas why this is happening? Thank you!
The message WM_CTLCOLORSTATIC will be sent only to the parent window, but not parent's parent window.
According to About Static Controls :
The window procedure for the predefined static control window class
performs default processing for all messages that the static control
procedure does not process.
The WM_CTLCOLORSTATIC is not in the list that it process. So The predefined window procedure will passes the message to DefWindowProc for default processing.
(We really don't often put a static window inside another static window. This is not a common operation. So you should reset the parent window of subItem to hwnd.)

How can i put icon on button in c++?

I have a window and there is a button on it. I want to put a icon of question mark on that button,how can i do this??
To create button:-
HWND button = CreateWindow(TEXT("button"), NULL,
WS_VISIBLE | WS_CHILD | BS_ICON, 20, 50, 200, 25,
hWnd, NULL, NULL, NULL);
To load question mark icon:-
HICON hIcon = LoadIcon(NULL, IDI_QUESTION);
To put the icon on button:-
SendMessage(button, WM_SETICON, IMAGE_ICON, (LPARAM)hIcon);
But icon is not appearing on button.
You are using the wrong message to set the icon to the button. You need to use BM_SETIMAGE.

Child window disappears on scrolling

HWND hwndDlg=GetDesktopWindow();
HWND hImage=CreateWindow(_T("STATIC"), _T(""), SS_CENTERIMAGE | SS_REALSIZEIMAGE | SS_BITMAP | WS_CHILD | WS_VISIBLE,
550, 480, 10, 10, hwndDlg, NULL,
(HINSTANCE)GetWindowLong(hwndDlg, GWLP_HINSTANCE),
NULL);
LPWSTR imgPath = getImagePath();
HBITMAP bitmap = (HBITMAP)LoadImageW(NULL,imgPath, IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
SendMessage(hImage, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap);
With this piece of code i'm able to create a child window to the current window and make a picture appear on that window. It works as expected. But my problem is when i scroll the child window and the picture disappear. What am I doing wrong? I'm totally new with windows programming. Please help me out.
http://i.stack.imgur.com/VO0uD.png
You may see the screenschot in the above link

Window creation fails with non-NULL hMenu parameter

In addition to the main window, I'm trying to create another top level window. The problem is that when I'm setting the second window's hMenu parameter to a non-NULL value, it doesn't show up.
e.g:
This window shows up (hMenu == 0)
case IDC_BUTTON_SEND_COMMAND:
{
CreateWindowExW(NULL,
L"CommandWindow", L"Send Command",
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
100, 100, 600, 400,
NULL,
(HMENU)0,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
break;
}
This window doesn't show up (hMenu == 4)
case IDC_BUTTON_SEND_COMMAND:
{
CreateWindowExW(NULL,
L"CommandWindow", L"Send Command",
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
100, 100, 600, 400,
NULL,
(HMENU)4,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
break;
}
I'm using Windows 7.
Passing (HMENU)4 as the hMenu parameter to CreateWindowEx to create a top level window tells the system to attach a menu to it. This menu has the menu handle 4. A menu handle (HMENU) is returned from functions like CreateMenu. If the handle is not a valid HMENU window creation fails.
Your observation, that the window doesn't show up is misleading yourself into believing that the window actually exists. The window doesn't exist, and CreateWindowEx returns NULL. Checking return values is advisable, and calling GetLastError when an API call fails is usually quite helpful.