我有许多用于显示数据的列表视图控件(TListView)。所有这些列表视图都设置为“详细信息”模式,并且都将TImageList分配给它们的“SmallIcons”属性。
我正在尝试根据内容的宽度设置这些列的宽度,就像用户双击每个列标题末尾的分隔符滑块一样。
首先,我尝试将列宽设置为“-1”和“-2”以自动调整它们:不仅没有完美地工作(某些列包含本地字符 - 我正在使用D6和那个表示ANSI字符串 - 太低了)但它也使列的显示速度非常慢(最多30秒显示列表视图,其中包含6列和150个项目,当它具有固定宽度的瞬时)。
我尝试在每个单元格上使用GetTextExtent来获取文本的预期宽度,添加一些边距(从2到10像素),如果列低于计算的文本宽度,则展开列的宽度。对第一列应用特殊处理(Items.caption)以考虑图标的显示(我将图标的宽度加上边距加到单元格文本的宽度上)。
这也不起作用:在许多情况下(例如,以“yyyy / mm / dd hh:nn:ss”格式显示日期会导致文本太大而无法放入列中。)
认为问题可能来自窗口主题引擎,我已经切换到使用GetThemeTextExtent而不是GetTextExtent但获得了相同的结果。
唯一可行的方法是为每个列宽添加一个任意大的边距(20个像素),当然,这会产生比它们应该更大的列。
那么,还有其他策略吗?我不需要任何东西,只能计算一次正确的宽度:首次填充列表时。 “点击列分隔符”背后的代码工作正常,但我找不到如何通过代码触发它(好吧,我想我可以直接将双击消息发送到标题作为黑客)
为了澄清,以下是我尝试以下代码的内容:
(在调用的情况下,有一个对ListView.canvas.Font.Assign(ListView.font)
的调用。它不在这些函数中,因为单个赋值就足够了,但代码在listview的所有非自动调整列上循环。)
修改
我最初尝试使用Windows Theme API:
function _GetTextWidth1(AText: widestring; IsHeader: boolean = false): Integer;
var
ATheme: HTheme;
rValue: TRect;
iPartID: integer;
AWidetext: WideString;
const
LVP_GROUPHEADER = 6;
begin
// try to get text width using theme API
ZeroMemory(@rValue, SizeOf(rValue));
ATheme := OpenThemeData(ListView.Handle, 'LISTVIEW');
try
if not IsHeader then
iPartID := LVP_LISTITEM
else
iPartID := LVP_GROUPHEADER;
AWidetext := AText;
GetThemeTextExtent( ATheme,
ListView.Canvas.Handle,
iPartID,
LIS_NORMAL,
PWideChar(AWidetext),
-1,
DT_LEFT or DT_SINGLELINE or DT_CALCRECT,
nil,
rValue
);
finally // wrap up
CloseThemeData(ATheme);
end; // try/finally
result := rValue.Right;
end;
下次尝试使用DrawText / DrawTextW:
function _GetTextWidth2(AText: widestring; IsHeader: boolean = false): Integer;
var
rValue: TRect;
lFlags: Integer;
begin
// try to get text width using DrawText/DrawTextW
rValue := Rect(0, 0, 0, 0);
lFlags := DT_CALCRECT or DT_EXPANDTABS or DT_NOPREFIX or DT_LEFT or DT_EXTERNALLEADING;
DrawText(ListView.canvas.Handle, PChar(AText), Length(AText), rValue, lFlags);
//DrawTextW(ListView.canvas.Handle, PWideChar(AText), Length(AText), rValue, lFlags);
result := rValue.Right;
end;
使用delphi的TextWidth函数进行第三次尝试
function _GetTextWidth3(AText: widestring; IsHeader: boolean = false): Integer;
begin
// try to get text width using delphi wrapped around GetTextExtentPoint32
result := ListView.canvas.TextWidth(Atext);
end;
在所有情况下,我都会在结果宽度上添加一个边距:我尝试了高达20像素的值。我还考虑了视图使用图标的可能性(在这种情况下,我将图标的宽度加上边距再次添加到第一列)。
答案 0 :(得分:0)
您可以使用canvas.TextWidth方法。但一定要使用TListView画布(不是其他的,即TForm)并首先从TListView为画布指定字体。 例如:
var
s: integer;
begin
ListView1.AddItem('test example item', nil);
ListView1.canvas.Font.Assign(ListView1.font);
s := ListView1.canvas.TextWidth(ListView1.Items[0].Caption) + 10; //this "+10" is a small additional margin
if s > ListView1.Columns[0].Width then
ListView1.Columns[0].Width := s;
它适用于我。