Domanda

Qualcuno può suggerire come dovrei implementare colonna di drag and drop (con scorrimento automatico) funzione in DataGridView. So che posso usare l'opzione AllowUserToDragDrop del controll. Tuttavia, dato che il mio controllo DataGridView ha relativamente elevato numero di colonne, ho bisogno di una funzione di scorrimento automatico che segue la posizione di drag-drop attuale in modo che gli utenti possono vedere la colonna di destinazione (s) prima di cadere. Ho implementato il trascinamento personalizzato e dispongono di calo, ma ancora sto avendo problemi per abilitare l'opzione di scorrimento automatico.

È stato utile?

Soluzione

Sto usando la seguente classe di auto-scorrere un TTreeView. Il TScroller viene creato nella Creazione del telaio su cui si siede, passando nel controllo TreeView. Viene distrutto nel telaio di distruggere. Nel OnDragOver del TreeView ho semplicemente chiamare MyDragScroller.Scroll (stato);

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;

Note: Se si dispone di più controlli che hanno bisogno di auto-scorrimento, si avrebbe bisogno di creare un TScroller per ogni controllo. In tal caso sarebbe probabilmente fare le prestazioni della vostra applicazione un sacco di bene di utilizzare una sorta di osservatore / meccanismo osservato per condividere un timer tra tutti i controlli di scorrimento.

Altri suggerimenti

Si potrebbe gestire OnMouseMove, e programmaticamente scorrimento di conseguenza.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top