title: MFC VC++ Custom Checkbox Image
body: <p>How do I get a 3-state checkbox to use a different bitmap for the Indeterminate state?</p>
  
  <p>I want to change the image used by my 3-state checkboxes to use a different one; the controls are in Win98-style, and the indeterminate state of such checkboxes is difficult to distinguish from disabled checkboxes (this is presumably why they changed this for the WinXP-style controls, but I cannot use those because of other details in my project).</p>
  
  <p>I'm using Visual C++ 2010, and I've defined an 8x8 bitmap in VS's Resource Editor. The bitmap's ID is <code>IDB_INDET_CHECK</code>.</p>
  
  <p>I'm not entirely sure what the standard "technique" for something like this is; I've only really just started getting into manipulating Windows controls and MFC.</p>
  
  <p>My first attempt was to create a class, <code>CTriButton</code>, that derives from <code>CButton</code>, override the <code>DrawItem</code> function, and try to draw it myself. I then used <code>SubclassDlgItem</code> to turn one of the checkboxes in my window into this class (I think?). This... sort of works? The checkbox no longer appears, and if I click on where it should be, an empty checkbox frame appears, but nothing else happens (and the debug message in my code is not being sent).</p>
  
  <p>Here's the relevant code, though I'm not sure <em>any</em> of this is right. First, code from my window's <code>OnInitDialog</code>.</p>
  
  <pre><code>BOOL CAffixFilterDlg::OnInitDialog() // CAffixFilterDlg is my CDialog-derived window
  {
      CDialog::OnInitDialog(); // call basic version
  
      // subclass a CButton-derived control with CTriButton
      if ( CBipedHead.SubclassDlgItem(IDC_HEAD, this) ) // CBipedHead is a CTriButton member of CAffixFilterDlg, IDC_HEAD is a checkbox
          SetWindowLong(CBipedHead.m_hWnd, GWL_STYLE, CBipedHead.GetStyle() | BS_OWNERDRAW); // set the ownerdraw style
      else // subclassing didn't work
          _ERROR("Subclassing failed."); // I do not see this error message, so SubclassDlgItem worked?
  
      // initialization continues, but is not relevant...
      UpdateWindow();
      Invalidate();
  
      return TRUE;
  }
  </code></pre>
  
  <p>Next, the code for my custom button's <code>DrawItem</code>.</p>
  
  <pre><code>void CTriButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  {
      _DMESSAGE("Drawing TriButton"); // never see this message
  
      CDC dc;
      dc.Attach(lpDrawItemStruct-&gt;hDC);     //Get device context object
      int nWidth = GetSystemMetrics(SM_CXMENUCHECK);
      int nMargin = ( nWidth - 8 ) / 2;
  
      CRect textRt = lpDrawItemStruct-&gt;rcItem;
      textRt.right = textRt.right - nWidth - nMargin;
  
      CString text;
      GetWindowText(text);
  
      UINT textDrawState = DST_TEXT;
      if ( lpDrawItemStruct-&gt;itemState &amp; ODS_DISABLED )
          textDrawState |= DSS_DISABLED;
  
      dc.DrawState(CPoint(textRt.left, textRt.top), textRt.Size(), text, textDrawState, TRUE, 0, (CBrush*)NULL);
  
      CRect rt = lpDrawItemStruct-&gt;rcItem;    // initial rect is for entire button
      rt.left = rt.right - nWidth;            // set left margin
      LONG center = ( rt.bottom + rt.top ) / 2;
      rt.top = center - nWidth/2;
      rt.bottom = center + nWidth/2;
  
      UINT checkDrawState = DFCS_BUTTONCHECK;
      if ( lpDrawItemStruct-&gt;itemState &amp; ODS_DISABLED )
          checkDrawState |= DFCS_INACTIVE;
  
      if ( lpDrawItemStruct-&gt;itemState &amp; ODS_CHECKED )
          checkDrawState |= DFCS_CHECKED;
  
      else if ( GetCheck() == BST_INDETERMINATE ) {
          _VMESSAGE("Indeterminate; custom draw.");
  
          CBitmap indet_check = CBitmap();
          indet_check.LoadBitmap(IDB_INDET_CHECK);
  
          CPoint pt = CPoint(rt.left + nMargin, rt.top + nMargin);
          CSize sz = CSize(8, 8);
  
          dc.DrawState(pt, sz, &amp;indet_check, DST_BITMAP|DSS_NORMAL);
      }
  
      dc.DrawFrameControl(rt, DFC_BUTTON, checkDrawState);
  }
  </code></pre>