Click here to Skip to main content
Click here to Skip to main content

Autosize ListCtrl Header

, 19 Apr 2007
Rate this:
Please Sign up or sign in to vote.
Autosize the last column of a list control's header. But there is a catch...

Screenshot - ListCtrlAutoSize.jpg

Introduction

Did you ever wonder how to make a list control automatically resize the last column to fit the entire list control without a horizontal scrollbar. Did you ever want to make it do that as you resize your list control.

Did you actually get it done but ended up with something like this?

Screenshot - ListCtrlAutoSizeProblem.jpg

There is hope, keep on reading.

Background

A while back, I was answering a question on a forum, the person asking the question had created a list control that would resize the last column as he resized his view. But he ran into a problem. When the first item in the list control was not the first visible item and the user resized the view to where a vertical scrollbar was no longer needed, the list control would end up with an empty entry at the top. Of course there was no item there, but it looked like a blank item. He said that a version of Windows Media player had the same problem, but I can't remember the version number. Anyway I didn't believe him until I tried it for myself, and saw the bug first hand.

Let's start writing some code for the resizing, find the problem along the way and fix it.

Using the code

The first thing we need to do is to create a dialog base application. Delete everything on the dialog box. Add a list control to it, make it report type, give it an ID, and attach a variable to it, let's call it m_cList. Don't worry too much about its size or position; we will take care of that in the code. Don't forget to change the dialog's border style to Resizing while you are in the resource editor. Also in order to reduce flickering set the WS_CLIPCHILDREN flag for the dialog box.

Once the above steps are done, we can start coding. Let's add some columns and items to the list control. We are going to do that in OnInitDialog of the main dialog box.

BOOL CListControlIssueDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE); // Set big icon
   SetIcon(m_hIcon, FALSE); // Set small icon

   m_cList.InsertColumn(0, _T("Column1"),LVCFMT_LEFT,100);
   m_cList.InsertColumn(1, _T("Column2"),LVCFMT_LEFT,100);
   m_cList.InsertColumn(2, _T("Column3"),LVCFMT_LEFT,100);

   for ( int i = 0 ; i < 10 ; i++ )
   {
      for ( int j = 0 ; j < 3 ; j++ )
      {
         CString s;
         s.Format(_T("Item %d (%d)") , i, j);
         if ( j == 0 )
         {
            m_cList.InsertItem(i, s);
         }
         else
         {
            m_cList.SetItemText(i, j, s);
         }
      }
   }
   //also lets move it to cover most of the dialog
   CRect Rect;
   GetClientRect(&Rect);
   m_cList.MoveWindow( 5, 5, Rect.Width()-10, Rect.Height()-10);

   return TRUE; // return TRUE unless you set the focus to a control

}

Now let's also add a handler for the WM_SIZE message so that we can resize the list control to fit the dialog as the dialog is being resized. This should look something like this:

void CListControlIssueDlg::OnSize(UINT nType, int cx, int cy)
{
   CDialog::OnSize(nType, cx, cy);

   //make sure m_cList has already been
   //attached to the list control
   if ( IsWindow( m_cList.m_hWnd ) )
   {
      m_cList.MoveWindow( 5, 5, cx-10, cy-10);
   }
}

Now when you run the program you should see a list control with 10 items, 3 columns at 100 pixels wide, which gets resized as you resize the dialog. Easy so far.

Now let's add the code to automatically change the size of the column. For that we need to create a class that inherits from CListCtrl, let call it CMyListCtrl. After that's done let go ahead and catch the WM_SIZE message for the List control. Also add a private method named AutoAdjustColumns which looks like this:
(I have to thank Chris Radke for this code.)

void CMyListCtrl::AutoSizeColumn()
{
   SetColumnWidth(GetHeaderCtrl()->GetItemCount()-1, LVSCW_AUTOSIZE_USEHEADER);
} 

The code above is pretty straight forward. It simply loops through all the columns (except the last one) and subtract their width from the width of the control. And sets the last column's width to the remaining value. (Note: In order to keep the article from getting too complicated this code does not handle minimum column size. However this situation should be handled).

