且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何更改MFC中复选框的背景颜色?

更新时间:2023-01-27 20:58:24

没有简单的方法可以更改复选框的背景颜色。原因是MFC复选框是系统控件,它不提供更改箭头区域背景颜色的选项,并且该区域不透明。



唯一选项这样做是派生一个使用所有者绘图的 CButton 类。在那里,您可以使用系统功能绘制未选中的框。对于选中的框,然后填充背景并手动绘制箭头。



这可以使用 CDC :: DrawFrameControl对经典复选框进行,用 CDC :: FillSolidRect 填充背景(使用 InflateRect(-2,-2)使用复选框大小)并绘制箭头。



但是应用程序现在不使用经典风格。然后你必须使用 DrawThemeBackground ,使用 CDC :: GradientFill 填充背景,并绘制阴影箭头。但这看起来与系统绘制的复选框完全不同。



There is no simple method to change the background colour of check boxes. The reason is that MFC check boxes are system controls which do not provide options to change the background colour for the arrow area and that area is not transparent.

The only option to do this is deriving a CButton class that uses owner drawing. There you can draw an unchecked box using system functions. For checked boxes fill then the background and draw the arrow manually.

This can be done for classic check boxes using CDC::DrawFrameControl, filling the background with CDC::FillSolidRect (use InflateRect(-2, -2) with the check box size) and drawing the arrow.

But applications do not use the classic style nowadays. Then you have to use DrawThemeBackground, fill the background using CDC::GradientFill, and draw the arrow shaded too. But that will not look exactly like the system drawn check boxes.

// Draw default sized check box.
// Classic        Themed
//
// LLLLLLLLLLLLW  BBBBBBBBBBBBB
// LGGGGGGGGGGSW  B           B
// LG         SW  B           B
// LG       K SW  B        G  B
// LG      KK SW  B       GG  B
// LG K   KKK SW  B  G	 GGG  B
// LG KK KKK  SW  B  GG GGG   B
// LG KKKKK   SW  B  GGGGG    B
// LG  KKK    SW  B   GGG     B
// LG   K     SW  B    G      B
// LSSSSSSSSSSSW  B           B
// WWWWWWWWWWWWW  BBBBBBBBBBBBB
// 
// L = light gray, G = dark gray, S =very light gray, B/K = black, W = white
//
// rcBox:  Rect containing the check box
// clrBk:  Background colour
// clrArr: Colour for arrow (COLOR_BTNSHADOW if disabled; else COLOR_WINDOWTEXT)

// save bk color; is changed by drawing functions
int nBkClr = pDC->GetBkColor(); 

#if 1
// Add aditional states (inactive, pushed) as required
pDC->DrawFrameControl(rcBox, DFC_BUTTON, DFCS_BUTTONCHECK);
#else
// Themed (set nThemedState accordingly):
DrawThemeBackground(m_hTheme, 
    lpDrawItemStruct->hDC, 
    BP_CHECKBOX, nThemedState, 
    &rcBox, NULL);
#endif

CRect rcBk(rcBox);
// Use -3 when themed and CBS_UNCHECKEDHOT
rcBk.InflateRect(-2, -2);
#if 1
pDC->FillSolidRect(&rcBk, clrBk);
#else
// Themed:
// Two triangles: upper left and lower right
static GRADIENT_TRIANGLE TriG[2] = { { 0, 1, 3 }, { 0, 3, 2} };
#define GetR(rgb)   ((int)((rgb) & 0xFF)) // extract R/G/B values fro COLORREF
#define GetG(rgb)   ((int)(((rgb) >> 8) & 0xFF))
#define GetB(rgb)   ((int)(((rgb) >> 16) & 0xFF))
#define Darken(a)   ((a) - ((a) >> 1)) // make R/G/B part darker
#define Brighten(a) ((a) + ((0xFF - (a)) >> 1))	// make R/G/B part brighter
#define Col16(c)    ((COLOR16)((c) << 8)) // convert R/G/B part to COLOR16 value
#define Bright16(a) (Col16(Brighten(a)))
TRIVERTEX TriV[4] = {
{rc.left, rc.top, Col16(GetR(clr)), Col16(GetG(clr)), Col16(GetB(clr)), 0},
{rc.right, rc.top, Bright16(GetR(clr)), Bright16(GetG(clr)), Bright16(GetB(clr)), 0},
{rc.left, rc.bottom, Bright16(GetR(clr)), Bright16(GetG(clr)), Bright16(GetB(clr)), 0},
{rc.right, rc.bottom, 0xff00, 0xff00, 0xff00, 0}
};
pDC->GradientFill(TriV, 4, TriG, 2, GRADIENT_FILL_TRIANGLE);
#endif

// Themed: clrArr = RGB(76, 97, 152); // not shaded!
CRect rcArr(rcBox.left + 3, // left start position
    rcBox.top + 5, // top start position
    rcBox.left + 4, // width 1 pixel
    rcBox.top + 8); // height 3 pixels
for (int i = 0; i < 7; i++) 
{
    pDC->FillSolidRect(&rcArr, clrArr);
    rcArr.OffsetRect(1, (i < 2) ? 1 : -1);
}

pDC->SetBkColor(nBkClr); // restore bk color