delphitvirtualstringtree

Delphi, TVirtualStringTree, WM_SIZE events when resizing columns


I have a descendant of TVirtualStringTree class with my own autosizing columns procedure. To make it work whenever the size of the control is changed I have overriden the Resize procedure:

type
  TMyVirtualStringTree = class(TVirtualStringTree)
  protected
    procedure Resize; override;
  end;
.....
procedure TMyVirtualStringTree.Resize;
var
  cb: Integer;
begin
  inherited;
  if Header.Columns.Count > 0 then
    for cb := 0 to Header.Columns.Count - 1 do
      Header.Columns[cb].Width := round((Width - 20) / Header.Columns.Count);
end;

Everything works fine except one thing: resizing columns manually (by mouse on the header) without changing actual size of the control causes generation of unwanted WM_SIZE events with different LParams (control size). And thus Resize is called and columns automatically adjust their width which I didn't mean them to. How to make autosize work only when the control width is actually changed?


Solution

  • You can add a Boolean flag FColumnResize, which you set to True in the DoColumnResize method.

    In the Resize method check for the flag i.e:

    type
      TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
      protected
        FColumnResize: Boolean;
        procedure Resize; override;
        procedure DoColumnResize(Column: TColumnIndex); override;
      end;
    
    ...
    
    procedure TVirtualStringTree.DoColumnResize(Column: TColumnIndex);
    begin
      inherited;
      FColumnResize := True;
    end;
    
    procedure TVirtualStringTree.Resize;
    var
      cb: Integer;
    begin
      inherited;
      if not FColumnResize then
      begin 
        Header.Columns.BeginUpdate; { Important: do not trigger OnColumnResize }
        try
          if Header.Columns.Count > 0 then
            for cb := 0 to Header.Columns.Count - 1 do
              Header.Columns[cb].Width := round((Width - 20) / Header.Columns.Count);
        finally
          Header.Columns.EndUpdate;
        end;
      end;
      FColumnResize := False;
    end;
    

    Another option instead of overriding DoColumnResize it is probably better to override and set FColumnResize to True in DoHeaderMouseDown, and back to False in DoHeaderMouseUp. in that case remove the FColumnResize := False in the Resize method.