【问题标题】:Delphi, TVirtualStringTree, WM_SIZE events when resizing columns调整列大小时的 Delphi、TVirtualStringTree、WM_SIZE 事件
【发布时间】:2019-04-29 20:05:44
【问题描述】:

我有一个 TVirtualStringTree 类的后代,我有自己的自动调整列大小的过程。为了让它在控件大小发生变化时工作,我重写了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;

除了一件事之外,一切都很好:手动调整列的大小(通过鼠标在标题上)而不改变控件的实际大小会导致生成具有不同 LParam(控件大小)的不需要的 WM_SIZE 事件。因此,Resize 被调用,列会自动调整它们的宽度,我不是故意的。如何仅在实际更改控件宽度时才使自动调整大小起作用?

【问题讨论】:

  • 对不起,我不知道如何使问题更清楚。我希望只有在控件本身实际调整大小时才自动更改列的宽度,而不是在手动调整其中一列的大小时。
  • 我相信 Molochnik 希望在调整整个组件大小时调整列的大小,但阻止用户单独调整它们的大小。
  • 好的,例如,这样会更好。假设树宽为 300 像素,3 个自动调整大小的列,每列的宽度为 100 像素。我调整窗口大小,树变成 600 px 宽度。每列 - 200 像素。完美的。现在我认为第二列太窄并尝试手动增加其大小以使其宽度为 300 像素(因此列的宽度为 200、300 和 200 像素),当然应该出现水平滚动条导致所有列(700 像素)不适合控件大小(600 像素)。最后一部分不起作用 - 导致生成 WM_SIZE,调用调整大小并且所有列的宽度再次为 200 像素。
  • 好的,完成

标签: delphi tvirtualstringtree


【解决方案1】:

您可以添加一个布尔标志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 的另一个选项可能更好的是覆盖并将FColumnResize 设置为DoHeaderMouseDown 中的True,然后返回DoHeaderMouseUp 中的False。在这种情况下,删除 Resize 方法中的 FColumnResize := False

【讨论】:

  • 它工作正常,谢谢,只有一个缺陷:在手动更改列宽之后,第一次调用 Resize 不会自动调整列大小导致 FColumnResize=true。如果有很多 WM_SIZE 事件(例如,当您通过鼠标逐渐调整窗体大小来调整树的大小时)这没什么大不了的。但是,如果它只有一个 WM_SIZE 事件(例如,当您通过移动外部拆分器来调整树的大小时)树仅在第二次拆分器移动后响应。
  • 我明白了。我没有彻底测试这个。您可以在DoHeaderMouseUp 中将FColumnResize 设置为False。我认为这个想法很明确。
  • 谢谢,但也应该使用 DoColumnResize 覆盖 DoHeaderMouseDown 因为当不仅通过鼠标调整列大小而且还通过编程方式调整列大小时调用 DoColumnResize。
  • 可能更好:) 在这种情况下删除FColumnResize := False 方法中的Resize
猜你喜欢
  • 1970-01-01
  • 2014-05-31
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-30
  • 1970-01-01
相关资源
最近更新 更多