0

谁能建议我应该如何在 DataGridView 中实现列拖放(自动滚动)功能。我知道我可以使用控件的 AllowUserToDragDrop 选项。但是,由于我的 datagridview 控件的列数相对较多,因此我需要一个跟随当前拖放位置的自动滚动功能,以便用户在拖放之前可以看到目标列。我已经实现了自定义拖放功能,但我仍然无法启用自动滚动选项。

4

2 回答 2

1

我正在使用以下类来自动滚动 TTreeView。TScroller 是在它所在的 Frame 的 Create 中创建的,传入 TreeView。它在框架的 Destroy 中被销毁。在 TreeView 的 OnDragOver 中,我只需调用 MyDragScroller.Scroll(State);

type
  TScroller = class(TObject)
  private
    MyTimer: TTimer;
    FControl: TWinControl;
    FSensitiveSize: Integer;
  protected
    procedure HandleTimer(Sender: TObject);
  public
    constructor Create(aControl: TWinControl);
    destructor Destroy; override;

    procedure Scroll(const aState: TDragState);
  end;

implementation

{ TScroller }

constructor TScroller.Create(aControl: TWinControl);
begin
  inherited Create;
  MyTimer := TTimer.Create(nil);
  MyTimer.Enabled := False;
  MyTimer.Interval := 20; // Not too short, otherwise scrolling flashes by.
  MyTimer.OnTimer := HandleTimer;

  FControl := aControl;
  // Width/Height from edge of FControl within which the mouse has to be for
  // automatic scrolling to occur. By default it is the width of a vertical scrollbar.
  FSensitiveSize := GetSystemMetrics(SM_CXVSCROLL);
end;

destructor TScroller.Destroy;
begin
  FreeAndNil(MyTimer);
  FControl := nil;
  inherited;
end;

procedure TScroller.HandleTimer(Sender: TObject);
var
  MousePos: TPoint;
  MouseX: Integer;
  MouseY: Integer;

  function _MouseInSensitiveSize: Boolean;
  begin

    MousePos := FControl.ScreenToClient(Mouse.CursorPos);
    MouseY := MousePos.Y;
    MouseX := MousePos.X;

    Result :=
         ((MouseY >= 0) and (MouseY < FSensitiveSize))
      or ((MouseY > FControl.ClientHeight - FSensitiveSize) and (MouseY <= FControl.ClientHeight))
      or ((MouseX >= 0) and (MouseX < FSensitiveSize))
      or ((MouseX > FControl.ClientWidth - FSensitiveSize) and (MouseX <= FControl.ClientWidth))
    ;

  end;
begin
  if Mouse.IsDragging and _MouseInSensitiveSize then begin
    if MouseY < FSensitiveSize then begin
      FControl.Perform(WM_VSCROLL, SB_LINEUP, 0);
    end else if MouseY > FControl.ClientHeight - FSensitiveSize then begin
      FControl.Perform(WM_VSCROLL, SB_LINEDOWN, 0);
    end;

    if MouseX < FSensitiveSize then begin
      FControl.Perform(WM_HSCROLL, SB_LINELEFT, 0);
    end else if MouseX > FControl.ClientWidth - FSensitiveSize then begin
      FControl.Perform(WM_HSCROLL, SB_LINERIGHT, 0);
    end;
  end else begin
    MyTimer.Enabled := False;
  end;
end;

procedure TScroller.Scroll(const aState: TDragState);
begin
  if not Mouse.IsDragging then Exit;  // Only scroll while dragging.
  if not (aState in [dsDragMove]) then Exit; // No use scrolling on a dsDragLeave and not nice to do so on a dsDragEnter.

  MyTimer.Enabled := True;
end;

注意:如果您有更多需要自动滚动的控件,则需要为每个控件创建一个 TScroller。在这种情况下,使用某种观察者/被观察机制在所有滚动控件之间共享计时器可能会对您的应用程序的性能产生很大的好处。

于 2010-05-29T15:13:28.827 回答
0

您可以处理 OnMouseMove,并以编程方式相应地滚动。

于 2010-05-20T21:08:12.803 回答