Scroll TTreeView while dragging over/near the edges

后端 未结 3 1063
滥情空心
滥情空心 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:56

    This is the code I use. It will work for any TWinControl descendent: list box, tree view, list view etc.

    type
      TAutoScrollTimer = class(TTimer)
      private
        FControl: TWinControl;
        FScrollCount: Integer;
        procedure InitialiseTimer;
        procedure Timer(Sender: TObject);
      public
        constructor Create(Control: TWinControl);
      end;
    
    { TAutoScrollTimer }
    
    constructor TAutoScrollTimer.Create(Control: TWinControl);
    begin
      inherited Create(Control);
      FControl := Control;
      InitialiseTimer;
    end;
    
    procedure TAutoScrollTimer.InitialiseTimer;
    begin
      FScrollCount := 0;
      Interval := 250;
      Enabled := True;
      OnTimer := Timer;
    end;
    
    procedure TAutoScrollTimer.Timer(Sender: TObject);
    
      procedure DoScroll;
      var
        WindowEdgeTolerance: Integer;
        Pos: TPoint;
      begin
        WindowEdgeTolerance := Min(25, FControl.Height div 4);
        GetCursorPos(Pos);
        Pos := FControl.ScreenToClient(Pos);
        if not InRange(Pos.X, 0, FControl.Width) then begin
          exit;
        end;
        if Pos.YFControl.Height-WindowEdgeTolerance then begin
          SendMessage(FControl.Handle, WM_VSCROLL, SB_LINEDOWN, 0);
        end else begin
          InitialiseTimer;
          exit;
        end;
    
        if FScrollCount<50 then begin
          inc(FScrollCount);
          if FScrollCount mod 5=0 then begin
            //speed up the scrolling by reducing the timer interval
            Interval := MulDiv(Interval, 3, 4);
          end;
        end;
    
        if Win32MajorVersion<6 then begin
          //in XP we need to clear up transient "fluff"; results in flickering so only do it in XP where it is needed
          FControl.Invalidate;
        end;
      end;
    
    begin
      if Mouse.IsDragging then begin
        DoScroll;
      end else begin
        Free;
      end;
    end;
    

    Then to use it you add an OnStartDrag event handler for the control and implement it like this:

    procedure TMyForm.SomeControlStartDrag(Sender: TObject; var DragObject: TDragObject);
    begin
      TAutoScrollTimer.Create(Sender as TWinControl);
    end;
    

提交回复
热议问题