Recently, when I made a checkbox transparent, I encountered a cbutton re-painting. There were many posts on the Internet about this problem and there were many implementation methods.
Here we will only talk about some problems and solutions I have encountered in actual operations.
1. When the wm_ctlcolor is reloaded in the form to achieve transparency, in some systems that use the XP style, the checkbox has a dark background color and does not really achieve the transparency effect, the specific reason is unclear. The Code is as follows:
Hbrush ctestdlg: onctlcolor (CDC * PDC, cwnd * pwnd, uint nctlcolor)
{
Hbrush HBr = cdialog: onctlcolor (PDC, pwnd, nctlcolor );
// Todo: change any attributes of the DC here
Switch (pwnd-> getdlgctrlid ()){
Case idc_check1:
PDC-> setbkmode (transparent );
PDC-> settextcolor (RGB (0, 0, 0 ));
HBr = (hbrush) getstockobject (null_brush );
Default:
Break;
}
// Todo: return a different brush if the default is not desired
Return HBr;
}
2. Use the subclass method to customize a class ccheckboxtrans and inherit from cbutton, and directly reload the wm_paint message processing function, in the dialog usage section, define the MFC member cbutton m_ocheck and replace it with ccheckboxtrans m_ocheck. The specific code is as follows:
Class ctestdlg: Public cdialog
{
Public:
Ctestdlg (cwnd * pparent = NULL );
// Dialog data
// {Afx_data (ctestdlg)
Enum {IDD = idd_test_dialog };
Ccheckboxtrans m_ocheck;
//} Afx_data
.....
Declare_message_map ()
};
Void ccheckboxtrans: onpaint ()
{
Cpaintdc DC (this); // device context for painting
// Todo: add your message handler code here
Crect rect;
Getclientrect (& rect );
Crect boxrect;
Boxrect = rect;
Boxrect. Right = boxrect. Left + 13;
DC. drawframecontrol (boxrect, dfc_button, dfcs_buttoncheck | (getcheck ()? Dfcs_checked: 0 ));
Cfont ofont;
Ofont. createfontindirect (& m_sfont );
Cbrush * poldbrush = (cbrush *) DC. SelectObject (hbrush) getstockobject (null_brush ));
Cfont * poldfont = (cfont *) DC. SelectObject (& ofont );
DC. setbkmode (transparent );
Cstring strwndtext;
Getwindowtext (strwndtext );
Rect. offsetrect (17, 0 );
DC. drawtext (strwndtext, & rect, dt_left | dt_vcenter | dt_singleline );
// Rect. offsetrect (-3, 0 );
// Rect. Right = 3 + strwndtext. getlength () * (getdevicecaps (DC. getsafehdc (), logpixelsy) * ABS (m_sfont.lfheight)/72 );
// If (getfocus ())
// Dc. drawfocusrect (& rect );
DC. SelectObject (poldfont );
// Dc. SelectObject (poldbrush );
Ofont. deleteobject ();
// Do not call cbutton: onpaint () for painting messages
}
This method basically meets the requirements, but I still found two problems:. when the checkbox is not focused, the highlighted dotted box is sometimes displayed. B. sometimes influenced by the style of the XP style, the font size will become much larger. It is different from other controls, and there will be text overlapping display. The specific reason is unclear. I hope you can give some advice.
3. Using the button of ownerdraw also inherits the cbutton class. However, this time, the onpaint function is not reloaded, but the virtual void drawitem (lpdrawitemstruct) that inherits the wm_drawitem message ); // note that it is not ondrawitem. Do not directly use the Class Wizard to reload wm_drawitem. These two functions are not one function. In addition, you need to reload virtual void presubclasswindow (). The specific code is as follows:
Class ccheckboxtrans: Public cbutton
{
// Construction
Public:
Ccheckboxtrans ();
// Attributes
Public:
// Operations
Public:
// Overrides
// Classwizard generated virtual function overrides
// {Afx_virtual (ccheckboxtrans)
Public:
Virtual void drawitem (lpdrawitemstruct );
Protected:
Virtual void presubclasswindow ();
//} Afx_virtual
......
Declare_message_map ()
};
Void ccheckboxtrans: presubclasswindow ()
{
// Todo: add your specialized code here and/or call the base class
Setbuttonstyle (getbuttonstyle () | bs_ownerdraw );
Cbutton: presubclasswindow ();
}
Void cxpbutton: drawitem (lpdrawitemstruct)
{
// Obtain control information from lpdrawitemstruct
Crect rect = lpdrawitemstruct-> rcitem;
CDC * PDC = CDC: fromhandle (lpdrawitemstruct-> HDC );
Int nsavedc = PDC-> savedc ();
Uint state = lpdrawitemstruct-> itemstate;
Point pt;
Tchar strtext [max_path + 1];
: Getwindowtext (m_hwnd, strtext, max_path );
// Obtain the button status
If (State & ods_focus ){
} Else {
}
If (State & ods_selected | State & ods_default ){
}
...... // Draw other widgets (omitted)
// Display the text of the button
If (strtext! = NULL)
{
Cfont * hfont = getfont ();
Cfont * holdfont = PDC-> SelectObject (hfont );
Csize szextent = PDC-> gettextextent (strtext, lstrlen (strtext ));
Cpoint Pt (rect. centerpoint (). X-szextent. CX/2, rect. centerpoint (). Y-szextent. cy/2 );
If (State & ods_selected)
PT. offset (1, 1 );
Int nmode = PDC-> setbkmode (transparent );
If (State & ods_disabled)
PDC-> drawstate (PT, szextent, strtext, dss_disabled, true, 0, (hbrush) null );
Else
PDC-> drawstate (PT, szextent, strtext, dss_normal, true, 0, (hbrush) null );
PDC-> SelectObject (holdfont );
PDC-> setbkmode (nmode );
}
PDC-> restoredc (nsavedc );
}
In addition, you also need to reload the mouse and keyboard-related messages. Otherwise, the control is drawn and the result cannot be used: (, pay attention to it.
Therefore, the subclass-based self-painting method can solve this problem, but it is better to directly set the image in cmfcbutton to save time and effort.