Click here to Skip to main content
15,881,413 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
INTRODUCTION AND RELEVANT INFORMATION:

I have 2 dialog boxes created via Resource Editor. Since I use Microsoft Visual Studio Express edition, I had to download free resource editor[^]. In my program, I have visual styles enabled like this:
C++
#include <commctrl.h>

#pragma comment( lib, "comctl32.lib")

#pragma comment( linker, "/manifestdependency:\"type='win32' \
        name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
        processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
        language='*'\"")

As far as I know, check box, radio button, and group box get WM_CTLCOLORSTATIC message for painting their text. This is what I have coded for the first dialog box:
C++
case WM_CTLCOLORSTATIC:
        {
            SetBkMode( (HDC)wParam, TRANSPARENT );
            SetTextColor( (HDC)wParam, RGB( 0, 0, 0 ) );
            return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) );
        }

I just want those controls to have transparent text background and black color of their text.

THE PROBLEM:

On Windows XP[^], the result for first dialog is that check box and it's text are painted properly, but the text background is black. Group box has brown borders, text background has proper transparent color, but text is blue. Radio button is painted properly.

On Windows 7[^], after starting the same program, group box and check box have proper text color, yet text background of the check box and the border of the group box are wrong - they are both white. Radio button has proper text color, but text background is gray.

In my dialog box, I have static controls and they are painted properly both on Windows 7 and Windows XP.

MY EFFORTS TO SOLVE THE PROBLEM:

I have browsed through StackOverflow archive, and tried searching here at CodeProject, but haven't found anything I could use to modify my WM_CTLCOLORSTATIC handler.

I have found an example which removes Visual Styles from those controls, so it can achieve the desired result, but I need to keep the Visual Styles and make the background of the text transparent, thus this solution can not satisfy me.

After looking through Visual Styles reference and a little experimenting, I have found a workaround for radio button and check box ( but not for group box ) with the following code:
C++
case WM_CTLCOLORSTATIC:

     if( (HWND)lParam == GetDlgItem( hwnd, IDC_RADIO1 ) ) 
     {
	 RECT r;
	 GetClientRect( hwnd, &r );
 	 DrawThemeParentBackground( (HWND)lParam, (HDC)wParam, &r );
     }
     else
     {
	 SetTextColor( (HDC)wParam, RGB( 0, 0, 0 ) );
	 SetBkMode( (HDC)wParam, TRANSPARENT );
     }
     return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) );


Still, I have "hit the wall" with this:

In my dialog box there is a treeview and once I select node and press spacebar ( or any other key for that matter ) dialog's background bitmap gets on top of my static controls.

