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.

1 comment:

Anonymous said...

Aston Villa rode their luck at Hull City where an 88-minute own goal from Kamil Zayatte saw them leapfrog three points clear of Arsenal and into fourth place in the Premier League wow gold with a 1-0 win.

Villa had to survive Hull penalty appeals for a handball against Ashley Young in time added on, television replays showing that referee Steve Bennett wow gold correctly rejected the claims after consulting a linesman.

Bennett had been involved in controversy after just five minutes when American goalkeeper Brad Friedel looked to have handed Hull the initiative and threaten Villa's return to the Champions League qualifying wow gold zone.

Friedel spilled wow gold the ball under pressure from Nick Barmby and stand-in right-back Nigel Reo-Coker turned it into his own net as he attempted to wow gold clear.

But Bennett cut short wow gold celebrations at the KC Stadium -- and let Friedel off the hook -- when he ruled out the score for an apparent infringement by Barmby.

Zayatte's intervention from a Young cross bound for wow gold Gabriel Agbonlahor then saw Villa leapfrog Arsenal and draw level with Manchester United on 38 points -- seven adrift of leaders Liverpool and four wow gold behind Chelsea.

Stung by an on-pitch dressing down wow gold by manager Phil Brown at Manchester City last week, Hull showed five changes and a vastly improved performance.

Promoted Hull were looking for only their second win in 11 games while wow gold Villa arrived unbeaten in seven and it looked to be heading for a goalless draw when the home side suffered a cruel late blow.