Question

Quelqu'un peut-il s'il vous plaît suggérer comment dois-je mettre en œuvre la fonction glisser-déposer colonne (avec défilement automatique) dans DataGridView. Je sais que je peux utiliser l'option AllowUserToDragDrop du controll. Cependant, étant donné que mon contrôle DataGridView a un nombre relativement important de colonnes, ai-je besoin d'une fonction de défilement automatique qui suit la position actuelle glisser-déposer afin que les utilisateurs peuvent voir la colonne de destination (s) avant de laisser tomber. Je l'ai mis en œuvre la fonction glisser-déposer sur mesure mais j'ai problème pour activer l'option automatique.

Était-ce utile?

La solution

J'utilise la classe suivante pour faire défiler automatiquement une TTreeView. Le TScroller est créé dans la Création du cadre sur lequel il se trouve, en passant dans le TreeView. Il est détruit dans le cadre de Détruis. Dans le OnDragOver du TreeView j'appeler simplement MyDragScroller.Scroll (État);

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;

Notes: Si vous avez plus de contrôles que le défilement automatique besoin, vous devez créer un TScroller par commande. Dans ce cas, il serait probablement faire les performances de votre application beaucoup de bien d'utiliser une sorte d'observateur / mécanisme observé pour partager une minuterie entre toutes les commandes de défilement.

Autres conseils

Vous pouvez gérer OnMouseMove et programatically défilement en conséquence.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top