Wednesday, January 24, 2007

Automatically Sizing ListView Columns

I use the Microsoft ListView ActiveX control a fair bit. It has several benefits over display-only grids, including multiple row selection and easy support for images. I usually try to avoid having a horizontal scroll bar if possible, so I size the ListView and its columns so the data nicely fits. However, one thing that messes that up is when a vertical scroll bar appears, which automatically happens when there are more rows than the ListView can display. In that case, if you've sized the columns so they exactly fit the width of the ListView, you get a horizontal scroll bar because the vertical scroll bar takes away some of the width of the ListView that was used by columns.

To deal with this, I decided it was better to initially size one of the columns larger than it needs to be to display its data (if possible), then make it narrower if a vertical scroll bar appears. The only problem: how do you know when the vertical scroll bar is visible? There isn't any property indicating that, so I decided to take a brute force method to figure it out.

The following code assumes the ListView is named oList and has two columns, the second of which will be resized after loading the list. There are a couple of "magic" numbers here: 1 is the height of a grid line in the ListView and 22 is the height of the column headers. The code determines whether a vertical scroll bar appears by calculating the height of each item (the height of the font plus the grid line), multiplying by the number of rows, and adding the height of the column headers. If that's greater than the height of the ListView, there's a vertical scroll bar, so the column width is adjusted, accounting for the width of the ListView, the width of the first column, the width of the ListView border, and the width of the vertical scroll bar.
with This.oList
llScroll = .ListItems.Count * ;
(fontmetric(1, .Object.Font.Name, .Object.Font.Size) + ;
fontmetric(5, .Object.Font.Name, .Object.Font.Size) + 1) + ;
22 > .Height
.ColumnHeaders.Item(2).Width = .Width - ;
.ColumnHeaders.Item(1).Width - sysmetric(4) - ;
iif(llScroll, sysmetric(7), 0)
endwith
Adjust this code as necessary if you have more than two columns or want to resize a different column or more than one column.

No comments: