Virtual Developer Workshop: Containerized Development with Docker

Download Source Code and Example

Checked list boxes are often used to show multiple choices that are from multiple-column data source. You might want to try to put a tab between words to separate each item in the list, like its parent, list box.

But if you set LBS_USETABSTOPS for your checked list box style and call SetTabStops() function for your checked list box, all you get is some black marks where the tabs suppose to be in your checked list box.

You might solve this problem by using fonts with constant stroke width (fixed-pitch), like Pica, Elite, and Courier New, then set fixed length for the strings you add. If you are not using these fonts in your checked list boxes, the class CTabCheckListBox is the easiest way to do it.

The class, CTabCheckListBox, implements owner drawn checked list box derived from the CCheckListBox, which overrides the CCheckListBox::DrawItem(), adds SetTabStops() functions that are inherited from CListBox. You are going to use the same ways to setup tab stops as CListBox do. The class CTabCheckListBox is simple, and using this class is simple too, just like normal list box you use tabs, and follow the rules for building normal checked list box.

The code of CTabCheckListBox::DrawItem() mostly comes from CCheckListBox::DrawItem() by using TabbedTextOut() instead of ExtTextOut().

void CTabCheckListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 

	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

	if (((LONG)(lpDrawItemStruct->itemID) >= 0) &&
		(lpDrawItemStruct->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)))
		int cyItem = GetItemHeight(lpDrawItemStruct->itemID);
		BOOL fDisabled = !IsWindowEnabled() || !IsEnabled(lpDrawItemStruct->itemID);
		COLORREF newTextColor = fDisabled ?
			RGB(0x80, 0x80, 0x80) : GetSysColor(COLOR_WINDOWTEXT);  // light gray
		COLORREF oldTextColor = pDC->SetTextColor(newTextColor);
		COLORREF newBkColor = GetSysColor(COLOR_WINDOW);
		COLORREF oldBkColor = pDC->SetBkColor(newBkColor);

		if (newTextColor == newBkColor)
			newTextColor = RGB(0xC0, 0xC0, 0xC0);   // dark gray

		if (!fDisabled && ((lpDrawItemStruct->itemState & ODS_SELECTED) != 0))

		if (m_cyText == 0)
			VERIFY(cyItem >= CalcMinimumItemHeight());

		CString strText;
		GetText(lpDrawItemStruct->itemID, strText);

			lpDrawItemStruct->rcItem.top + max(0, (cyItem - m_cyText) / 2),
			ETO_OPAQUE, &(lpDrawItemStruct->rcItem), "", 0, NULL);

			lpDrawItemStruct->rcItem.top + max(0, (cyItem - m_cyText) / 2),
			strText, strText.GetLength(), m_nTabStops, m_lpnEachStop, lpDrawItemStruct->rcItem.left);


	if ((lpDrawItemStruct->itemAction & ODA_FOCUS) != 0)

In order to use TabbedTextOut(), we need to convert dialog unit to logical unit (or device unit). For the dialog box using the system font, ::GetDialogBaseUnits() will do the work; I couldn't find a exact way to get the dialog unit for using the non-system font. But the code here does do the work we want.

int CTabCheckListBox::GetAverageCharWidths()
	CFont* pFont = GetFont();
	int nBaseUnit = lf.lfWidth;
	if(nBaseUnit == 0)
		nBaseUnit = LOWORD(GetDialogBaseUnits());
	return nBaseUnit;
To use CTabCheckListBox:
  1. Add a list box control to your dialog resource. Setup the list box style by selecting LBS_OWNERDRAWFIXED, LBS_HASSTRINGS (without LBS_SORT selected). If you want to use the other checked list box styles, you are going to make your own class.
  2. Insert TabCheckListBox.cpp and TabCheckListBox.h files into your project.
  3. Add an instance of CTabCheckListBox in your dialog box member data.
  4. CTabCheckListBox m_ctrlCheckListBox;

  5. Call SubclassDlgItem() to initialize the class in your OnInitDialog();
  6. m_ctrlCheckListBox.SubclassDlgItem(IDC_LIST1, this);

  7. Set tab-stop position before you add strings to your checked list box. There are 3 functions to set the tab-stop, same as the CListBox::SetTabStops().
  8. void SetTabStops( );

    BOOL SetTabStops( const int& cxEachStop );

    BOOL SetTabStops( int nTabStops, LPINT rgTabStops );

    To set equal tab stops to the default size of 2 dialog units, call the parameterless version of this member function. To set equal tab stops to a size other than 2, call the version with the cxEachStop argument.

    To set tab stops to an array of sizes, use the version with the rgTabStops and nTabStops arguments. A tab stop will be set for each value in rgTabStops, up to the number specified by nTabStops.

    Referring CListBox::SetTabStops for how to using these functions.

  9. Add Strings to your checked list box, like

CString str;

str.Format(_T("%s\t%s\t%d"), "aaZAaa", "dddaaa", 1);


The demo project shows how to use CTabCheckListBox by setting different tab stops and using different font.

Last updated: 6 June 1998


  • Problem: Text with white color !!

    Posted by bhushan_kalse on 08/21/2006 11:49am

    Hi, I was trying to use the same code in my program where I want to have a list box control with 4 columns for text and of course one check box in every row. I did it successfully and the result was - text in the list box was with white color ! I am very sure that text was getting inserted into the list box, as I am able to read that from other functions in my program (which read the text from listbox). Not sure why is it happening. I have tried to debug in "CTabCheckListBox::DrawItem" and feel this is where my text is getting into white color. Any clue ? Thanks for your help. ~Bhushan.

  • adding strings to a multicolumn checklistbox

    Posted by Legacy on 12/04/2001 08:00am

    Originally posted by: Rekha

    I dont have the class CTabChecklistbox available in my VC version. So, what can i do for my total string(given in Addstring function) to be properly aligned?
    i've got 5 strings, that need to be concatenated to get a single large string, which is then added as a parameter to checklistbox's Addstring function.
    But its somehow not appearing correctly. Pl. help.

  • help

    Posted by Legacy on 01/13/2000 08:00am

    Originally posted by: weiling

    How to "Setup the list box style by selecting LBS_OWNERDRAWFIXED, LBS_HASSTRINGS"?

  • You must have javascript enabled in order to post comments.

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

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date