I have developed a short piece of code to disable clicking column
headers for columns than cannot be sorted-by.
This code simply uses the customization of header control as
presented in “Indicating sort order” article. I just added slight
more functionality to that header control.
1. I define a prototype and a variable in a class declaration body:
public: typedef BOOL (*ColumnCheckF)(void *,int,LPARAM); void SetCallback(ColumnCheckF checkf=NULL,void * cbdata=NULL) { m_fColumnCheck=checkf; m_pCBData=cbdata; } private: ColumnCheckF m_fColumnCheck; void *m_pCBData;
After a click in a header, I find out the column (and I try to be
wise and not disable clicking to resize columns) and ask the callback
if the click is allowed (TRUE returned) or not.
It means, in the header (class declaration), I add
// handlers afx_msg void OnLButtonDown(UINT,CPoint); DECLARE_MESSAGE_MAP()
and in the .CPP I add
BEGIN_MESSAGE_MAP(CCustHeaderCtrl,CHeaderCtrl) ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() void CCustHeaderCtrl::OnLButtonDown(UINT flags,CPoint pt) { if (m_fColumnCheck!=NULL) { HD_ITEM hditem; CClientDC dc(this); int offset=dc.GetTextExtent(_T(" "),1).cx*2; int x_coord=pt.x; int column=0; hditem.mask=HDI_WIDTH; while (x_coord>((column==0)?0:offset)) { GetItem(column,&hditem); if (x_coord<hditem.cxy-offset) { // falls inside - query the func hditem.mask=HDI_LPARAM; GetItem(column,&hditem); if (!m_fColumnCheck(m_pCBData,column,hditem.lParam)) { // don't forward the message! return; } break; } x_coord-=hditem.cxy; column++; } } CHeaderCtrl::OnLButtonDown(flags,pt); }
The side effect of this code - it disables dragging the "disabled"
columns. (That's because the header control never hears of LButtonDown
message - I filter it of.)