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.
HeaderAutofit.h
#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 public: CHeaderAutofit(); // Attributes private: bool m_bAutofit; public: // Operations private: void Autofit(int nOverrideItemData = -1, int nOverrideWidth = 0); public: void SetAutofit(bool bAutofit = true) { m_bAutofit = bAutofit; Autofit(); } // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CHeaderAutofit) //}}AFX_VIRTUAL // Implementation public: virtual ~CHeaderAutofit(); // Generated message map functions protected: //{{AFX_MSG(CHeaderAutofit) afx_msg void OnEndTrack(NMHDR * pNotifyStruct, LRESULT* result); afx_msg void OnSize(UINT nType, int cx, int cy); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // 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
// HeaderAutofit.cpp : implementation file // // ) 1997 Baldvin Hansson [baldvin@trafficsoftware.com] #include#include #include "HeaderAutofit.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CHeaderAutofit CHeaderAutofit::CHeaderAutofit() { m_bAutofit = false; } CHeaderAutofit::~CHeaderAutofit() { } BEGIN_MESSAGE_MAP(CHeaderAutofit, CHeaderCtrl) //{{AFX_MSG_MAP(CHeaderAutofit) ON_NOTIFY_REFLECT(HDN_ENDTRACK, OnEndTrack) ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // 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) return; SetRedraw(FALSE); GetClientRect(&rClient); 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 continue; 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! continue; hi.mask = HDI_WIDTH; GetItem(nItem, &hi); hi.mask = HDI_WIDTH; hi.cxy = (hi.cxy * rClient.Width()) / nTotalWidthOfColumns; SetItem(nItem, &hi); } } SetRedraw(TRUE); Invalidate(); } 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); Autofit(); }