How Do I Set the Background Color of buttons including a Checkbox button? - c++

How Do I Set the Background Color of buttons including a Checkbox button?
I struggled to find the answer to this today - thinking it should be simple to answer this, but the information I stumbled on was less than helpful, so at the risk of duplicating stuff that's out there but I couldn't find, I'll make this quick'n'dirty how-to...

All 'Button' class windows send WM_CTLCOLORSTATIC to their parent window, which can then call ::SetBkColor((HDC)wParam, rgbBkColor), and return a brush for that color.
If this is all using system colors, then the brush handle doesn't need to be managed, you can simply ask for the ::GetSysColor(sysIndex), and return the ::GetSysColorBrush(sysIndex) for the returned brush.
If you're using a custom color, then you'll need to create your own brush and manage the handle for that.
I needed this code for a Message Box replacement, which has the upper part using a white background, and the lower part using a gray background, per the Windows standard message box. So my static control (icon) needed to be white, while my other buttons (including a "Don't ask again" checkbox) needed to have a gray background (checkboxes normally have a white background).
So, I handle WM_ERASEBKGND to paint the two portions of the background correctly, and then I handle WM_CLTLCOLORSTATIC to ensure that all buttons are properly "transparent" for the background that they appear on. In my case, the I used a "Static" control for the icon, which draws its background in gray, and a couple of push-buttons plus a checkbox button - which a checkbox button always paints its background in white, so both required a fix.
My example is using MFC, but hopefully you can translate that trivially enough for your purposes:
// add to the message map:
ON_MESSAGE(WM_CTLCOLORSTATIC, OnCtlColorStatic)
// create the implementation:
LRESULT CRTFMessageBox::OnCtlColorStatic(WPARAM wParam, LPARAM lParam)
{
// buttons and static controls (icon) send WM_CTLCOLORSTATIC, so we can force them to use the correct background color here...
const HDC hdc = (HDC)wParam;
const int idc = ::GetDlgCtrlID((HWND)lParam);
// choose a system color or brush based on if this is icon (static) or another control (a button)
const int idx = idc == IDC_STATIC ? COLOR_WINDOW : COLOR_3DFACE;
// select system color
::SetBkColor(hdc, GetSysColor(idx));
// return system brush (which we don't need to delete!)
return (LRESULT)GetSysColorBrush(idx);
}

Related

What is the right way to add buttons to the Media Foundation Interfaces video screen

