Drawing Check Box and Radio controls on a CDialogEx for Dark Mode (Win32)

ChuckieAJ 176 Reputation points
2025-02-04T11:35:15.4433333+00:00

If I switch off the theme for my checkbox / radio controls with:

SetWindowTheme(hControl, L" ", L" ");

I then get the text colours as I would like, but the actual check / radio symbols are drawn differently:

User's image

If I don't switch off the theme, then the checkbox / radio are drawn as they should be, but the text is black:

User's image

And, using OntCtlColor in the dialog has no affect on those controls:

inline void ApplyDarkModeColors(CDC* pDC, CWnd* pControl, UINT nCtlColor)
	{
		switch (nCtlColor)
		{
		case CTLCOLOR_STATIC: // Static text
			pDC->SetTextColor(darkTextColor);
			pDC->SetBkColor(darkBkColor);
			break;
		case CTLCOLOR_DLG: // Dialog background
		case CTLCOLOR_SCROLLBAR: // Scrollbars
		case CTLCOLOR_EDIT: // Edit control
		case CTLCOLOR_LISTBOX: // Listbox
		case CTLCOLOR_MSGBOX:
			pDC->SetTextColor(darkTextColor);
			pDC->SetBkColor(darkBkControlColor);
			break;
		case CTLCOLOR_BTN: // Buttons
		default:
			// You can add specific cases here if needed
			break;
		}
	}

What I would like to achieve is a combination of the 2:

  • The themed symbols
  • The lighter text

How can I achieve this? Please note that this is a CDialogEx based application so I can't use any code that requires underlying frame functionality.

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,850 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 86,971 Reputation points
    2025-02-04T16:41:44.8733333+00:00

    With themed controls, you can change text colors with Custom Draw

    Test in C++/Win32 with a RadioButton with ID = 12 by changing text color to red and keeping Button theme on Windows 10 :

    Radio_TextColor

    case WM_NOTIFY:
    {
    	LRESULT lResult = 0;
    	switch (((NMHDR*)lParam)->code)
    	{
    	case NM_CUSTOMDRAW:
    	{
    		if (12 == ((NMHDR*)lParam)->idFrom)
    		{
    			NMHDR* pnm = (LPNMHDR)lParam;				
    			lResult = OnCustomDraw(((NMHDR*)lParam)->hwndFrom, (LPNMCUSTOMDRAW)pnm);
    		}
    	}
    	break;
    	default:
    		return FALSE;
    	}
    	return lResult;
    }
    break;
    
    
    LRESULT OnCustomDraw(HWND hWnd, __inout NMCUSTOMDRAW* pNMCD)
    {
    	LRESULT lResult = CDRF_DODEFAULT;
    	switch (pNMCD->dwDrawStage)
    	{
    	case CDDS_PREPAINT:
    	{
    		SetBkMode(pNMCD->hdc, TRANSPARENT);
    		SetTextColor(pNMCD->hdc, RGB(255, 0, 0));
    	
    		SIZE sizeCheckBox;
    		HTHEME hTheme = OpenThemeData(NULL, TEXT("Button"));
    		HRESULT hr = GetThemePartSize(hTheme, pNMCD->hdc, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, NULL, TS_DRAW, &sizeCheckBox);
    		CloseThemeData(hTheme);
    
    		SIZE sizeExtent;
    		GetTextExtentPoint32(pNMCD->hdc, TEXT("0"), 1, &sizeExtent);
    		int nShift = sizeExtent.cx / 2;
    			
    		RECT rc = pNMCD->rc;
    		OffsetRect(&rc, sizeCheckBox.cx + nShift, 0);
    
    		WCHAR wszText[MAX_PATH];
    		GetWindowText(hWnd, wszText, MAX_PATH);
    		DrawText(pNMCD->hdc, wszText, -1, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS | DT_END_ELLIPSIS);
    		lResult = CDRF_SKIPDEFAULT;
    	}
    	break;	
    	}
    	return lResult;
    }
    
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.