Get window's background color - c++

Is there any function (C++, MFC) to obtain window's background color?

There's a default background color for windows, use GetSysColor(COLOR_WINDOW). But ultimately a window decides itself what is 'background' and what is 'foreground'. Affected by WNDCLASS.hbrBackground and the window's WM_ERASEBKGND and WM_PAINT message handlers. Anything is possible.

CDC* pDc= GetDC();
COLORREF crBkgnd = pDc->GetBkColor();

Related

ATL project pushbutton color change

We have a requirement to change the color of pushbutton/control. I have controls defined in resource file.
We have tried multiple ways
1)Using CMFCButton Object I got defination ambiguity errors
2)
Using CBUtton CDC* pdcWindow1 = m_Button.GetWindowDC(); CRect rect1; GetClientRect(&rect1); pdcWindow1->FillSolidRect(&rect1, (RGB(0, 0, 255)));
No effect on Button color no error as well.
Inputs which i have got so far : we have used ATLcontrols and to color Button we need MFC Functions, here ATL and MFC libs can't coexist they are causing ambiguity errors as both have same functional definitions.
Is it even possible to color ATL controls without MFC functions.?
only solution is --https://jeffpar.github.io/kbarchive/kb/173/Q173974/??
Look of standard Windows GDI buttons is customized according to Button Color Messages:
The system sends a WM_CTLCOLORBTN message to a button's parent window before drawing a button. This message contains a handle to the button's device context and a handle to the child window. The parent window can use these handles to change the button's text and background colors. However, only owner-drawn buttons respond to the parent window processing the message.
In ATL project, you would either handle this notification message in parent window class or use more sophisticated message forwarding (reflection) to reflect this message to button class.
Either way you don't really paint (FillSolidRect), you can just update colors in the message handler. And also pay attention that only owner-drawn buttons expose this functionality.
See also: Owner-drawn button, WM_CTLCOLORBTN and WM_DRAWITEM (clearing an HDC)
This is how I was able to achieve :
HINSTANCE hInstance = GetModuleHandle(NULL);
HANDLE hBitmap = LoadImage(hInstance, MAKEINTRESOURCE(IDB_CURCANCEL_LOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
HANDLE hBitmap1 = LoadImage(hInstance, MAKEINTRESOURCE(IDB_CURLOGIN_LOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
const HWND hOriginalLoginButton = GetDlgItem(IDOK);
const HWND hOriginalCancelButton = GetDlgItem(IDCANCEL);
SendMessage(hOriginalLoginButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap1);
SendMessage(hOriginalCancelButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
Now i am trying to make corners rounded.

Draw in the nonclient area with Direct2D

On this page : https://learn.microsoft.com/en-us/windows/win32/gdi/wm-ncpaint it is explained how to draw in the nonclient area with GDI.
How can I draw in the nonclient area of my window with Direct2D without having to deal with GDI or GDI+ ?
First of all, WM_NCPAINT is old. Using it will disable the DWM theme-ing for the window, giving a windows classic/7 basic look. So don't do it.
But to use any rendering API do draw in the client area, remove the standard window frame from the window by returning 0 when wParam is true in your WM_NCCALCSIZE message.
case WM_NCCALCSIZE:
if (static_cast<bool>(wParam))
return 0;
return DefWindowProc(hwnd, msg, wParam, lParam);
If you want to keep the standard borders, recalculate the window bounds in WM_NCCALCSIZE.
Then to get a "client area" title bar, use DwmExtendFrameIntoClientArea and extend it from the TOP.
Make sure to handle WM_NCHITTEST so that dragging your window will work too.
Make sure to premultiply your ALPHA in direct2d.
Drawing a rectangle at (0,0) will draw a rectangle in the titlebar of your new custom window.
SEE: https://github.com/oberth/custom-chrome

How to just invalidate the background of window, not any pixel of the client area?

just want repaint the background, not any part of the client area.
You can't. The background is painted IN the child area of the window. IF the window uses child controls to draw objects (in its client area) then you could use the WS_CLIPCHILDREN style to ensure that the background painting of the parent window does not over-paint any children.
You'd need to just paint the relevent area on the parent window however, any InvalidateRect type call will cause any overlapping child windows to be repainted regardless.
Have a try with WM_ERASEBKGND.
Example:
HDC hDC = GetDCEx(hWnd, NULL, DCX_CLIPCHILDREN | DCX_CACHE);
SendMessage(WM_ERASEBKGND, (WPARAM)hDC, 0);
When you say "not pixels of the client" area, I assume you want to invalidate the non-client area? If so, try using the SetWindowPos() function with SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME flags.

How to set background color of window after I have registered it?

I am not using a dialog, I'm using my own custom class which I have registered and then used the CreateWindow call to create it, I have preset the background color to red when registering:
WNDCLASSEX wc;
wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0));
But now I want to change the background color at runtime, by e.g. clicking a button to change it to blue.
I have tried to use SetBkColor() call in the WM_PAINT, and tried returning a brush from the WM_CTLCOLORDLG message, they don't work.
Any help?
From Window Background comes:
...The system paints the background for a
window or gives the window the
opportunity to do so by sending it a
WM_ERASEBKGND message when the
application calls BeginPaint. If an
application does not process the
message but passes it to
DefWindowProc, the system erases the
background by filling it with the
pattern in the background brush
specified by the window's class.....
...... An application can process the
WM_ERASEBKGND message even though a
class background brush is defined.
This is typical in applications that
enable the user to change the window
background color or pattern for a
specified window without affecting
other windows in the class. In such
cases, the application must not pass
the message to DefWindowProc. .....
So, use the WM_ERASEBKGND message's wParam to get the DC and paint the background.
You may try the following:
HBRUSH brush = CreateSolidBrush(RGB(0, 0, 255));
SetClassLongPtr(hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
Short answer: Handle WM_ERASEBKGND.
Longer answer:
When you register the WNDCLASS, you're providing information about all windows of that class. So if you want to change the color of just one instance of the window, you'll need to handle it yourself.
When it's time to repaint your window, the system will send your wndproc a WM_ERASEBKGND message. If you don't handle it, the DefWindowProc will erase the client area with the color from the window class. But you can handle the message directly, painting whatever color (or background pattern) you like.

c++ win32: how to set back color of a window?

I can set the back color when i am registering the class, e.g.:
wincl.hbrBackground = CreateSolidBrush(RGB(202, 238, 255));
RegisterClassEx(&wincl);
But how would i do it to any window i have created with the CreateWindow function?
like a button on my main window, i have visual styles enabled, and i can notice the windows default gray back color behind the button.
Don't tell me i have to SetWindowLong for the window procedure on allllllll my controls and intercept the WM_PAINT :(
All the windows controls send a message to their parent to get the brush to use to fill their background.
Assuming you save a copy of the brush handle somewhere, you can do the following in your WindowProc, or DialogProc, to ensure everything draws with the correct background brush.
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORBTN:
HDC hdc;
HWND hwndCtl;
POINT pt;
hdc = (HDC)wParam;
hwndCtl = (HWND)lParam;
pt.x = 0;
pt.y = 0;
MapWindowPoints(hwndCtl,_hwnd,&pt,1);
x = -pt.x;
y = -pt.y;
SetBrushOrgEx(hdc,x,y,NULL);
return (INT_PTR)_skinBrush;
If you want a customized window you can create your own window class to draw that type of window. Implement a handler for wm_paint and draw whatever you want for the window. There are a lot of tutorials available.