如何自动调整TVirtualStringTree中跨列的大小?

4
我有一个VirtualStringTree (VST)的简单示例,它有4列,在第2列或第3列中可能会有更多的文本,适合默认列宽。我启用了hoAutoSpanColumns,因此如果它们为空,大文本将重叠其他列。这个效果很好。问题是当第2或第3列的文本应跨越整个VST长度时。在这种情况下,大列只延伸到最后一列(第4列)的末尾。

以下是第3行中第2列如何仅跨越第3和第4列,然后停止在第4列的宽度处:

enter image description here

如果我使用AutoFitColumns自动调整第二列的大小:
VST1.Header.AutoFitColumns(false, smaUseColumnOption,1,1);

然后它推动第三和第四列,使它们从第二列的末尾开始:

enter image description here

但是我需要第三列和第四列保持相同的位置,就像这样:

enter image description here

有没有一种方法可以自动调整第二列的宽度以适应文本,但保持第三列和第四列与原来的位置相同?

我认为没有内置的方法。你想要调整哪一个大小呢?最后一个可调整大小的(第四个)吗?如果我在开发这个功能,我会做同样的事情,只是调整你请求的列的大小。 - Victoria
@Victoria 我知道如何调整最后一列的大小,而且它也很有效。问题在于非最后一列,比如我的例子中第二列,它跨越了第三列和第四列。我想要调整它的大小以便看到整个文本,但同时保持第三列和第四列不变。 - Mike Torrettinni
我理解你的问题。我不知道你想要做什么来使那段文字完全可见。是调整最后一列的大小以使跨度文本完全可见吗?还是在最后一列之后移除文本裁剪并以某种方式调整内容矩形的大小?或者是其他什么? - Victoria
我猜最后一列应该调整大小,以便完整显示第二列。那样行得通吗? - Mike Torrettinni
是的,那可能行得通。或者你可以在表头末尾添加一些“幽灵”列,这些列不可点击(无论如何也不可控制),只会为跨度文本调整大小。 - Victoria
1个回答

3

目前还没有内置的方法来自动适应跨列文本的标题。要自动调整给定列的大小以查看整个跨列文本,您可以编写以下代码(针对单个节点)。请注意,VT中的autospan功能目前不支持RTL阅读(因此此代码也不支持):

type
  TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
  protected
    function GetSpanColumn(Node: PVirtualNode): TColumnIndex; virtual;
  public
    procedure AutoFitSpanColumn(DestColumn: TColumnIndex; Node: PVirtualNode);
  end;

implementation

{ TVirtualStringTree }

function TVirtualStringTree.GetSpanColumn(Node: PVirtualNode): TColumnIndex;
begin
  { this returns visible span column for the given node, InvalidColumn otherwise }
  Result := Header.Columns.GetLastVisibleColumn;
  while ColumnIsEmpty(Node, Result) and (Result <> InvalidColumn) do
    Result := Header.Columns.GetPreviousVisibleColumn(Result);
end;

procedure TVirtualStringTree.AutoFitSpanColumn(DestColumn: TColumnIndex; Node: PVirtualNode);
var
  ColsWidth: Integer;
  SpanWidth: Integer;
  SpanOffset: Integer;
  SpanColumn: TColumnIndex;
begin
  SpanColumn := GetSpanColumn(Node);

  if SpanColumn <> InvalidColumn then
  begin
    { get the total width of the header }
    ColsWidth := Header.Columns.TotalWidth;
    { get the width of the span text cell as it would be autosized }
    SpanWidth := DoGetNodeWidth(Node, SpanColumn) + DoGetNodeExtraWidth(Node, SpanColumn) +
      DoGetCellContentMargin(Node, SpanColumn).X + Margin;
    { and get the left position of the span cell column in header }
    SpanOffset := Header.Columns[SpanColumn].GetRect.Left;
    { now, the width of the autosized column we increase by the subtraction of the fully
      visible span cell width and all columns width increased by offset of the span cell
      column; in other words, we'll just increase or decrease width of the DestColumn to
      the difference of width needed for the span column to be fully visible, or "fit" }
    Header.Columns[DestColumn].Width := Header.Columns[DestColumn].Width +
      SpanWidth - ColsWidth + SpanOffset;
  end;
end;

太好了!我添加了一个参数 NeverShrink: boolean = True,以确保它不会缩小总大小,以防一行比下一行/最后一行的文本多。你觉得这个怎么样? - Mike Torrettinni
我不确定我是否理解了。如果你想要自动调整所有节点及其可能的跨列的标题大小,你可以简单地创建一个函数,返回 DestColumn 的增长而不是修改它,当遍历所有节点并修改 DestColumn 的宽度时存储该函数返回的最小值和最大值即可。 - Victoria
我循环VST并在每个节点上调用AutoFitSpanColumn。我的前提是一旦DestColumn被调整大小,它就不应该再缩小。不确定我需要知道它被调整了多少,对吧? - Mike Torrettinni
1
那我猜对了。好的,那么你可以按照我的建议去做。只收集增长值,当迭代完成后,通过你所收集到的最低或最高值来修改“DestColumn”。这样做更好,因为你只需要在迭代过程中调整一次列的大小(所以无需锁定列集合进行更新)。 - Victoria
现在我知道你的意思了。好建议,不要每次调整大小,而是获取最大宽度并调整一次。谢谢! - Mike Torrettinni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接