Now in order to resize the columns as the list control is being resized, you would naturally want to call AutoSizeColumn from the OnSize handler of the list control. Go ahead and do that.

void CMyListCtrl::OnSize(UINT nType, int cx, int cy)
{
   CListCtrl::OnSize(nType, cx, cy);

   AutoSizeColumn();
}

Franc Morales suggested that the columns should autoresize after the user drags the column headers. In order to do that we need to handle the HDN_ENDTRACK message and call AutoSizeColumn.

//Per Franc Morales' suggestion
void CMyListCtrl::OnHdnEndtrack(NMHDR *pNMHDR, LRESULT *pResult)
{
   AutoSizeColumn();
   *pResult = 1;
}

Don't forget to change your m_cList type from CListCtrl to CMyListCtrl. Then run the program, scroll the list control to the bottom, and then resize the dialog to a point where a vertical scrollbar is no longer needed. You will probably see this:

Screenshot - ListCtrlAutoSizeProblem.jpg

Well the fix for that in my opinion is pretty interesting. If the call to AutoSizeColumn is made directly from OnSize then this is the result, but if you were to call it after OnSize had returned everything works fine. So to do this we are going to change OnSize's implementation to use PostMessage to post a message to itself and the message handler for that message is going to call AutoSizeColumn. So let's change things to make them look like this:

#define WM_RESIZEME WM_APP+1

BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
   ON_WM_SIZE()
   ON_MESSAGE(WM_RESIZEME,OnResizeMe)
END_MESSAGE_MAP()


void CMyListCtrl::OnSize(UINT nType, int cx, int cy)
{
   CListCtrl::OnSize(nType, cx, cy);

   PostMessage(WM_RESIZEME);
}

LRESULT CMyListCtrl::OnResizeMe(WPARAM,LPARAM)
{
   AutoSizeColumn();
   return 1;
}

Now run the program and resize the dialog in the same way you did before. Things should be fine now.

Have Fun!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ali Rafiee
Architect
United States United States
Ali Rafiee has been developing windows applications using C++ since 1991, and he hasn't looked back since. Ali has been a software development consultant for must of his career, but he has finally settled down and has been working for an educational software company since 2000. While he is not working, he is either learning C#, flying airplanes, playing with his daughter, or answering peoples question on newsgroups, he finds that to be a great learning tool for himself.
 
Ali is also a Microsoft Visual C++ MVP.

Comments and Discussions

 
QuestionHDN_ENDTRACK and VS2010 [modified] PinmemberMember 104327338-Apr-14 4:37 
GeneralExcellent writing Pinmemberk7773-Nov-09 1:46 
GeneralRe: Excellent writing PinmemberAli Rafiee3-Nov-09 4:30 
GeneralRe: Excellent writing Pinmemberk7773-Nov-09 4:37 
You are quite welcome!
One minor change for who may be insterested.
In OnHdnEndtrack(),
Invalidate();
*pResult = 0;
will resize the columns.
GeneralRe: Excellent writing PinmemberAli Rafiee3-Nov-09 5:13 
GeneralOther Columns are not resized. Pinmember"_$h@nky_"8-Oct-08 18:32 
GeneralRe: Other Columns are not resized. PinmemberAli Rafiee9-Oct-08 4:33 
GeneralRe: Other Columns are not resized. Pinmember"_$h@nky_"12-Oct-08 18:28 
GeneralThanx!! PinmemberJUNO_NICE22-Jun-07 23:45 
GeneralPreferred way to size last column Pinmembercradke16-Apr-07 17:05 
GeneralRe: Preferred way to size last column PinmemberAli Rafiee19-Apr-07 5:36 
GeneralDragging headers PinmemberFranc Morales12-Apr-07 22:52 
GeneralRe: Dragging headers PinmemberAli Rafiee13-Apr-07 5:20 
GeneralNice! PinmvpHans Dietrich12-Apr-07 20:19 
GeneralGreat Info! Pinmembertserface12-Apr-07 18:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 19 Apr 2007
Article Copyright 2007 by Ali Rafiee
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid