Custom drawing of a Group Box in CDialog

ChuckieAJ 96 Reputation points
2025-02-04T20:54:38.59+00:00

I think that this is related to the answer here.

I have derived from CFindReplaceDialog in an effort to render it in dark mode:

User's image

All is well (event the check boxes / radio controls 🤣). But the group box needs attantion. In my own dialogs I was switching off the theme and owner drawing:

void CMyStatic::OnPaint() {
	CPaintDC dc(this); // Device context for painting

	// Get the text to display
	CString text;
	GetWindowText(text);

	// Get the client area
	CRect rect;
	GetClientRect(&rect);

	// Use the same font as the parent window (dialog)
	CFont* pOldFont = dc.SelectObject(GetParent()->GetFont());

	// Calculate the text height
	CSize textSize = dc.GetTextExtent(text);
	int textHeight = textSize.cy;

	// Adjust the frame position so the top border intersects the middle of the text
	rect.top += textHeight / 2;

	// Draw the group box border
	// dc.DrawEdge(&rect, EDGE_ETCHED, BF_RECT);

	// Draw a 1-pixel-thick frame
	CPen pen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); // Use a 1-pixel pen
	CPen* pOldPen = dc.SelectObject(&pen);

	// Draw the top border
	dc.MoveTo(rect.left, rect.top);
	dc.LineTo(rect.left + 8, rect.top); // Leave space for the text
	dc.MoveTo(rect.left + 8 + textSize.cx, rect.top); // Resume after the text
	dc.LineTo(rect.right, rect.top);

	// Draw the bottom border
	dc.MoveTo(rect.left, rect.bottom - 1);
	dc.LineTo(rect.right, rect.bottom - 1);

	// Draw the left border
	dc.MoveTo(rect.left, rect.top);
	dc.LineTo(rect.left, rect.bottom - 1);

	// Draw the right border
	dc.MoveTo(rect.right - 1, rect.top);
	dc.LineTo(rect.right - 1, rect.bottom - 1);

	// Restore the old pen
	dc.SelectObject(pOldPen);

	// Set the text color and background mode
	dc.SetTextColor(m_textColor);
	dc.SetBkMode(OPAQUE); // Use OPAQUE mode to draw the text with a background

	// Get the system background color for dialogs (typically COLOR_3DFACE or COLOR_BTNFACE)
	// COLORREF bgColor = GetSysColor(COLOR_3DFACE);
	COLORREF bgColor = RGB(32, 32, 32);

	// Set the background color for the text
	dc.SetBkColor(bgColor);

	// Calculate the text position
	rect.left += 8; // Indent the text slightly
	rect.top -= textHeight / 2; // Move the text back up to its original position

	// Draw the text with a background to mask out the border
	dc.DrawText(text, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE);

	// Restore the old font
	dc.SelectObject(pOldFont);
}

But I can't use this approach with common dialogs. Now I am wondering if I can go down the same route as for checkboxes and radio controls, by using NM_CUSTOMDRAW (since groupbox is also derived from button).

I know that we can detect if we are on a groupbox easily enough:

TCHAR className[256];
GetClassName(pControl->GetSafeHwnd(), className, 256);

if (_tcscmp(className, L"Button") == 0)
{
	CButton* pButton = reinterpret_cast<CButton*>(pControl);
	if (pButton)
	{
		DWORD buttonStyle = pButton->GetStyle();
		if ((buttonStyle & BS_GROUPBOX) == BS_GROUPBOX)
		{
			// We need to draw the group box
		}
	}
}

Is there a better way to render the groupbox here in NM_CUSTOMDRAW?

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,843 questions
0 comments No comments
{count} votes

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.