尽管使用"执行"发送消息,但树视图中的项目高度不会更改

max*_*fax 1 delphi treeview height

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

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

在设计时我将Form的Position属性设置为poDesigned.为什么TreeView1.Perform Position在运行时没有工作?

请查看此问题的视频:http://liga-installer.realservers.info/tv.mp4

这是我的代码:

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;
Run Code Online (Sandbox Code Playgroud)

And*_*and 8

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

如果您只需要设置Position(或任何其他属性,将导致窗口(在技术意义上)重新创建)同时您设置树视图项的高度,您可以做

procedure TForm1.FormCreate(Sender: TObject);
begin
  Position := poDesigned;
  TreeView1.HandleNeeded;
  TreeView1.Perform(TVM_SETITEMHEIGHT, 28, 0);
end;
Run Code Online (Sandbox Code Playgroud)


NGL*_*GLN 5

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

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

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

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

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;
Run Code Online (Sandbox Code Playgroud)

更新:

根据以下注释的要求,这是使用重写的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.
Run Code Online (Sandbox Code Playgroud)

而且,如果您不想继承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.
Run Code Online (Sandbox Code Playgroud)