为何不能覆盖方法!!??(100分)

  • 主题发起人 主题发起人 JohnsonGuo
  • 开始时间 开始时间
J

JohnsonGuo

Unregistered / Unconfirmed
GUEST, unregistred user!
请看以下代码:

type
TMyNode = class(TTreeNode)
public
procedure MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode); override;
end;

...

procedure TMyNode.MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode);
begin
inherited;
ShowMessage('永远都不会出现的对话框!');
end;

...

procedure TForm1.Button1Click(Sender: TObject);
var
Node: TMyNode;
begin
Node := TMyNode(TreeView1.Selected);
Node.MoveTo(TreeView1.Items[0], naAddChild);
end;

运行该程序,会发觉不会出现对话框!!!!

请高手指教,如何才能把TTreeNode.MoveTo方法覆盖掉????

注:到现在为止,我就只发现这个方法不能被覆盖,如果各路英雄有发现其他类也有类似
情况的话,敬请提出。
 
To htw:
我不知道你是在纸上谈兵,还是怎么样。
你试真了没有??我劝你还是打开delphi认真试试。
你写的东西和我写的东西根本没有本质区别!!!!

或许是我使用的版本和你使用的版本不同吧。我是在使用Delphi5
 
其实真正的原因是:
那个Node还是TTreeNode而不是TMyNode,
语句 Node := TMyNode(TreeView1.Selected);并不会把Node真正地转换为TMyNode,
使用TreeView.Items.Add/AddChile总是创建TTreeNode,所以你必须在这些地方显示地
创建TMyNode才能达到你的目的
 
在TTreeView里有 function CreateNode: TTreeNode; 可以覆盖,把这个方法改为创建
TMyNode会来得简单些
 
龙丹的方法好是好,但那几乎是重建整个 TTreeView 了

JohnsonGuo 兄能说说为什么要这么做吗?
也许可以用别的方法达到你的目的,比如 CN_NOTIFY
 
没有那么严重的,其实第二种方法非常简单:
type
TTreeView=class(ComCtrls.TTreeView) //必须位于TForm1的声明之前
protected
function CreateNode: TTreeNode; override;
end;
implementation
function TTreeView.CreateNode: TTreeNode;
begin
Result:=TMyNode.Create(Items);
end;
用了这个方法就不用去管别的了,一切OK
 
龙丹的说法无疑是正确的。也比较简单。不过的确是改动了整个TTreeView。
而且如果改动大的话,这种方法不是总是有效。这里有一个.pas文件和.dfm文件对treeView
的引用不同的问题,不定会出现什么毛病。Delphi推荐的作法是:
将TreeView从published域挪到Privide域,在Form的Create事件中手工将这个TreeView建立
上去。然后在实现部分重新修改TreeView的接口和实现,最好换一个控件类名。这样可以完
全避免冲突。
JohnsonGuo的目的无非是在移动节点时响应某个过程。思路上应该从事件入手。
为什么不用OnDragDrop事件呢?在ButtonClick事件中可以调用OnDragDrop的事件句柄呀?
 
龙丹的方法是可行的。但无疑要对整棵树进行改动。
不知是否有更好的方法呢?

To 940801:
我不能使用CN_NOTIFY。因为树控件似乎没有提供节点移动的通知。
并且,我要在节点移动之前作一定的预处理,所以我不能使用CN_NOTIFY

To barton:
我不是通过树控件的界面对节点进行移动,而且通过修改TTreeNode的方法,
让用户移动节点,所以是不会激发OnDragDrop事件的。而且我要把移动节点前
的预处理封装起来,所以我也不能在OnClick中去调用OnDragDrop,而必须从修改
其原有方法来处理。
 
一个办法,Items 属性不要 published 出来,不让用户用,
给 TreeView 写个 MoveTo 的方法,让用户用这个方法
 
我认为你没有理由只能用“修改其原有方法来处理”。如果真是这样,只能用龙丹的方法。
 
To barton:
确实没有覆盖该方法的必要,但我第一次遇到这类问题,好奇起来才发冋啊。
学多点东西很好啊。

To 940801:
不公布Items似乎不妥,别人还得通过Items来遍历树控件中的节点啊。
 
或者干脆你不Override它,直接reintroduce,再强制类型转换过去的时候就搞定了。[:D]
TMyNode = class(TTreeNode)
public
procedure MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode); reintroduce;
end;

这样你的目的就达到了。
 
To xianjun
看来你也是在纸上谈兵。不信你自己试试。
如果你在没有覆盖TTreeView.CreateNode的情况下,使用你
给出的代码,将会产生一个非法访问内存的异常!!!!
 
TO JohnsonGuo:
我回答这类贴子都是经过试验才写答案的。[:)]
我这执行下面和代码没有任何问题:
代码:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyNode = class(TTreeNode)
  public
    procedure MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode); reintroduce;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TMyNode }

procedure TMyNode.MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode);
begin
  Destination.Text := Destination.Text + IntToStr(Destination.AbsoluteIndex);
  inherited;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyNode(TreeView1.Selected).MoveTo(TreeView1.Items[0], naAddChild);
end;

end.
 
To xianjun
Oh, I'm sorry. 你的方法是正确的。我测试的时候是用如下原型:
function MoveTo(Destination: TMyNode; Mode: TNodeAttachMode); reintroduce; virtual;
呵呵。
 
多人接受答案了。
 
后退
顶部