I'm currently trying to build a player literally from scratch using Media Foundation Interfaces.
I use the example taken from here:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd979592(v=vs.85).aspx
As the basis for the player.
I want to add buttons (back/forward button , progress bar etc.) to the video screen window, but it isn't so clear to me how.
I can not simply add a button as a child of the main window because it is hidden by the player, I tried to add the buttons as children of Video window but it did not work ...
What is the right way to add buttons to a video window?
This is part of the code where you register to the player window (to the full code please enter the link I have attached).
// create the instance of the player hwnd = handle of main window
HRESULT hr = CPlayer::CreateInstance(hwnd, hwnd, &g_pPlayer);
// inner call to cplayer
CPlayer *pPlayer = new (std::nothrow) CPlayer(hVideo, hEvent);
// Create a partial topology. (m_hwndVideo == hVideo == hwnd)
hr = CreatePlaybackTopology(m_pSource, pSourcePD, m_hwndVideo, &pTopology);
i try to use this function in order to change video paint so i will have some
place left at the bottom to put there my buttons, here is my function:
VOID update_lower_window(HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc;
GetClientRect(hwnd, &rc);
//rc = father size
RECT repaint;
memcpy(&repaint, &rc, sizeof(RECT));
repaint.top = repaint.bottom - DOWN_SPACE; // DOWN_SPACE == 50
// paint back bottom to white
FillRect(hdc, &repaint, (HBRUSH)COLOR_WINDOW);
EndPaint(hwnd, &ps);
}
i call this function when:
WM_PAINT happend
WM_SIZE happend
WM_CREATE happend
With this said I still could not achieve my goals:
When the movie starts playing it starts full screen and does not leave the space I wanted down (I can not seem to find the message sent when the movie is played or in other words when the movie paint on the screen it's not sent one of the messages on which I inserted my function)
When I reduce the screen, the remnants of the previous screen still remain down and I can't see the background.
When using the Minimize button it get the same phenomenon as in 2.
Another interesting detail The phenomenon I mentioned in 2 occurs only when I change window size by drag from the bottom up, if I change window size by drag from one corner (enlarges or decreases height and width simultaneously) then the window corrects itself and I see in the bottom white part (the background) all the time.
You can reposition video area so your win32 GUI (buttons and progress) is below. See WM_SIZE handler in that sample for how to do it, they calculate rectangle to occupy the window, you can adjust to accommodate your controls.
If you want translucent overlaid controls you can write a EVR Presenter.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb530107(v=vs.85).aspx
https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/mediafoundation/evrpresenter
But that’s relatively hard.
P.S. If you just want a simple solution, use something higher-level. Like Windows Media Player control note they have a C++ example, or .NET for GUI and MediaElement in it.
Update: I think the right place to set initial video position in that sample is likely CPlayer::OnTopologyStatus, after MFGetService(MR_VIDEO_RENDER_SERVICE) line.
Anyway, another approach that might be simpler for your task, create a child window dedicated to the video. Position it so it occupies the majority of your app’s main window, and only leaves bottom 50px unoccupied. Don’t forget to handle at least WM_SIZE to reposition and ideally also WM_DISPLAYCHANGED, WM_ENDSESSION, WM_GETMINMAXINFO. Setup the MF playback so that video occupies the complete child video window.
This will ensure the video won’t interfere with Win32 stuff you’re painting on your bottom 50px panel.
BTW that’s what MPC-HC is doing, see the pic.
As you see on Spy++ screenshot, they have dedicated video window, and also other child windows for Win32 controls of the player.

Treeview node with transparent text background instead of default white

I am using custom draw to try and create transparent tree view ( for now I am testing when Visual Styles are enabled ).
My CDDS_PREPAINT handler works fine, tree has parent's background bitmap drawn properly.
I tried to add CDDS_ITEMPREPAINT handler where I use SetBkColor( ((LPNMCUSTOMDRAW)lParam)->hdc, TRANSPARENT ); and return CDRF_NEWFONT, but that failed. Node is drawn with default white background.
How can I make item's text background transparent?
Thank you.
Best regards.
Below is the illustrative code snippet:
switch( ((LPNMCUSTOMDRAW)lParam)->dwDrawStage )
{
case CDDS_PREPAINT:
{
DrawThemeParentBackground(
((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom,
((LPNMCUSTOMDRAW)lParam)->hdc,
&((LPNMCUSTOMDRAW)lParam)->rc );
// since tree is in dialog box we need below statement
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, (LONG_PTR)CDRF_NOTIFYITEMDRAW );
return TRUE;
}
break;
case CDDS_ITEMPREPAINT : // how to properly handle this ???
{
SetBkMode( ((LPNMCUSTOMDRAW)lParam)->hdc, TRANSPARENT );
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, (LONG_PTR)CDRF_NEWFONT );
return TRUE;
}
break;
}
Unfortunately, this is not easily possible without drawing the items yourself, sorry.
It turns out the Tree View Control has traditionally used ExtTextOut() function internally to draw the item titles. This function takes an explicit flags parameter, where value ETO_OPAQUE says that "the current background color should be used to fill the rectangle".
Because this option is passed as an extra flag and not determined by looking at the current GDI background mode, you can't use SetBkMode() in a custom draw handler to work around this. The background color property of a DC does not support alpha channel either, so it cannot be just set transparent.
Since Common Controls version 6.0 and themed window decorations, this is a bit different, but still not useful in this case: the control just calls DrawThemeBackground() with the TVP_TREEITEM part and the rest is handled according to the theme being used. I see e.g in the default Aero theme in Windows 8.1 that there is this entry:
ClassID | PartID | StateID | Property | Value
---------+--------------+--------------+-----------------+--------------
TreeView | TVP_TREEITEM | TREIS_NORMAL | FILLCOLOR:COLOR | 255, 255, 255
So, what are the alternatives?
There is always an option to return CDRF_SKIPDEFAULT for the CDDS_ITEMPREPAINT event and do all the display operations yourself. But then you need to take care of drawing even the lines, [+] boxes, selection and focus rectangles and everything else.
Another option might be to leave the title text stored in the control empty, then add it in CDDS_ITEMPOSTPAINT - i.e. use TVM_GETITEMRECT with wParam=TRUE to get the text rectangle and draw the real text there after everything else has been already painted by the control. But this method fails too, because some tiny opaque rectangle is apparently drawn even for empty text. You'd need to erase that artifact first, only then proceed with drawing the text youself. Coming up with a code which does work for all combinations of item state seemed tricky.

change background colour in parent window

I'm very new to win32api programming. I have 3 questions.
how to change the background colour in the parent window. i did it as folows but it dont work
wClass.hbrBackground=(HBRUSH)(RGB(255,255,255));
second question is, I use to add text in the window as follows. the text is in bold font and with a background colour. I want the text to be in normal and without background colour.
PAINTSTRUCT ps;
HDC hDC;
char szBuffer[]="Hello, World!";
hDC=BeginPaint(hWnd,&ps);
TextOut(hDC,10,10,szBuffer,strlen(szBuffer));
third question is how to add group boxes in the parent window. i searched it in the internet but this was discribed how to add group boxes on dialog boxes using resources.
pls some one help me with these isue...
> wClass.hbrBackground=(HBRUSH)(RGB(255,255,255));
I suppose the class structure requiers the handle of the brush, not the color value itself (but I'm not sure). Something like this:
wClass.hbrBackground=(HBRUSH)(CreateSolidBrush(RGB(255,255,255)));
To make the text background transparent use special WinAPI function, SetBkMode(TRANSPARENT); (Oof, spend some time to remember it's name:) ).
In most tasks it will be much better to make a dialog resource and use it like an ordinary window (drawing smth in it, putting simple windows in which you draw, etc) than take an ordinary window and try to add dialog controls in it. It became a common practice since WinForms and then WPF - every window in them is a "form" in which you can add controls, draw in it and so on.
I'm trying to remember if Microsoft put in code to clear the client area. I know at the minimum, you can get the client rect and then use that to base a drawRect() command to the whole client area. You also may have to trap the command to erase the background

StaticText background in TabControl... What events should be processed?

I am rewiting the older application to get the modern look in Windows 7. The GUI elements are created and moved via the explicit code (no special layout manager). Because of some historic reasons, the GUI events were not processed the standard way. They were redirected. It is rather difficult to track them, especially when I do not know what should I focus for.
Here is the example of the window that should be polished. It is not a dialog. It is classical, sizable window placed on the top. However, it should mimic the dialog look. The window uses WTL::CTabControlT<CControl> where the CControl is my class based on the ATL::CWindow -- see the picture first:
It man not be well visible from the picture, but the ends of the red arrows show the grey background of the static texts. However, the backround of the tab itself is white.
What event causes the grey background of the static texts? Is it the WM_CTLCOLORSTATIC. Or, where is the problem? Is the background of the tab expected to be white or grey (standard behaviour)?
Is it recommended (by designers of the visual interface, user experience) to have also the listboxes in the tab the same (white) background?
The outer window has COLOR_3DFACE defined via ATL macro DECLARE_WND_CLASS_EX. What event is responsible for painting the bacground around the tab windows?
Thanks for your help,
Petr
The missing grey background around the tabs was solved by processing the WM_ERASEBKGND message explicitly (the redirection somehow prevented the default processing):
if (uMsg == WM_ERASEBKGND)
{
WTL::CDCHandle dc(reinterpret_cast<HDC>(wParam));
RECT rc;
GetClientRect(&rc);
dc.FillRect(&rc, GetWndClassInfo().m_wc.hbrBackground);
return TRUE;
}
Similarly, the grey background of the static texts on the white tabs was whitened by processing WM_CTLCOLORSTATIC in the ProcessWindowMessage of the TabControl window this way:
else if (uMsg == WM_CTLCOLORSTATIC)
return TRUE;

Visual Studio 2005: static text control won't display with transparent background

I'm using the Dialog editor in Visual Studio 2005 to create a Dialog box with a static text control. I'd like the background of the static text control to be transparent since I'm using an static image control underneath it and the grey text background looks hideous. In the editor, I set the "Transparent" attribute to True and it causes the background to go transparent just like I want it to. But as soon as I run my app and change the text using a SendMessage(hText, WM_SETTEXT, 0L, "newtext"), the background loses its transparency and goes grey again. Any ideas? Btw, I'm doing this in C++.
Thanks in advance for your help!
As Anthony Johnson said, handle the WM_CTLCOLORSTATIC message in the dialog box (you don't have to handle WM_NOTIFY - I don't believe static controls use that message, anyway). But it doesn't seem to be enough to set the background mode to transparent. You also have to set the background brush to a null brush. Something like this should work (in your DialogProc):
case WM_CTLCOLORSTATIC:
SetBkMode((HDC)wParam, TRANSPARENT);
return (INT_PTR)(HBRUSH)GetStockObject(NULL_BRUSH);
If you change the text on the static control, you may have to invalidate what's underneath it for it to draw correctly when you do this.
Try hiding the control, then setting the text, then showing it.
I don't know how you can do it in the dialog editor, but if you handle the WM_NOTIFY message in the static's parent window, the static will send a WM_CTLCOLORSTATIC message before drawing the static. There, if you call SetBkMode((HDC)wParam, TRANSPARENT);, that should make the static have a transparent background.