【问题标题】:How to auto size spanned column in TVirtualStringTree?如何在 TVirtualStringTree 中自动调整跨栏的大小?
【发布时间】:2018-03-02 03:36:50
【问题描述】:

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

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

如果我使用 AutoFitColumns 来自动调整第二列的大小:

VST1.Header.AutoFitColumns(false, smaUseColumnOption,1,1);

然后它会推动第 3 列和第 4 列,因此它们从第 2 列的末尾开始:

但我需要第 3 列和第 4 列保持相同的位置,如下所示:

有没有办法让第 2 列自动适应文本,但将第 3 列和第 4 列保持在原来的位置?

【问题讨论】:

  • 我认为没有内置方法。无论如何,您想调整哪一个?最后一个可调整大小的(第 4 个)?如果我正在开发此功能,我也会这样做,只需调整您请求的列的大小。
  • @Victoria 我知道如何调整最后一个的大小,而且效果很好。问题是非最后一列,就像我的示例第 2 列一样,它跨越第 3 列和第 4 列。我想调整它的大小以查看整个文本,但保留第 3 列和第 4 列。
  • 我理解你的问题。我不知道您要如何使该文本完全可见。调整最后一列的大小以使跨区文本完全可见?或者在最后一列之后删除文本剪辑并以某种方式调整内容矩形的大小?还是别的什么?
  • 我猜应该调整最后一列的大小,以便完整的第二列可见。这行得通吗?
  • 是的,这可行。或者,您可以在标题的末尾添加一些“幽灵”列,该列不可点击(并且无论如何都是可控的),并且只会针对跨区文本调整大小。

标签: delphi autosize virtualtreeview tvirtualstringtree


【解决方案1】:

目前没有内置方法可以将标题自动调整为跨栏文本。要自动调整给定列的大小以查看整个跨区文本,您可以编写这样的代码(对于单个节点)。请注意,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 以确保它不会缩小总大小,以防一行的文本多于下一行/最后一行。您对此有何看法?
  • 我不确定我是否理解。如果您要自动调整所有节点的标题及其可能的跨度列,您可以简单地创建一个函数,该函数将返回 DestColumn 的增长而不是对其进行修改,存储此函数在迭代时返回的最小值和最大值所有节点并相应地修改DestColumn宽度。
  • 我循环VST并在每个节点上调用AutoFitSpanColumn。我的前提是一旦DestColumn 被调整大小,它就永远不会缩小。不确定我需要知道它调整了多少,对吧?
  • 那我猜对了。好吧,那你可以按照我的建议去做。仅收集增长,当您完成迭代时,将 DestColumn 修改为您收集的最低或最高值。更好的是,您只需为迭代调整一次列的大小(因此无需锁定列集合以进行更新)。
  • 现在我知道你的意思了。好建议,不要每次都调整大小,而是获得最大宽度并调整一次。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 2014-11-03
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
相关资源
最近更新 更多