CCheckSK'�An Extended Check Box Class

Environment: VC6 SP4

Introduction

This class is derived from the MFC CButton class. It supports the following features:

  • Showing of On/Off LEDs to indicate the state of the check box
  • Showing an icon to indicate the state of the check box. The icon can be specified by using a resource ID, filename, or HICON
  • Left/Center/Right aligned texts
  • Text on the left or right of the LED
  • Enabled/disabled check boxes
  • Tool tips

This article demonstrates how to extend MFC to subclass common controls and to apply owner drawing to give them any desired look.

Using the Code

To use the class, follow these steps:

  1. Add the files CCheckSK.h and CCheckSK.cpp to your project.
  2. Create check boxes on the dialog.
  3. Open the class wizard and create control variables for the check boxes. Choose "Control" for the "Category" and "CButton" for the "Variable Type."
  4. Include CCheckSK.h in the .h file for your dialog class (in the demo, the file is checkDlg.h).
  5. If you had named the check box variable m_chk, in the header file for the dialog, there will be a line CButton m_chk;. Replace the CButton with CCheckSK.
  6. At the end of OnInitDialog of your dialog class, add calls to the appropriate methods in CCheckSK.
  7. BOOL CCheckDlg::OnInitDialog()
    {
        ...
        m_chk1.SetCheck(TRUE);
        m_chk1.SetLedColor(RGB(255, 0, 0), RGB(128, 0, 0));
        m_chk1.SetToolTip("Click on this to change the state");
    
        m_chk5.SetIcon(IDI_ON, IDI_OFF);
        ...
    }
    
  8. If you want to change the look of the check boxes later, you can call any of these methods from your code at run time.

How the Code Works

We start by deriving the CCheckSk class from the CButton MFC.

class CCheckSK : public CButton
{
    ....
}

To make the control owner drawn, the BS_OWNERDRAW style needs to be added to the window style. For this, subclassing is used. To do this, the PreSubclassWindow method is overridden as follows:

void CCheckSK::PreSubclassWindow()
{
    UINT nBS = GetButtonStyle();

    //  the button should not be owner draw
    ASSERT((nBS & SS_TYPEMASK) != BS_OWNERDRAW);

    //  This class supports only check boxes
    ASSERT(nBS & BS_CHECKBOX);

    // Switch to owner-draw
    ModifyStyle(SS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);

    m_nStyle = GetWindowLong(GetSafeHwnd(), GWL_STYLE);

    CButton::PreSubclassWindow();
}

After the owner-draw style has been set, the framework will call the DrawItem method each time it requires the control to be redrawn. So, this method has to be implemented and all code to draw the LED or display the icon has to be added to it. The implementation of this method is a bit long and the following snippet just gives the flow.

void CCheckSK::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
    //  this class works only for push buttons
    ASSERT (lpDIS->CtlType == ODT_BUTTON);

    //  get the device context pointer to draw into
    CDC* pDC = CDC::FromHandle(lpDIS->hDC);

    //  get button state, selected? has focus? disabled?

    //  draw bounding rectangle with color based on whether
    //  the mouse is over the check box

    //  if check box has focus, draw the focus rectangle

    //  calculate LED's and text's rectangle

    //  If icon is given, draw the icon;
    //  otherwise, draw the LED using GDI functions

    //  Calculate the rectangle for the text based on the
    //  horizontal alignment style of the check box

    //  if the button is disabled, draw etched text or draw
    //  plain text

    //  Release all resources

}

Methods

The following methods are present in the CDialogSK class:

  1. DWORD SetIcon(int nIconOn, int nIconOff);

    Sets the icon based on resource ID

  2. DWORD SetIcon(HICON hIconOn, HICON hIconOff);

    Sets the icon based on the handle to a icon

  3. DWORD SetIcon(LPCTSTR lpszFileNameIn, LPCTSTR lpszFileNameOut);

    Sets the icon based on the name of an icon file

  4. BOOL SetLedColor(COLORREF colLedOn, COLORREF colLedOff);

    If any icons are not used, this method is used to set the color of the on/off LED

  5. BOOL SetLedSize (int nSize);

    The size of the LED is changed with this method

  6. void SetToolTip (LPCTSTR lpszText);

    The tool tip for the check box can be changed by using this method

Downloads

Download demo project - 15 Kb
Download source - 6 Kb


About the Author

Abhinaba Basu

Abhinaba loves coding for the sheer fun of it. He started programming in 1995 with BASIC and then moved through Cobol, Pascal, Prolog, C, C++, VisualBasic and VC++. He received a Bachelor of Technology degree from University of Calcutta in 2001. Abhinaba is originally from the City of Joy, Kolkata in India, but now codes and lives in Noida close to Delhi. His hobby is coding which also happens to be his job. Besides coding he loves traveling.

Comments

  • CCheckSK and non-auto check boxes

    Posted by CodeJack on 08/19/2009 06:17am

    CCheckSK doesn't handle properly buttons with BS_CHECKBOX (instead of BS_AUTOCHECKBOX) style. This is how to fix it:

    1. Add new member to the CCheckSK class:
      BOOL m_bAuto;
    2. In the CCheckSK::PreSubclassWindow, right after the line:
      ASSERT(nBS & BS_CHECKBOX);
      insert the following line:
      m_bAuto = (nBS & 0x01);
    3. Make CCheckSK::OnClicked look like this:
      BOOL CheckBox::OnClicked()
      {
      	if (m_bAuto)
      	{
      		m_bCheck = !m_bCheck;
      		Invalidate();
      	}
      
      	return FALSE; // let the parent window handle this message too
      }
      
      (See also my comment "Please notify your parent")

    Reply
  • CCheckSK and DDX_Check

    Posted by CodeJack on 08/19/2009 05:04am

    If you set the initial check box value using DDX_Check, called in CDialog::OnInitDialog, and subclass your check box after this call, then the initial value is ignored by CCheckSK object. This can be fixed by adding the following line to the CCheckSK::PreSubclassWindow:

    m_bCheck = (SendMessage(BM_GETCHECK) == BST_CHECKED);

    Reply
  • Please notify your parent ;-)

    Posted by CodeJack on 08/18/2009 07:57am

    Very good, but I would rather use:
    ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
    and return FALSE from OnClicked(), to let the parent window handle this message too.

    Reply
  • Cool controls!

    Posted by Legacy on 12/07/2003 12:00am

    Originally posted by: Boley

    Cool control,just what I look for?
    Thanks!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • In support of their business continuity and disaster recovery plans, many midsized companies endeavor to avoid putting all their eggs in one basket. Understanding the critical role of last-mile connectivity and always available Internet access for their enterprises, savvy firms utilize redundant connections from multiple service providers. Despite the good intentions, their Internet connectivity risk may still be in a single basket. That is because internet service providers (ISPs) and competitive local …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds