困惑,Treeview 的 Change 事件继承问题 ( 积分: 200 )

  • 主题发起人 主题发起人 dawuboy
  • 开始时间 开始时间
D

dawuboy

Unregistered / Unconfirmed
GUEST, unregistred user!
我做了一个控件,在主窗体调用MoveTo时控件代码中的OnChange事件触发了两次,而主窗体
中没有触发。问题代码如下:

代码:
//控件代码
unit MyTestTreeView;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, ComCtrls, CSIntf;

type
  TMyTestTreeView = class(TTreeView)
  protected
    procedure Change(Node: TTreeNode); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

{ TMyTestTreeView }

procedure TMyTestTreeView.Change(Node: TTreeNode);
begin
  inherited;
  CodeSite.SendMsg('控件代码中Change事件触发');
end;

constructor TMyTestTreeView.Create(AOwner: TComponent);
begin
  inherited;
  //
end;

destructor TMyTestTreeView.Destroy;
begin
  //
  inherited;
end;

end.

--------------------------------------------------------------------------------

代码:
//主窗体代码
procedure TForm1.btn2Click(Sender: TObject);
var
  Node: TTreeNode;
begin
  with MyTestTreeView1 do
  begin
    Node := Selected.getPrevSibling;
    if Node <> nil then
    begin
      Selected.MoveTo(Node, naInsert);
    end;
  end;
end;

procedure TForm1.MyTestTreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  CodeSite.SendMsg('主窗体中Change事件触发');
end;

请问是哪里出了问题?
 
我做了一个控件,在主窗体调用MoveTo时控件代码中的OnChange事件触发了两次,而主窗体
中没有触发。问题代码如下:

代码:
//控件代码
unit MyTestTreeView;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, ComCtrls, CSIntf;

type
  TMyTestTreeView = class(TTreeView)
  protected
    procedure Change(Node: TTreeNode); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

{ TMyTestTreeView }

procedure TMyTestTreeView.Change(Node: TTreeNode);
begin
  inherited;
  CodeSite.SendMsg('控件代码中Change事件触发');
end;

constructor TMyTestTreeView.Create(AOwner: TComponent);
begin
  inherited;
  //
end;

destructor TMyTestTreeView.Destroy;
begin
  //
  inherited;
end;

end.

--------------------------------------------------------------------------------

代码:
//主窗体代码
procedure TForm1.btn2Click(Sender: TObject);
var
  Node: TTreeNode;
begin
  with MyTestTreeView1 do
  begin
    Node := Selected.getPrevSibling;
    if Node <> nil then
    begin
      Selected.MoveTo(Node, naInsert);
    end;
  end;
end;

procedure TForm1.MyTestTreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  CodeSite.SendMsg('主窗体中Change事件触发');
end;

请问是哪里出了问题?
 
你在定义MyTestTreeView1的时候,是怎么定义的?
 
//主窗体源代码
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, MyTestTreeView, csintf;

type
TForm1 = class(TForm)
MyTestTreeView1: TMyTestTreeView;
btn2: TButton;
procedure btn2Click(Sender: TObject);
procedure MyTestTreeView1Change(Sender: TObject; Node: TTreeNode);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn2Click(Sender: TObject);
var
Node: TTreeNode;
begin
with MyTestTreeView1 do
begin
Node := Selected.getPrevSibling;
if Node <> nil then
begin
Selected.MoveTo(Node, naInsert);
end;
end;
end;

procedure TForm1.MyTestTreeView1Change(Sender: TObject; Node: TTreeNode);
begin
CodeSite.SendMsg('主窗体中Change事件触发');
end;

end.
 
