General controls are not displayed properly by the WM_CTLCOLORSTATIC handler after I set Visual Styles on

INTRODUCTION AND RELATED INFORMATION:

I have two dialog boxes created using the resource editor. Since I use Microsoft Visual Studio Express, I had to download a free resource editor to create them. In my program, I have Visual Styles like this:

 #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 the box, radio button, and group box to get the text WM_CTLCOLORSTATIC to draw their text.

This is what I encoded for the first and second dialog box:

 case WM_CTLCOLORSTATIC: { SetBkMode( (HDC)wParam, TRANSPARENT ); SetTextColor( (HDC)wParam, RGB( 0, 0, 0 ) ); return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) ); } 

I want these controls to have a transparent text background and the black color of their text.

PROBLEM:

In Windows XP, here is an image of the result for the first dialog:

enter image description here

The group box has blue text and a brown frame, and the check box has everything black. In Windows 7, after running the same program, I get the following:

enter image description here

Here the group field and check box have the correct text color, however, the background of the check box and the border of the group field are incorrect. In my dialog box, I have static controls and they are correctly colored in both Windows 7 and Windows XP.

WHAT HAD THE FOLLOWING:

I looked through the SO archive, but did not find anything that I could use to modify the WM_CTLCOLORSTATIC handler.

I found a workaround that removes visual styles from these controls, so it can achieve the desired result, but I need to keep the visual styles and make the text background transparent, the solution cannot satisfy me.

After looking at the Visual Styles link and a little experiment, I found a workaround for the switch and a checkbox (but not for the group field) with the following code:

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

However, I “hit the wall” as follows:

There is a tree structure in my dialog box, and as soon as I select node and press spacebar (or any other key, for that matter), the dialog box bitmap gets on top of my static controls.

After I comment on DrawThemeParentBackground() , recompile and run the program again, everything works fine (when I select the node tree and press spacebar ), but then I am “square one”.

QUESTIONS:

  • How can I change the WM_CTLCOLORSTATIC handler to fix my problem?

  • If the above is not possible, can I get the desired effect using NM_CUSTOMDRAW ?

Note:

I think I will have to draw a group box using GDI . If so, I will also agree with this solution, since my main problem is checkbox and radio button .

THE SUGGESTED PROGRAM EXAMPLE CHANGED:

Upon request, I send SSCCE . To create a project, follow these steps:

1.) Create a default Win32 project in Visual Studio.

2.) In stdafx.h copy / paste the following directives below #include <windows.h> :

 #include <commctrl.h> #include <Uxtheme.h> #pragma comment( linker, "/manifestdependency:\"type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \ language='*'\"") #pragma comment( lib, "comctl32.lib") #pragma comment( lib,"Msimg32.lib") // needed for GradientFill(...) API #pragma comment( lib, "UxTheme.lib") 

3.) In the resource editor, change the "Add" dialog box by adding 2 radio buttons, 2 flags and the group they belong to (see the above figures, also see what I mean) and add a tree structure control (this element control will "cause" the problem).

4.) In the main cpp file, add a helper function to paint a custom background:

 void GradientTriangle( HDC MemDC, LONG x1, LONG y1, LONG x2, LONG y2, LONG x3, LONG y3, COLORREF top, COLORREF bottom ) { TRIVERTEX vertex[3]; vertex[0].x = x1; vertex[0].y = y1; vertex[0].Red = GetRValue(bottom) << 8; vertex[0].Green = GetGValue(bottom) << 8; vertex[0].Blue = GetBValue(bottom) << 8; vertex[0].Alpha = 0x0000; vertex[1].x = x3; vertex[1].y = y3; vertex[1].Red = GetRValue(bottom) << 8; vertex[1].Green = GetGValue(bottom) << 8; vertex[1].Blue = GetBValue(bottom) << 8; vertex[1].Alpha = 0x0000; vertex[2].x = x2; vertex[2].y = y2; vertex[2].Red = GetRValue(top) << 8; vertex[2].Green = GetGValue(top) << 8; vertex[2].Blue = GetBValue(top) << 8; vertex[2].Alpha = 0x0000; // Create a GRADIENT_TRIANGLE structure that // references the TRIVERTEX vertices. GRADIENT_TRIANGLE gTriangle; gTriangle.Vertex1 = 0; gTriangle.Vertex2 = 1; gTriangle.Vertex3 = 2; // Draw a shaded triangle. GradientFill( MemDC, vertex, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE); } 

5.) Initiate common controls in _tWinMain :

 // initialize common controls INITCOMMONCONTROLSEX iccex; iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_STANDARD_CLASSES ; InitCommonControlsEx(&iccex); 

