Autofit Header Control


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

The Header Common Control has a lot of functionality but can still be improved quite a bit. One thing I've always missed is to be able to automatically resize it's columns so that they occupy the entire width of the control. The following class inherits from CHeaderCtrl and adds exactly this feature to the Header Control. All you have to do is to insert the columns you want and then call the SetAutofit method. From there on all columns are resized proportionally to their existing size when the size of the control changes or when the user drags a column header divider.

There is still lot of room for improvements. If you find this class useful and make any modifications to it I would appreciate if you'd send me a note with the changes so that we can continue to improve this document. It's much better than posting an alternate version all together. I'll be glad to merge any such improvements into the basic idea.

For information on how to add this header control class to your listview for example, refer to the article "The Header Control" under the ListView category.


#if !defined(AFX_HEADERAUTOFIT_H__B2BEAB04_6276_11D1_875B_00A0C9181E86__INCLUDED_)
#define AFX_HEADERAUTOFIT_H__B2BEAB04_6276_11D1_875B_00A0C9181E86__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// HeaderAutofit.h : header file
// ) 1997 Baldvin Hansson [baldvin@trafficsoftware.com]

// CHeaderAutofit window

class CHeaderAutofit : public CHeaderCtrl
// Construction

// Attributes
	bool m_bAutofit;

// Operations
	void Autofit(int nOverrideItemData = -1, int nOverrideWidth = 0);
	void SetAutofit(bool bAutofit = true) { m_bAutofit = bAutofit; Autofit(); }

// Overrides
	// ClassWizard generated virtual function overrides

// Implementation
	virtual ~CHeaderAutofit();

	// Generated message map functions
	afx_msg void OnEndTrack(NMHDR * pNotifyStruct, LRESULT* result);
	afx_msg void OnSize(UINT nType, int cx, int cy);



// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_HEADERAUTOFIT_H__B2BEAB04_6276_11D1_875B_00A0C9181E86__INCLUDED_)

// HeaderAutofit.cpp : implementation file
// ) 1997 Baldvin Hansson [baldvin@trafficsoftware.com]

#include "HeaderAutofit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;

// CHeaderAutofit

	m_bAutofit = false;


BEGIN_MESSAGE_MAP(CHeaderAutofit, CHeaderCtrl)

// CHeaderAutofit message handlers

void CHeaderAutofit::Autofit(int nOverrideItemData /*= -1*/, int nOverrideWidth /*= 0*/)
	int nItemCount = GetItemCount();
	int nTotalWidthOfColumns = 0;
	int nDifferenceInWidht;
	int nItem;
	HD_ITEM hi;
	CRect rClient;

	if (!m_bAutofit)


	if (-1 != nOverrideItemData)
		rClient.right -= nOverrideWidth;

	// Get total width of all columns
	for (nItem = 0; nItem < nItemCount; nItem++)
		if (nItem == nOverrideItemData)	// Don't mess with the item being resized by the user

		hi.mask = HDI_WIDTH;
		GetItem(nItem, &hi);

		nTotalWidthOfColumns += hi.cxy;

	if (nTotalWidthOfColumns != rClient.Width())
		nDifferenceInWidht = abs(nTotalWidthOfColumns-rClient.Width());	// We need to shrink/expand all columns!
		// Shrink/expand all columns proportionally based on their current size
		for (nItem = 0; nItem < nItemCount; nItem++)
			if (nItem == nOverrideItemData)	// Skip the overrride column if there is one!
			hi.mask = HDI_WIDTH;
			GetItem(nItem, &hi);

			hi.mask = HDI_WIDTH;
			hi.cxy = (hi.cxy * rClient.Width()) / nTotalWidthOfColumns;

			SetItem(nItem, &hi);


void CHeaderAutofit::OnEndTrack(NMHDR * pNotifyStruct, LRESULT* result)
	HD_NOTIFY* pHDN = (HD_NOTIFY*)pNotifyStruct;

	Autofit(pHDN->iItem, pHDN->pitem->cxy);

void CHeaderAutofit::OnSize(UINT nType, int cx, int cy) 
	CHeaderCtrl::OnSize(nType, cx, cy);



  • Better Solution

    Posted by Legacy on 09/06/2001 07:00am

    Originally posted by: Kyle Sluder

    I have an even better method that requires no subclassing at all.  Override your view's OnActivateView virtual member function, and add the following code:

    void CMyView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
    CListView::OnActivateView(bActivate, pActivateView, pDeactiveView);

    if(pActivateView == this)

    GetListCtrl().SetColumnWidth(0, LVSCW_AUTOSIZE);
    GetListCtrl().SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);

    GetListCtrl().SetColumnWidth(1, LVSCW_AUTOSIZE);
    GetListCtrl().SetColumnWidth(1, LVSCW_AUTOSIZE_USEHEADER);

    // TODO: Do the same thing for every column,
    // replacing the first parameter with the column index.


    Of course, this only occurs when the view's window is activated, but you can encapsulate this code in a function and call it from where you need it. The SetRedraw() and RedrawWindow() calls are there to prevent the noticable resize from being drawn to the screen; in the rare case you are doing something like an animation in an item in the control, it will be paused for a half a second.

  • Autofit Header Control

    Posted by Legacy on 03/21/2001 08:00am

    Originally posted by: Mark Elrod

    I also want to do something like this but both your implementation and mine have problems.

    1) resizing the parent window causes the listview to display it horizontal scrollbar in a flickering fashion.

    2) your version does not resize header in realtime but waits until the EndTrack. mine does it in real time but it runs in to scrollbar problem above.

    3) sometimes the proportions can get messed up and resizing causes one column to get progressively bigger and the other to get smaller. this can be avoided by not recalculating the proportions each resize but keeping them around in a member array/vector (choose your poison).

    from messing around with the for a couple hours i feel the only way to do this might be to rewrite the entire lsitview control like netscape did in their mail program. otherwise it is always going to have some problems.


  • Column Headers Occupy entire CListView width

    Posted by Legacy on 10/03/2000 07:00am

    Originally posted by: Jk

    If the idea is to Resize the Column Headers to fit the entire width of the CListView, the following code in the derived ListView class will do. We do not need to have a custom CMyHeaderCtrl derived from CHeaderCtrl

    void CMyListView::OnSize(UINT nType, int cx, int cy)
    CMyListView::OnSize(nType, cx, cy);
    CListCtrl& lc = GetListCtrl();

    CHeaderCtrl *hc = lc.GetHeaderCtrl();

    int lastHeader = hc->GetItemCount() - 1;

    //calculate width occupied by other headers
    int width = 0;
    for(int i = 0; i < lastHeader; i++)
    width += lc.GetColumnWidth(i);

    int lastHeaderWidth = cx - width;
    //now, expand the last column to fit the entire List
    lc.SetColumnWidth(lastHeader, lastHeaderWidth);


  • Simple ListCtrl Header AutoSize

    Posted by Legacy on 02/25/1999 08:00am

    Originally posted by: Larry Yates


    Using VC++ 5, I have had successful results using
    something like this:

    m_ListItem.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER );


  • 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