Delphi、TVirtualStringTree、WM_SIZE 调整列大小时的事件

Delphi, TVirtualStringTree, WM_SIZE events when resizing columns

我有一个 TVirtualStringTree class 的后代,使用我自己的自动调整列大小程序。为了使其在控件大小更改时起作用,我覆盖了 Resize 过程:

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;

一切正常,除了一件事:手动调整列的大小(通过 header 上的鼠标)而不更改控件的实际大小会导致生成不需要的 WM_SIZE 具有不同 LParams(控件大小)的事件.因此 Resize 被调用并且列自动调整它们的宽度,我不是故意的。如何让 autosize 只在控件宽度实际改变时才起作用?

您可以添加一个布尔标志 FColumnResize,您在 DoColumnResize 方法中将其设置为 True

Resize 方法中检查标志,即:

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;

另一个选项而不是覆盖 DoColumnResize 可能更好的做法是在 DoHeaderMouseDown 中覆盖并将 FColumnResize 设置为 True,然后返回到 False DoHeaderMouseUp。在这种情况下,删除 Resize 方法中的 FColumnResize := False