6.) Insert several elements into the tree structure in WM_INITDIALOG :

 case WM_INITDIALOG: { HWND TreeView = GetDlgItem( hDlg, IDC_TREE1 ); // add root item TVINSERTSTRUCT tvis = {0}; tvis.item.mask = TVIF_TEXT; tvis.item.pszText = L"This is root item"; tvis.hInsertAfter = TVI_LAST; tvis.hParent = TVI_ROOT; HTREEITEM hRootItem = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) ); // add firts subitem for the hTreeItem memset( &tvis, 0, sizeof(TVINSERTSTRUCT) ); tvis.item.mask = TVIF_TEXT; tvis.item.pszText = L"This is first subitem"; tvis.hInsertAfter = TVI_LAST; tvis.hParent = hRootItem; HTREEITEM hTreeSubItem1 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) ); // now we insert second subitem for hRootItem memset( &tvis, 0, sizeof(TVINSERTSTRUCT) ); tvis.item.mask = TVIF_TEXT | TVIF_STATE; // added extra flag tvis.item.pszText = L"This is second subitem"; tvis.hInsertAfter = TVI_LAST; tvis.hParent = hRootItem; HTREEITEM hTreeSubItem2 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) ); } return (INT_PTR)TRUE; 

7.) Draw a custom dialog background:

 case WM_ERASEBKGND: { RECT r; GetClientRect( hDlg, &r ); GradientTriangle( (HDC)wParam, r.right, r.bottom - r.top, r.left, r.bottom - r.top, r.left, r.top, RGB( 0x0, 0x0, 0xFF ), RGB( 0xFF, 0xFF, 0x0 ) ); GradientTriangle( (HDC)wParam, r.right, r.bottom - r.top, r.right, r.top, r.left, r.top, RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) ); } return TRUE; 

8.) Add a handler for WM_CTLCOLORSTATIC :

 case WM_CTLCOLORSTATIC: if( ( (HWND)lParam == GetDlgItem( hDlg, IDC_RADIO1 ) ) || ( (HWND)lParam == GetDlgItem( hDlg, IDC_CHECK1 ) ) ) { RECT r; GetClientRect( hDlg, &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) ); 

These are all the necessary steps and information to create a minimal program that demonstrates the problem. Now run the application and notice the differences:

A camera with IDC_RADIO1 and a flag with IDC_CHECK1 will be correctly colored (transparent text with black), while other flags and the switch will not. In addition, after clicking on the tree and click spacebar , you will see a problem with the background of the dialogs.

END OF EDITING

Thanks.

Sincerely.

+8
c ++ winapi
source share
2 answers

I made your dialogue and ran it in both xp and 7, and everything went well. You should do the following:

Create a bitmap in memory and make all your drawings. This should be the background of the dialogue.

 HDC hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL); hdcMemDialogBackground = CreateCompatibleDC(hdc); hBitmap = CreateCompatibleBitmap(hdc, dialogWidth, dialogHeight); hBitmapOld = SelectObject(hdcMemDialogBackground , hBitmap); DeleteDC(hdc); 

To create a radio and checkbox use the "button" class, not static with

 WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON 

styles.

In your dialog box you should include

 WS_CLIPCHILDREN 

style. This will solve the problem of overlapping controls when you click on the screen.