按里说调用Moveto这个方法是不会出发 Change事件的。
从他的原码就可以知道了.
procedure TTreeNode.MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode);
var
AddMode: TAddMode;
Node: TTreeNode;
HItem: HTreeItem;
OldOnChanging: TTVChangingEvent;
OldOnChange: TTVChangedEvent;
begin
OldOnChanging := TreeView.OnChanging;//保存原有的正在改变的事件指针
OldOnChange := TreeView.OnChange;//保存原有的改变的事件指针
TreeView.OnChanging := nil;//清空正在改变的事件指针
TreeView.OnChange := nil;//清空改变的事件指针
//由以上就可是知道是不会触发Change事件了.
try
if (Destination = nil) or not Destination.HasAsParent(Self) then
begin
AddMode := taAdd;
if (Destination <> nil) and not (Mode in [naAddChild, naAddChildFirst]) then
Node := Destination.Parent else
Node := Destination;
case Mode of
naAdd,
naAddChild: AddMode := taAdd;
naAddFirst,
naAddChildFirst: AddMode := taAddFirst;
naInsert:
begin
Destination := Destination.GetPrevSibling;
if Destination = nil then AddMode := taAddFirst
else AddMode := taInsert;
end;
end;
if Node <> nil then
HItem := Node.ItemId else
HItem := nil;
if (Destination <> Self) then
InternalMove(Node, Destination, HItem, AddMode);
Node := Parent;
if Node <> nil then
begin
Node.HasChildren := True;
Node.Expanded := True;
end;
end;
finally
TreeView.OnChanging := OldOnChanging;//恢复正在改变的事件指针
TreeView.OnChange := OldOnChange;//恢复改变的事件指针
end;
end;
 
对啊,这几行好象不起作用似的。是不是我的继承代码不完善啊,请大家继续指点。
 
你加一行代码 node.Selected:=true;
看看能不能触发那个事。
 
在select.moveto();的下面!
 
谢谢xinxinhg的关注,代码已测试。意思是置移动目标节点状态为选中状态。选中节点改变,控件Change继承代码和主程序调用都可以正常触发。

但是我在主窗体只MoveTo后,主窗体OnChange事件没有改变,而控件Change代码显示当前节点从源节点跳到目标节点,又从目标节点跳到源节点,触发了两次。
 
procedure TMyTestTreeView.Change(Node: TTreeNode);
begin
CodeSite.SendMsg('控件代码中Change事件触发');//试试放到上面来呢
inherited;
end;
 
我的代码如下,完全正常啊
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls;

type
TMyTestTreeView = class(TTreeView)
protected
procedure Change(Node: TTreeNode); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure OnChange(Sender:TObject;Node:TTreeNode);
end;

var
Form1: TForm1;
MTT:TMyTestTreeView;

implementation

{$R *.DFM}
procedure TMyTestTreeView.Change(Node: TTreeNode);
begin
inherited;
showmessage('控件代码中Change事件触发');
end;

constructor TMyTestTreeView.Create(AOwner: TComponent);
begin
inherited;
//
end;

destructor TMyTestTreeView.Destroy;
begin
//
inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
MTT:=TMyTestTreeView.Create(self);
MTT.Parent:=self;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
MTT.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Node: TTreeNode;
begin
with MTT do
begin
Node := Selected.getPrevSibling;
if Node <> nil then
begin
Selected.MoveTo(Node, naInsert);
end;
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
Node: TTreeNode;
begin
Node:=TTreeNode.Create(MTT.Items);
MTT.Items.AddChild(Node,'wrl1');
Mtt.OnChange :=OnChange;
end;

procedure TForm1.OnChange(Sender:TObject;Node: TTreeNode);
begin
showmessage('shijiantest');
end;

end.
 
wrl_001的代码不行啊,执行MoveTo时还是控件Change继承代码触发两次而主窗体实例没有触发。
 
sorry,没看清楚就乱回,我试验的时候是直接点击来触发changed事件的,而不是用moveto
moveto的确不会触发原有的OnChange事件,但是自己重载的还会,
而会触发两次则是因为他在moveto的时候会先把焦点转到下个节点,然后转移自己到目标再把焦点转回来,这由测试得知,源代码我也看不懂
procedure TMyTestTreeView.Change(Node: TTreeNode);
begin
inherited;
showmessage('控件代码中Change事件触发'+#13+Node.Text);
end;
修改Change函数,并把TreeView.HideSelection :=False;就可以很清楚的看到了
暂时只有这些[:D]
 
dxDBTreeView 也存在这个问题。算了,绕过去,在Change继承代码中加判断。但是为什么会出现这种问题呢?
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
744
import
I
后退
顶部