TListView (ViewStyle = vsReport) を使用すると、各列の Width プロパティでLVSCW_AUTOSIZE
またはLVSCW_AUTOSIZE_USEHEADER
値を設定して列の幅を自動調整できます。仮想モードで Listview の使用を開始しましたが、列の幅は変更されません。これらの値に従って。質問は次のとおりです。リスビューが仮想モードの場合、コンテンツまたはヘッダーに合わせて列の幅を調整するにはどうすればよいですか?
3 に答える
仮想モードのリスト ビューは項目のキャプションを事前に認識していないため (可視領域のデータのみを要求するため)、最も広い幅も認識できないため、自動サイズ フラグがLVM_SETCOLUMNWIDTH
動作するのはそのためです。こちらです。
したがって、唯一の方法は、すべてのデータをクエリし、将来のすべてのキャプションのテキスト幅を測定し、列幅を最も広い幅の値に設定するカスタム関数を作成することです。
次の例は、その方法を示しています。テキスト幅の計算にマクロを使用しListView_GetStringWidth
ます (これが最も自然な方法のようです)。ただし、問題はテキスト パディングの値です。ドキュメントに記載されているように:
ListView_GetStringWidth マクロは、指定された文字列の正確な幅をピクセル単位で返します。ListView_SetColumnWidth マクロの呼び出しで、返された文字列幅を列幅として使用すると、文字列が切り捨てられます。文字列を切り捨てずに格納できる列幅を取得するには、返された文字列幅にパディングを追加する必要があります。
しかし、パディング値を取得する方法については言及していませんでした(そう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, ' + IntToStr(I) + '] ' +
DupeString('x', 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.
RRUZによって作成されたこのヘルパー関数ユニットについて考えてみます。
ヘルパー関数の抜粋:
procedure AutoResizeColumn(const Column:TListColumn;const Mode:Integer=LVSCW_AUTOSIZE_BESTFIT);
procedure AutoResizeColumns(const Columns : Array of TListColumn;const Mode:Integer=LVSCW_AUTOSIZE_BESTFIT);
procedure AutoResizeListView(const ListView : TListView;const Mode:Integer=LVSCW_AUTOSIZE_BESTFIT);
モード(パラメーター)は次のようになります。
- LVSCW_AUTOSIZE_BESTFIT
- LVSCW_AUTOSIZE
- LVSCW_AUTOSIZE_USEHEADER
それがあなたの要求の良い出発点として役立つことを願っています。
列が狭すぎるのを避けるための別の解決策を次に示します。ただし、表示する必要のあるデータについてある程度の知識が必要になるため、一般的な解決策ではありません..
最も長い/最も広いデータ項目を使用して ListViewItem を構築します。非仮想モードに切り替えて、この最大 ListViewItem だけを追加します。最大アイテムに基づいて列幅を自動調整してから、最大アイテムを削除し、仮想モードに切り替えます。例えば:
// build a ListViewItem with longest data items
string[] items = new string[2];
items[0] = "999999"; // number
items[1] = "99:59:59.999"; // time hh:mm:ss.ttt
ListViewItem lviMax = new ListViewItem (items);
lv.VirtualMode = false; // switch to non-virtual mode
lv.Items.Clear (); // empty the row/line collection
lv.Visible = false; // so user doesnt see the fake values
lv.Items.Add (lviMax); // add line(s) with longest possible data items
lv.AutoResizeColumns (ColumnHeaderAutoResizeStyle.ColumnContent); // adjust column width
lv.AutoResizeColumns (ColumnHeaderAutoResizeStyle.HeaderSize); // adjust column width
lv.Items.Clear (); // empty row/line collection
lv.Visible = true;
lv.VirtualMode = true; // switch back to virtual mode
サンプル形式の値によっては、一部の列が少し広すぎる可能性がありますが、少なくとも列が狭すぎることはありません..