Scroll TTreeView while dragging over/near the edges

后端 未结 3 1059
滥情空心
滥情空心 2020-12-29 14:18

I have a TTreeView that can have lots of nodes, when a lot of nodes are expanded the tree uses a lot of screen space.

Now suppose I want to drag a node that is near

3条回答
  •  独厮守ぢ
    2020-12-29 14:53

    Here's an alternative based on the fact that the selected node always automatically scrolls in view.

    type
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        TreeView2: TTreeView;
        procedure TreeViewDragOver(Sender, Source: TObject; X, Y: Integer;
          State: TDragState; var Accept: Boolean);
        procedure TreeViewEndDrag(Sender, Target: TObject; X, Y: Integer);
        procedure TreeViewMouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
      private
        FDragNode: TTreeNode;
        FNodeHeight: Integer;
      end;
    
    ...
    
    procedure TForm1.TreeViewMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      with TTreeView(Sender) do
      begin
        FDragNode := GetNodeAt(X, Y);
        if FDragNode <> nil then
        begin
          Selected := FDragNode;
          with FDragNode.DisplayRect(False) do
            FNodeHeight := Bottom - Top;
          BeginDrag(False, Mouse.DragThreshold);
        end;
      end;
    end;
    
    procedure TForm1.TreeViewDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    var
      Pt: TPoint;
      DropNode: TTreeNode;
    begin
      Accept := Source is TTreeView;
      if Accept then
        with TTreeView(Source) do
        begin
          if Sender <> Source then
            Pt := ScreenToClient(Mouse.CursorPos)
          else
            Pt := Point(X, Y);
          if Pt.Y < FNodeHeight then
            DropNode := Selected.GetPrevVisible
          else if Pt.Y > (ClientHeight - FNodeHeight) then
            DropNode := Selected.GetNextVisible
          else
            DropNode := GetNodeAt(Pt.X, Pt.Y);
          if DropNode <> nil then
            Selected := DropNode;
        end;
    end;
    
    procedure TForm1.TreeViewEndDrag(Sender, Target: TObject; X, Y: Integer);
    var
      DropNode: TTreeNode;
    begin
      with TTreeView(Sender) do
        if Target <> nil then
        begin
          DropNode := Selected;
          DropNode := Items.Insert(DropNode, '');
          DropNode.Assign(FDragNode);
          Selected := DropNode;
          Items.Delete(FDragNode);
        end
        else
          Selected := FDragNode;
    end;
    

    You may want to link the OnDragOver event handler to the parent of the TreeView too, which results in scrolling ánd dropping when the mouse is outside the TreeView. If you dó want the scrolling, but not the dropping when the mouse is outside the TreeView, then check if Target = Sender in the OnEndDrag event handler.

提交回复
热议问题