You should not draw the background of the dialog in the WM_ERASEBKGND message, but WM_PAINT

 case WM_PAINT: RECT r, rt; GetUpdateRect(hDlg, &rt, false); GetClientRect( hDlg, &r ); GradientTriangle( hdcMemDialogBackground, r.right, r.bottom - r.top, r.left, r.bottom - r.top, r.left, r.top, RGB( 0x0, 0x0, 0xFF ), RGB( 0xFF, 0xFF, 0x0 ) ); GradientTriangle( hdcMemDialogBackground, r.right, r.bottom - r.top, r.right, r.top, r.left, r.top, RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) ); hdc = BeginPaint(hDlg, &ps); BitBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hdcMemDialogBackground, rt.left, rt.top, SRCCOPY); EndPaint(hDlg, &ps); break; 

And finally for a transparent background, in WM_NOTIFY :

 case WM_NOTIFY: NMHDR *nmr; NMCUSTOMDRAW *nmcd; nmr = (NMHDR *)lParam; nmcd = (NMCUSTOMDRAW *)lParam; if(nmr->idFrom == IDC_RADIO1 && nmr->code == NM_CUSTOMDRAW){ if(nmcd->dwDrawStage == CDDS_PREERASE){ BitBlt(nmcd->hdc, 0, 0, radioButton1Width, radioButton1Height, hdcMemDialogBackground, radioButton1PosX, radioButton1PosY, SRCCOPY); return CDRF_SKIPDEFAULT; } } if(nmr->idFrom == IDC_RADIO2 && nmr->code == NM_CUSTOMDRAW){ //the same } if(nmr->idFrom == IDC_CHECK1 && nmr->code == NM_CUSTOMDRAW){ //the same } if(nmr->idFrom == IDC_CHECK2 && nmr->code == NM_CUSTOMDRAW){ //the same } break; 

At the end, dispose of resources:

 SelectObject(hdcMemDialogBackground, hBitmapOld); DeleteObject(hBitmap); hBitmap = NULL; DeleteDC(hdcMemDialogBackground); hdcMemDialogBackground= NULL; 

EDIT

 POINT pt; RECT rt; GetClientRect(hwndRadioButton1, &rt); pt.x = 0; pt.y = 0; ClientToScreen(hwndRadioButton1, &pt); ScreenToClient(hDlg, &pt); BitBlt(nmcd->hdc, 0, 0, rt.right, rt.bottom, hdcMemDialogBackground, pt.x, pt.y, SRCCOPY); 

EDIT2 (for resizing)

Change WM_PAINT:

 case WM_PAINT: GetUpdateRect(hDlg, &rt, false); hdc = BeginPaint(hDlg, &ps); BitBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hdcMemDialogBackground, rt.left, rt.top, SRCCOPY); EndPaint(hDlg, &ps); break; 

In WM_SIZE:

 case WM_SIZE: r.left = 0; r.top = 0; r.right = LOWORD(lParam);; r.bottom = HIWORD(lParam); GradientTriangle(hdcMemDialogBackground, r.right, r.bottom - r.top, r.left, r.bottom - r.top, r.left, r.top, RGB( 0x0, 0x0, 0xFF ), RGB( 0xFF, 0xFF, 0x0 ) ); GradientTriangle(hdcMemDialogBackground, r.right, r.bottom - r.top, r.right, r.top, r.left, r.top, RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) ); InvalidateRect(hwndRadioButton1, NULL, false); InvalidateRect(hwndRadioButton2, NULL, false); InvalidateRect(hwndCheck11, NULL, false); InvalidateRect(hwndCheck2, NULL, false); InvalidateRect(hDlg, NULL, false); break; 

To resize, you must create hdcMemDialogBackground with the maximum size dialog will have, for example, 1280x1024 or 1680x1050 or any other.

Here it is.

Walter

+3
source share

In the WM_CTLCOLORSTATIC handler WM_CTLCOLORSTATIC you can only modify BG static controls.

The buttons, switches, and test buttons are the same control button. To change its BG, you need to process WM_CTLCOLORBTN . Below is an example here .

+2
source share

All Articles