尽管使用Perform发送消息,树视图中的项目高度不会改变

问题描述 投票:1回答:2

我有一个树状视图作为主菜单。程序启动后,我添加了新的子项。

然后我做TreeView1.Perform(TVM_SETITEMHEIGHT, 28, 0);

在设计时,我将Form的Position属性设置为poDesigned。如果在运行时执行Position := poScreenCenter;,为什么TreeView1.Perform无法正常工作?

这是我的代码:

procedure TForm1.FormCreate(Sender: TObject);
begin
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu1');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu2');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu3');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu4');
  TreeView1.Perform(TVM_SETITEMHEIGHT, 28, 0);
  Position:=poScreenCenter;
end;
delphi treeview height
2个回答
4
投票

问题是,设置窗体的Position属性会导致调用RecreateWnd。 RecreateWnd意味着销毁Windows屏幕对象并从头开始构建它。似乎需要(或最简单的方法)来完全实现更改此属性的所有效果。窗口句柄的创建并不少见:例如更改窗体的BorderStyle甚至是Edit控件的BorderStyle都会导致调用RecreateWnd。

RecreateWnd级联为重新创建所有子窗口控件,也就是重新创建TreeView。通常,组件从其内部(属性,私有数据)知道如何重新创建自身。例如:TreeView在句柄销毁之前将其节点保存到临时内存流,并在句柄重新创建后将其重新加载。

所以,应该归咎于谁:窗体的Position属性,TreeView或两者都不是?如果没有TreeView的ItemHeight属性,则必须手动发送WinAPI消息。这是对未由VCL注册的控件的修改。到目前为止,解释了为什么会发生这种情况。

最佳解决方案是确保每次重新创建TreeView时都完成了自定义。不幸的是,没有活动可用。您将需要覆盖CreateWnd(请参见下面的更新)。但是,当您保留Ctl3D和BorderStyle属性不变时,也可以在父级级别控制它。我不得不重写CM_ShowingChanged,因为不幸的是,在TForm1.CreateWnd之后TreeView尚未完全重建:

TForm1 = class(TForm)
  TreeView1: TTreeView;
  ...
private
  procedure CMShowingChanged(var Message: TMessage);
    message CM_SHOWINGCHANGED;
end;

procedure TForm1.CMShowingChanged(var Message: TMessage);
begin
  inherited;
  TreeView1.Perform(TVM_SETITEMHEIGHT, 28, 0);
end;

更新:

按照下面的注释的要求,这是使用重写的TTreeView.CreateWnd的解决方案:

unit Unit1;

interface

uses
  Windows, Classes, Controls, Forms, StdCtrls, ComCtrls, CommCtrl, XPMan;

type
  TTreeView = class(ComCtrls.TTreeView)
  protected
    procedure CreateWnd; override;
  end;

  TForm1 = class(TForm)
    TreeView1: TTreeView;
    XPManifest1: TXPManifest;
    procedure FormCreate(Sender: TObject);
  end;

implementation

{$R *.dfm}

{ TTreeView }

procedure TTreeView.CreateWnd;
begin
  inherited CreateWnd;
  Perform(TVM_SETITEMHEIGHT, 38, 0);
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu1');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu2');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu3');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu4');
  Position := poScreenCenter;
end;

end.

并且,如果您不喜欢继承TTreeView,则重写该窗体的CreateWnd,但是在这种情况下,您需要按Andreas Rejbrand的回答调用HandleNeeded:

unit Unit1;

interface

uses
  Windows, Classes, Controls, Forms, StdCtrls, ComCtrls, CommCtrl, XPMan;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    XPManifest1: TXPManifest;
    procedure FormCreate(Sender: TObject);
  protected
    procedure CreateWnd; override;
  end;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu1');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu2');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu3');
  TreeView1.Items.AddChild(TreeView1.Items.Item[0],'Sub Menu4');
  Position := poScreenCenter;
end;

procedure TForm1.CreateWnd;
begin
  inherited CreateWnd;
  TreeView1.HandleNeeded;
  TreeView1.Perform(TVM_SETITEMHEIGHT, 38, 0);
end;

end.

8
投票

NGLN的答案给出了问题的解释。

[如果您只需要设置树视图项目的高度,则同时设置Position(或将导致重新创建窗口(从技术角度而言)的表单的任何其他属性),你可以做

procedure TForm1.FormCreate(Sender: TObject);
begin
  Position := poDesigned;
  TreeView1.HandleNeeded;
  TreeView1.Perform(TVM_SETITEMHEIGHT, 28, 0);
end;
© www.soinside.com 2019 - 2024. All rights reserved.