当前位置:编程学习 > Delphi >>

Delphi类和组件 - TreeView 智能拖拽

属性:
  TreeView:需要实现拖拽功能的 TreeView,当把一个 TreeView
  指定给该属性后,这个 TreeView 的节点就具有智能拖拽功能了。
  DragMode = dmHotKeyDrag   // 通过快捷键才能拖拽
  HotKeyMoveNode = hkCtrl;  // 拖拽节点: Ctrl
  HotKeyCopyNode = hkShift; // 拖拽并复制节点:Shift
  HotKeyChildNode = hkAlt;  // 拖拽到子节点:Alt
  EnableRButtonDrag = True; // 允许右键拖拽,会弹出菜单

  Public 方法:
  AddNode:添加节点,根据 AddMode 决定添加的位置
  DeleteNode:删除节点,返回被删除节点临近的节点
  MoveNode:移动或复制节点,根据 MoveMode 决定移动方式

******************************************************* }

unit TreeViewManage;

interface

uses
  SysUtils, Windows, Classes, Controls, ComCtrls, Menus;

type
  TAttachMode = (amLast, amFirst, amChildLast, amChildFirst, amPrev,
    amNext, amAuto);

  { 控制拖拽方式的热键:禁止,Ctrl,Shift,Alt }
  THotKey = (hkNone, hkCtrl, hkShift, hkAlt);

  { 节点拖动方式:自动拖拽,热键拖拽,禁止拖拽 }
  TDragMode = (dmAutoDrag, dmHotKeyDrag, dmDisableDrag);

  TTreeViewDrager = class(TComponent)
  private
    FTreeView: TTreeView;
    FOldOnMouseDown: TMouseEvent;
    FOldOnMouseUp: TMouseEvent;
    FOldOnDragOver: TDragOverEvent;
    FOldOnDragDrop: TDragDropEvent;

    FDragMode: TDragMode; { 节点拖动方式 }
    FDragButton: TMouseButton; { 拖动节点的按钮 }
    FDropMenu: TPopupMenu; { 右键拖拽后的弹出菜单 }
    FMoveSourceNode: TTreeNode; { 移动的源节点 }
    FMoveTargetNode: TTreeNode; { 移动的目标节点 }
    FHotKeyMoveNode: Integer; { 拖动节点的热键 }
    FHotKeyCopyNode: Integer; { 复制节点的热键 }
    FHotKeyChildNode: Integer; { 拖动到子节点的热键 }
    FEnableRButtonDrag: Boolean; { 是否允许右键拖拽,右键拖拽会弹出菜单 }

    function GetTreeView: TCustomTreeView;
    procedure SetTreeView(Value: TCustomTreeView);
    function GetHotKeyMoveNode: THotKey;
    procedure SetHotKeyMoveNode(Key: THotKey);
    function GetHotKeyCopyNode: THotKey;
    procedure SetHotKeyCopyNode(Key: THotKey);
    function GetHotKeyChildNode: THotKey;
    procedure SetHotKeyChildNode(Key: THotKey);

    procedure MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer);
    procedure DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure DragDrop(Sender, Source: TObject; X, Y: Integer);
  protected
    function CreateDropMenu: TPopupMenu; virtual;
    procedure DragMenuEvent(Sender: TObject); virtual;
    function GetNewNode(RelativeNode: TTreeNode = nil; NodeName: string = '';
      AddMode: TAttachMode = amAuto): TTreeNode;
    function CloneNode(FromNode, ToNode: TTreeNode;
      MoveMode: TAttachMode = amAuto): TTreeNode;
    procedure CopyChildNodes(FromNode, ToNode: TTreeNode); virtual;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    function AddNode(RelativeNode: TTreeNode = nil; NodeName: string = '';
      AddMode: TAttachMode = amAuto): TTreeNode; virtual;
    function DeleteNode(RelativeNode: TTreeNode): TTreeNode; virtual;
    function MoveNode(FromNode, ToNode: TTreeNode;
      MoveMode: TAttachMode = amAuto; bCopy: Boolean = False)
      : TTreeNode; virtual;
  published
    property TreeView: TCustomTreeView read GetTreeView Write SetTreeView;
    property DragMode: TDragMode read FDragMode Write FDragMode
      default dmHotKeyDrag;
    property HotKeyMoveNode: THotKey read GetHotKeyMoveNode
      write SetHotKeyMoveNode default hkCtrl;
    property HotKeyCopyNode: THotKey read GetHotKeyCopyNode
      write SetHotKeyCopyNode default hkShift;
    property HotKeyChildNode: THotKey read GetHotKeyChildNode
      write SetHotKeyChildNode default hkAlt;
    property EnableRButtonDrag: Boolean read FEnableRButtonDrag
      write FEnableRButtonDrag default True;
  end;

const
  { 由于 Delphi 的 TreeView 所能管理的最大节点数为 65535,所以这里给出范围限制 }
  MaxNodeCount = 65535;

resourcestring
  Error_NodeOutOfRange = '警告:TreeView 节点数达到最大限制:%d,无法继续添加节点';

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TTreeViewDrager]);
end;

{ 判断按键是否被按下 }
function IsKeyDown(VK: Integer): Boolean;
begin
  Result := GetKeyState(VK) < 0;
end;

constructor TTreeViewDrager.Create(AOwner: TComponent);
begin
  inherited;
  FDragMode := dmHotKeyDrag;
  HotKeyMoveNode := hkCtrl;
  HotKeyCopyNode := hkShift;
  HotKeyChildNode := hkAlt;
  FDropMenu := CreateDropMenu;
  FEnableRButtonDrag := True;
end;

destructor TTreeViewDrager.Destroy;
begin
  FDropMenu.Free;
  inherited;
end;

{ ------------------------------------------------------------ }
{ 拖放后的弹出菜单 }
{ ------------------------------------------------------------ }

function TTreeViewDrager.CreateDropMenu: TPopupMenu;
const
  DropMenuName: array [1 .. 9] of PChar = ('移动到之前(&1)', '移动到之后(&2)',
    '移动到子节点最前(&5)', '移动到子节点最后(&6)', '-', '复制到之前(&A)', '复制到之后(&B)',
    '复制到子节点最前(&E)', '复制到子节点最后(&F)');
var
  I: Integer;
  NewItem: TMenuItem;
begin
  Result := TPopupMenu.Create(FTreeView);

  for I := Low(DropMenuName) to High(DropMenuName) do
  begin
    NewItem := TMenuItem.Create(FTreeView);
    NewItem.Tag := I;
    NewItem.OnClick := DragMenuEvent;
    NewItem.Caption := DropMenuName[I];
    Result.Items.Add(NewItem);
  end;
end;

procedure TTreeViewDrager.DragMenuEvent(Sender: TObject);
const
  MoveMode: array [1 .. 4] of TAttachMode = (amPrev, amNext, amChildFirst,
    amChildLast);
var
  bCopy: Boolean;
  Inde

补充:软件开发 , Delphi ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,