4

I have simple example of VirtualStringTree (VST) with 4 columns and in 2nd or 3rd column I could have more text that fit the default column width. I have hoAutoSpanColumns enabled so the large text will overlap other columns, if they are empty. This works good. The problem is when text in 2nd or 3rd column should span over the full length of VST. In this case the large columns only extend to the end of last (4th) column.

Here is how 2nd column in line 3 only spans over 3rd and 4th columns and then it stops at the width of 4th column:

enter image description here

If I use AutoFitColumns to auto size 2nd column:

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

then it pushes 3rd and 4th columns so they start at the end of 2nd column:

enter image description here

But I need 3rd and 4th column to stay at the same positions, like this:

enter image description here

Is there a way to auto fit 2nd column to text, but keep 3rd and 4th columns at the same positions as they were originally?

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
Mike Torrettinni
  • 1,816
  • 2
  • 17
  • 47
  • I don't think there's a built-in way. Which one would you like to resize anyway? The last resizable (4th)? If I were developing this feature, I would do the same, simply resize the column you requested. – Victoria Sep 20 '17 at 23:22
  • @Victoria I know how to resize the last one, and it works good. The problem is the non-last column, like in my example 2nd column,which spans across 3rd and 4th columns. I want to resize it to see the whole text but keep 3rd and 4th columns in place. – Mike Torrettinni Sep 20 '17 at 23:34
  • I understand your question. I don't know what you want to do to make that text fully visible. Resize the last column so it makes that spanned text fully visible? Or remove text clipping after the last column and resize the content rectangle somehow? Or something else? – Victoria Sep 20 '17 at 23:42
  • I guess the last column should be resized so that full 2nd column is visible. Would that work? – Mike Torrettinni Sep 20 '17 at 23:44
  • Yes, that could work. Or you could add to the end of the header some "ghost" column that won't be clickable (and anyhow else controllable) and will be only resized for spanned texts. – Victoria Sep 21 '17 at 01:44

1 Answers1

3

There is no built-in way to autofit header to a spanned column text at this time. To autosize a given column to see the whole spanned text you can write a code like this (for single node). Do note that autospan feature in VT doesn't support RTL reading at this time (so this code doesn't as well):

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;
Victoria
  • 7,822
  • 2
  • 21
  • 44
  • Great! I added a parameter `NeverShrink: boolean = True` to make sure it doesn't shrink the total size, in case one line has more text than the next/last line. What do you think about this? – Mike Torrettinni Sep 21 '17 at 11:25
  • I'm not sure if I understood. If you're about to autosize the header from all nodes and their possible span columns, you can simply create a function that will return the growth of the `DestColumn` instead of its modification, store the minimum and maximum values this function returns while iterating all nodes and modify `DestColumn` width accordingly. – Victoria Sep 21 '17 at 12:57
  • I loop the `VST` and call `AutoFitSpanColumn` on each node. My premise was that the once `DestColumn` is resized, it should never shrink. Not sure I need to know by how much it was resized, right? – Mike Torrettinni Sep 21 '17 at 13:02
  • 1
    Then I guessed it right. Well, then you can do what I suggested. Collect only growths and when you finish the iteration, modify the `DestColumn` by the lowest, or highest value you collect. It's even better because you'll resize the column only once for the iteration (so there's no need for locking the column collection for updates). – Victoria Sep 21 '17 at 13:32
  • Now I know what you meant. Good suggestion, not to resize every time but get max width and resize once. Thank you! – Mike Torrettinni Sep 21 '17 at 18:16