delphi – 如何自动调整虚拟模式中列表视图的列宽?

当我使用TListView(ViewStyle = vsReport)时,我可以自动调整列的宽度,设置每列的Width属性中的LVSCW_AUTOSIZE或 LVSCW_AUTOSIZE_USEHEADER值,现在我开始在虚拟模式下使用Listview,但是列的宽度没有根据这些值进行修改.所以问题是:当lisvtiew处于虚拟模式时,如何调整列的宽度以适合内容标题

解决方法

由于在虚拟模式下的列表视图不提前知道项目标题(因为它只询问可见区域的数据),所以它也不能知道最宽的一个的宽度,所以这就是 LVM_SETCOLUMNWIDTH自动缩放标志的原因以这种方式行事

因此,唯一的方法是编写一个自定义函数,该函数查询所有数据,测量所有未来标题的文本宽度,并将列宽设置为最宽的值.

以下示例显示如何进行.它使用ListView_GetStringWidth宏进行文本宽度计算(这似乎是最自然的方法).但问题是文本填充的值.如文档中所述:

The ListView_GetStringWidth macro returns the exact width,in pixels,
of the specified string. If you use the returned string width as the
column width in a call to the ListView_SetColumnWidth macro,the
string will be truncated. To retrieve the column width that can
contain the string without truncating it,you must add padding to the
returned string width.

但是他们没有提到如何获得填充值(并且似乎是they won't这样做).有些人说(例如here)对于项目的填充使用6像素,而对于子项的填充使用12像素,但不是(至少在Windows 7中为此示例).

///////////////////////////////////////////////////////////////////////////////
/////   List View Column Autosize (Virtual Mode)   ////////////////////////////
///////////////////////////////////////////////////////////////////////////////

unit Unit1;

interface

uses
  Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,StdCtrls,Forms,Dialogs,StrUtils,ComCtrls,CommCtrl;

type
  TSampleRecord = record
    Column1: string;
    Column2: string;
    Column3: string;
  end;
  TSampleArray = array [0..49] of TSampleRecord;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    SampleArray: TSampleArray;
    procedure AutoResizeColumn(const AListView: TListView;
      const AColumn: Integer);
    procedure OnListViewData(Sender: TObject; Item: TListItem);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

///////////////////////////////////////////////////////////////////////////////
/////   TForm1.AutoResizeColumn - auto-size column   //////////////////////////
///////////////////////////////////////////////////////////////////////////////

// AListView - list view object instance
// AColumn - index of the column to be auto-sized

procedure TForm1.AutoResizeColumn(const AListView: TListView;
  const AColumn: Integer);
var
  S: string;
  I: Integer;
  MaxWidth: Integer;
  ItemWidth: Integer;
begin
  // set the destination column width to the column's caption width
  // later on we'll check if we have a wider item
  MaxWidth := ListView_GetStringWidth(AListView.Handle,PChar(AListView.Columns.Items[AColumn].Caption));
  // iterate through all data items and check if their captions are
  // wider than the currently widest item if so then store that value
  for I := 0 to High(SampleArray) do
  begin
    case AColumn of
      0: S := SampleArray[I].Column1;
      1: S := SampleArray[I].Column2;
      2: S := SampleArray[I].Column3;
    end;
    ItemWidth := ListView_GetStringWidth(AListView.Handle,PChar(S));
    if MaxWidth < ItemWidth then
      MaxWidth := ItemWidth;
  end;
  // here is hard to say what value to use for padding to prevent the
  // string to be truncated; I've found the suggestions to use 6 px
  // for item caption padding and 12 px for subitem caption padding,// but a few quick tests confirmed me to use at least 7 px for items
  // and 14 px for subitems
  if AColumn = 0 then
    MaxWidth := MaxWidth + 7
  else
    MaxWidth := MaxWidth + 14;
  // and here we set the column width with caption padding included
  AListView.Columns.Items[AColumn].Width := MaxWidth;
end;

///////////////////////////////////////////////////////////////////////////////
/////   TForm1.FormCreate - setup the list view and fill custom data   ////////
///////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  ListView1.ViewStyle := vsReport;
  ListView1.Columns.Add.Caption := 'Column 1';
  ListView1.Columns.Add.Caption := 'Column 2';
  ListView1.Columns.Add.Caption := 'Column 3';
  ListView1.OwnerData := True;
  ListView1.OnData := OnListViewData;
  ListView1.Items.Count := High(SampleArray);

  for I := 0 to High(SampleArray) do
  begin
    SampleArray[I].Column1 := 'Cell [0,' + IntToStr(I) + '] ' +
      DupeString('x',I);
    SampleArray[I].Column2 := 'Cell [1,High(SampleArray) - I);
    SampleArray[I].Column3 := '';
  end;
end;

///////////////////////////////////////////////////////////////////////////////
/////   TForm1.FormCreate - custom handler for OnData event   /////////////////
///////////////////////////////////////////////////////////////////////////////

procedure TForm1.OnListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := SampleArray[Item.Index].Column1;
  Item.SubItems.Add(SampleArray[Item.Index].Column2);
  Item.SubItems.Add(SampleArray[Item.Index].Column3);
end;

///////////////////////////////////////////////////////////////////////////////
/////   TForm1.Button1Click - auto-resize all 3 columns   /////////////////////
///////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button1Click(Sender: TObject);
begin
  AutoResizeColumn(ListView1,0);
  AutoResizeColumn(ListView1,1);
  AutoResizeColumn(ListView1,2);
end;

end.

相关文章

ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c++ 调用, 抽空研究了一下该库的最新版 ,把...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:...
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因为使用复杂...
API原型: Declare Function MoveFileEx& Lib "kernel32" Alias "MoveFileExA" (By...