After I comment out DrawThemeParentBackground(), recompile and start program again everything works fine ( when I select tree's node and press spacebar ) but then I am "at square one".

THE QUESTION:

1. How can I modify my WM_CTLCOLORSTATIC handler to fix my problem ?

2. If the above is not possible, can I get the desired effect with NM_CUSTOMDRAW ?

NOTE:

I think that I will have to draw group box using GDI. If that is the case, I will accept this solution too, as my main concern is checkbox and radio button.

Thank you.

Best regards.
Posted
Updated 20-Mar-14 8:39am
v9
Comments
The_Inventor 8-Oct-13 22:35pm    
Well that looks pretty slick. The GroupBox issue seems more complex. I tried creating a member in a dialog, and tried to find a method to alter the line used to draw the box, but found a lot of protected methods, and those that were not protected didn't seem to do the job. I am using MSVS 2013 Preview. It is a CStatic control. However, looking at your method, it seems to me, if you have a ResID for the Radio button, IDC_RADIO1, then maybe you could create a second internal switch group in the same case WM_CTLCOLORSTATIC, that uses IDC_GROUPBOX1, as an example, and have a cases for IDC_RADIO1, IDC_GROUPBOX1, etc. that you want to change.
AlwaysLearningNewStuff 10-Oct-13 18:33pm    
I have tried to assign an ID in the resource editor to the group box, and to add a special case for it-it didn't work.

I think that the only way is to draw it using GDI/GDI+...

Thank you, anyway.

Regards.
The_Inventor 10-Oct-13 23:13pm    
I has feeling that it was more embedded hard code somewhere ... Did you keep the special case within the WM_CTLCOLORSTATIC case braces? Or did you make it outside of it? If your using the MSVS IDE, when drag one on the dialog, a ResID is assigned but it is editable.

I believed it would have worked if you keep it within the case WM_CTLCOLORSTATIC {case IDC_GBOX1{do the changes of text color in here}}

Another choice is to write you own controls. I've never tried it as There Are So Many To Choose From, I feel I would not be able to come up with any better or more useful.

Examples From Microsoft

The following C++ example shows how to set the text foreground and background colors of a static control in response to the WM_CTLCOLORSTATIC message. The hbrBkgnd variable is a static HBRUSH variable that is initialized to NULL, and stores the background brush between calls to WM_CTLCOLORSTATIC. The brush must be destroyed by a call to the DeleteObject function when it is no longer needed, typically when the associated dialog box is destroyed.

A quick way to create an ActiveX control, or other specialized control, is to subclass a window. For more information, see MFC ActiveX Controls: Subclassing a Windows Control.

To prevent the control's container from receiving the window messages sent by a subclassed Windows control, COleControl creates a "reflector" window to intercept certain window messages and send them back to the control. The control, in its window procedure, can then process these reflected messages by taking actions appropriate for an ActiveX control.

Message Sent By Control__________________Message reflected to the control
WM_CTLCOLORSTATIC________________________OCM_CTLCOLORSTATIC

C++
     static HBRUSH hbrBkgnd = NULL; // If you do this ... 

     case WM_CTLCOLORSTATIC:
     {
         HDC hdcStatic = (HDC) wParam;//Yours didn't have this statement
         SetTextColor(hdcStatic, RGB(255,255,255));//White
         SetBkColor(hdcStatic, RGB(0,0,0));//Black

         if (hbrBkgnd == NULL) //... then this will work.
         {
             hbrBkgnd = CreateSolidBrush(RGB(0,0,0)); //And you really forgot this part.
         }
         return (INT_PTR)hbrBkgnd;
     }
     break;
...........

     DeleteObject hbrBkgnd;// Don't forget this either.


If the control runs on a Win32 system, there are several types of WM_CTLCOLOR* messages it may receive. For more information, see WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC.
 
Share this answer
 
Comments
AlwaysLearningNewStuff 14-Sep-13 22:37pm    
I need to color text to black, and text background must be transparent, your example is from MSDN and colors background to black and text to white, which is not what I need.

Since I load the brush using GetStockObject, I do not need to keep track of it, nor do I need to release it.

In my question, I have stated that static controls are painted properly.

This means that my handler for WM_CTLCOLORSTATIC is correct, and that the problem is in the button controls, not in my handler missing the statement you suggested in your WM_CTLCOLORSTATIC handler.

I have tried subclassing with no luck, perhaps you can provide a pseudo code or a snippet, just so I can see if I did something wrong/forgot.

The problem comes when I turn on Visual Styles on, keep that in mind.

Also, I have specifically pointed out that I use pure WIN32 API, not MFC.

Thank you for your reply, I appreciate it.

Regards.
The_Inventor 15-Sep-13 5:29am    
Works in Win32 and MFC. I may have gotten the comments reversed. But RGB(0,0,0), I think is black. In any case you just have to substitute the values for the colors you wanted. If you want transparent then you need RGBA(0,0,0,255). You still need a 'dummy' reference variable, as shown in Microsoft's example. This is seemingly necessary, so as not to confuse the runtime complier. Visual Styles is all about MFC, not Win32. I would check the documentation for the visual styles code reference if I were you.
AlwaysLearningNewStuff 15-Sep-13 6:38am    
Thank you for clarifications.

Still, I could use some small WIN32 example.

I do not think it is much of a big deal, it is standard stuff - text with transparent background, do you know any useful links ?

I will check out Visual Styles reference, but at the moment I am in a mess.

Thanks again.

Regards.
AlwaysLearningNewStuff 24-Sep-13 20:21pm    
I have tried your suggestions, but had no success.

Are you certain that the above handler works, when visual styles are enabled?

If you are certain, than I will have to make a test project to try your solution again.

Again, thank you for your suggestions, I highly appreciate it.

Regards.
The_Inventor 24-Sep-13 21:57pm    
The Visual Style thing, AFAIK, was not initially part of the 'win32', as it mostly started out as actual 32 bit DLLs for the background disk, network, I/O operations and less about how the text or colors looked, later icon and cursor choices were made easier.
The style will override most of your encoded information on a control. It starts with the type of control. Second is that the controls must be in a 'container', such as a dialog, or form view. The background color of the dialog is always gray. I have tried on several occasions to change the color or use a brush that is made from an image, to change the background color. Below you will see a 'new Solution' it used to work, but OS's change, am not sure how if at all that it will work.
C++
	this->GrayCtlColor(HDS hDC, HWND hWnd, UINT nCtlColor, HBRUSH hbrGray, COLORREF clrText);

// implementation of OnCtlColor for default gray backgrounds
//   (works for any window containing controls)
//  return value of FALSE means caller must call DefWindowProc's default
//  TRUE means that 'hbrGray' will be used and the appropriate text
//    ('clrText') and background colors are set.
BOOL PASCAL CWnd::GrayCtlColor(HDC hDC, HWND hWnd, UINT nCtlColor,
	HBRUSH hbrGray, COLORREF clrText)
{
	if (hDC == NULL)
	{
		// sometimes Win32 passes a NULL hDC in the WM_CTLCOLOR message.
		TRACE(traceAppMsg, 0, "Warning: hDC is NULL in CWnd::GrayCtlColor; WM_CTLCOLOR not processed.\n");
		return FALSE;
	}

	if (hbrGray == NULL ||
		nCtlColor == CTLCOLOR_EDIT || nCtlColor == CTLCOLOR_MSGBOX ||
		nCtlColor == CTLCOLOR_SCROLLBAR)
	{
		return FALSE;
	}

	if (nCtlColor == CTLCOLOR_LISTBOX)
	{
		// only handle requests to draw the space between edit and drop button
		//  in a drop-down combo (not a drop-down list)
		if (!_AfxIsComboBoxControl(hWnd, (UINT)CBS_DROPDOWN))
			return FALSE;
	}

	// set background color and return handle to brush
	LOGBRUSH logbrush;
	VERIFY(::GetObject(hbrGray, sizeof(LOGBRUSH), (LPVOID)&logbrush));
	::SetBkColor(hDC, logbrush.lbColor);
	if (clrText == (COLORREF)-1)
		clrText = ::GetSysColor(COLOR_WINDOWTEXT);  // normal text
	::SetTextColor(hDC, clrText);
	return TRUE;
}


The way I used it in another app:

C++
HBRUSH CPlayerView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    switch (nCtlColor)
    {
        case CTLCOLOR_BTN:
        case CTLCOLOR_STATIC:
        {
            pDC->SetBkMode(TRANSPARENT);
        }
        case CTLCOLOR_DLG:
        {
            CBrush*     back_brush;
            COLORREF    color;
            color = (COLORREF) GetSysColor(COLOR_BTNFACE);
            back_brush = new CBrush(color);
            return (HBRUSH) (back_brush->m_hObject);
        }
    }
    return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}
 
Share this answer
 
v2
Comments
AlwaysLearningNewStuff 6-Oct-13 23:47pm    
I was able to solve the problem for radio button and check box, all that remains is groupbox-I need to set the color of its text and the line.

Do you know some code example\tutorial\article that can help me?

Regards.
The_Inventor 8-Oct-13 0:56am    
Share your code for your solved problem first.
AlwaysLearningNewStuff 8-Oct-13 16:31pm    
OK, I have edited my question with the code snippet, as you have asked.

Regards.
The_Inventor 9-Oct-13 4:49am    
Look at comment just below where you posted your snip it. I think you will like it.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900