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

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.)

Related

Detect mouse click outside child window

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.

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.

Textbox hide behind animation of gif

I'm make window in c++ with supporting winapi(not MFC), and I made gif animation on window with gdi++, and I create TextBox, it showing, but some part is behind gif. Image in this link : 1
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
hMWDC = GetDC(hwnd);
pGphcs = new Graphics(hMWDC);
WCHAR path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
PathRemoveFileSpecW(path);
PathAppendW(path, L"gifs\\test.gif");
pImg = new Image(path);
if (pImg) {
nFrmCnt = pImg->GetFrameCount(&FrameDimensionTime);
SetTimer(hwnd, DRAW_ANIM, 100, NULL);
}
break;
case WM_TIMER:
if (wParam == DRAW_ANIM)
{
pImg->SelectActiveFrame(&FrameDimensionTime, nFrm);
Rect DRC(0, 0, pImg->GetWidth(), pImg->GetHeight());
pGphcs->Clear(Color(128, 128, 128));
pGphcs->DrawImage(pImg, DRC);
if (nFrm < (nFrmCnt - 1)) nFrm++; else nFrm = 0;
}
break;
hwndText = CreateWindow(L"EDIT",
L"",
WS_CHILD | WS_VISIBLE,
350, 480, 55, 20,
hWnd, NULL, NULL, NULL);
I expected gif as background and TextBox will be front of it.
But nothing, :(
For performance reasons by default device context for given HWND does not clip a child window from the parent window's client area.
If parent window draws something in the same location as the child window, it draws also over child window. Accepting some (nowadays minimal) performance hit you can automatically clip children windows form main frame window painting area, by adding WS_CLIPCHILDREN style when creating main frame window. With this style any HDC obtained for main frame window will have area occupied by child control excluded form painting area. This protects child window from overpainting by it's parent window activity.
Setting WS_CLIPCHILDREN for main frame window should solve your problem.
hwnd = CreateWindow( class_name, title, some_styles | WS_CLIPCHILDREN, ... );
Sometimes child windows overlap each other and then they can overdraw each other. In this case WS_CLIPSIBLINGS applied to child windows (of the same parent window), protects one child form another painting.

How to make a Win32 control created without WS_VISIBLE visible?

Suppose hCtl is a handle to a control created without the WS_VISIBLE flag such as:
HWND hCtl = CreateWindowEx(0, WC_STATIC, L"some text",
WS_CHILD | SS_NOTIFY, // no WS_VISIBLE flag
0, 0, 0, 0, hWndParent, (HMENU)IDC_STATIC1, g_hInst, 0);
Is there a more straightforward way to make it visible than the following?
void make_visible(HWND hCtl, HWND hWndParent) {
SetWindowLongPtr(hCtl, GWL_STYLE,
GetWindowLongPtr(hCtl, GWL_STYLE) | WS_VISIBLE);
RECT rc{};
GetClientRect(hCtl, &rc);
MapWindowRect(hCtl, hWndParent, &rc);
InvalidateRect(hWndParent, &rc, TRUE);
UpdateWindow(hWndParent);
//ShowWindow(hCtl, SW_SHOW); // no use: does not update window
//SetWindowPos(hCtl, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // no use: does not update window
}
To make a child control visible, call SetWindowPos like this:
SetWindowPos(hCtl, 0, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
Your code to call MapWindowRect, InvalidateRect, UpdateRect etc. should be removed.
Perhaps the real problem you have is that you have created the static control with zero width and height.
The normal way to make a window visible is only the function ShowWindow. There is no need dealing with flags and so on. Usually you use SW_SHOW as a parameter for a child window. Check the other values and use what you think is appropriate.
If the window has a visible rectangle and isn't covered by another window it will show up. Even UpdateWindow calls are not needed. The window will show up in the next paint cycle. If your control has a size of 0,0,0,0 (as it was created) it will never show up.
There is also a ShowWindowAsync function for the use if the window is on a different thread to avoid blocking.
BTW: I don't understand what you try with invalidating the parent window area. If there is a child window clipping (WS_CLIPCHILDREN) it has no effect.
I believe your problem is that you're explicitly setting the WS_VISIBLE style yourself and then calling ShowWindow, which confuses Windows into believing that the window is already visible and doesn't need to be repainted.
Just call ShowWindow. There should be no need to explicitly set WS_VISIBLE yourself because ShowWindow already does it. You should not need to forcibly repaint your control.
Additionally, if you find some need to explicitly invalidate your control, it should be sufficient to just do InvalidateRect(hCtl, NULL) and not bother with GetClientRect and MapWindowRect.

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