unit uNode;interface
uses
ComCtrls,Menus,Controls,Messages;
type
  TCNode=class(TTreeNode)
  private
    FPop:TPopupMenu;
    FItem:TMenuItem;
    procedure RButtonDown(var Message:TMessage);message WM_RBUTTONDOWN;
  public
    constructor create();
end;
implementation{ TCNode }constructor TCNode.create;
begin
  inherited create(nil);
  FPop:=TPopupMenu.Create(nil);
  FItem:=TMenuItem.Create(FPop);
  FItem.Caption:='复制';
end;procedure TCNode.RButtonDown(var Message: TMessage);
begin
  FPop.Popup(200,200);
end;end.
//添加到TreeView控件上是可以的,但是拦截鼠标右键按下弹出"复制"菜单没有效果
//再想想TTreeNode在使用的时候是不需要Create创建的,但我写的这个有Constuctor,
//单步调试时就没有执行Constuctor
//我想封装的实现,只能继承TTreeView来实现吗?

解决方案 »

  1.   

    一般带有弹出菜单的都是控件,而TTreeNode本身不属于控件,如果要简单的实现,最好从TTreeView继承,否则与自己写一个控件没有区别,当然也有实现的办法,就是从TComponent继承一个控件,并组合TTreeNode与TPopupMenu
      

  2.   

    看了一下VCL代码,发现Delphi的设计还是比较牛B的!你不用继承TreeView的,因为TreeView有个OnCreateNodeClass
    事件可以满足你的要求,你只要如下就可以了把你的TCNode给创建好的TreeView:
    procedure TForm1.TreeView1CreateNodeClass(Sender: TCustomTreeView;
      var NodeClass: TTreeNodeClass);
    begin
      NodeClass := TCNode;
    end;
    虽然是回答问题,但是自己也学会了一招!爽!
      

  3.   

    不明白楼上的意思我只是说消息拦截不成功,
    至于自定义的TCNode还是能添加到TreeView上的,
    你自己可以测试.
      

  4.   

    unit Unit3;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ComCtrls, Menus;type
      TForm3 = class(TForm)
        NodeMenu: TPopupMenu;
        TreeMenu: TPopupMenu;
        ree1: TMenuItem;
        Node1: TMenuItem;
        TreeView1: TTreeView;
        procedure TreeView1CreateNodeClass(Sender: TCustomTreeView;
          var NodeClass: TTreeNodeClass);
        procedure TreeView1ContextPopup(Sender: TObject; MousePos: TPoint;
          var Handled: Boolean);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;  TUserTreeNode = class(TTreeNode)
        private
          FPopupMenu: TPopupMenu;
        public
          property PopupMenu: TPopupMenu read FPopupMenu write FPopupMenu;
      end;var
      Form3: TForm3;implementation{$R *.dfm}procedure TForm3.FormCreate(Sender: TObject);
    var
      Node: TTreeNode;
      I: Integer;
    begin  TreeView1.PopupMenu := TreeMenu;  for I := 0 to TreeView1.Items.Count - 1 do
        begin
          Node := TreeView1.Items.Item[I];
          if Node is TUserTreeNode then
            TUserTreeNode(Node).PopupMenu := NodeMenu;
        end;    
    end;procedure TForm3.TreeView1ContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
    var
      Node: TTreeNode;
    begin
      //
      Node := TreeView1.GetNodeAt(MousePos.X,MousePos.Y);
      if Node = Nil then
        Exit;
      if Not (Node is TUserTreeNode) then
        Exit;  if TUserTreeNode(Node).PopupMenu = Nil then
        Exit;
      try
        MousePos := TreeView1.ClientToScreen(MousePos);
        TUserTreeNode(Node).PopupMenu.Popup(MousePos.X,MousePos.Y);
      Except
        Exit;
      end;
      Handled := True;
    end;procedure TForm3.TreeView1CreateNodeClass(Sender: TCustomTreeView;
      var NodeClass: TTreeNodeClass);
    begin
      NodeClass := TUserTreeNode;
    end;end.
      

  5.   

    不是控件也可以popu出来的unit Unit2;interface
    uses
      menus,classes;
    type
      Ta=class
      private
        FPop:TPopupMenu;
        FItem:TMenuItem;
        FAOwner:TComponent;
      protected  public
        sname:string;
        procedure pop(x,y:integer);
        constructor create(AOwner:TComponent);
    end;
    implementation{ Ta }constructor Ta.create(AOwner:TComponent);
    begin
      FAOwner:=AOwner;
      FPop:=TPopupMenu.Create(AOwner);
      FItem:=TMenuItem.Create(AOwner);
      FItem.Caption:='复制';
      FPop.Items.Add(FItem);
    end;procedure Ta.pop(x, y: integer);
    begin
      FPop.Popup(x,y);
    end;unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ComCtrls,Unit2, StdCtrls;type
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      a:Ta;
      pt:TPoint;
    begin
      pt.X:=button1.Left;
      pt.Y:=button1.Top;
      pt:=ClientToScreen(pt);
      a:=Ta.create(self);
      a.pop(pt.X,pt.Y);
    end;end.//关键的问题是消息处理,是不是TTreeNode不能处理消息?可能
      

  6.   

    哎啊,没有仔细看你。看来我的答案和你的问题不相干了!呵呵~
    为了挽回点颜面,说明一下:
    1、构造函数constructor TCNode.create 没有执行没关系,就不用构造函数;你访问FPop时,可以判定是否为空,
      为空你创建就可以了,建议封装成TCNode的属性PopupMenu
    2、TTreeNode不是TWinControl,没有WM_RBUTTONDOWN消息截获的,所以你必须要继承TTreeView的,处理WM_RBUTTONDOWN
     看当前的Selected节点是不是TCNode,是的话弹出TCNode.PopupMenu
      

  7.   

    TPopMenu也是可以继承的,并且可以动态创建,你可以在ContextPopup事件当中对Node的Data属性进行处理,从而使得某些Menu选项为Enabled/Disabled,Visible/Invisible.
      

  8.   

    其实,你这个要求没有必要重新创建节点了。
    你给TTreeView绑定一个PopupMenu;在PopupMenu的OnPopup事件里判断
    TreeView1.Selected的类型,修改PopupMenu相应菜单项和事件应该就
    可以了
      

  9.   

    其实,你这个要求没有必要重新创建节点了。 
    你给TTreeView绑定一个PopupMenu;在PopupMenu的OnPopup事件里判断 
    TreeView1.Selected的节点类型,修改PopupMenu相应菜单项Caption和事件(OnClick)应该就 
    可以了