DataGridView Columna de arrastrar y soltar con desplazamiento automático horizontal
-
04-10-2019 - |
Pregunta
Puede alguien por favor sugerir cómo debería implementar arrastrar y soltar la columna (con desplazamiento automático) en función DataGridView. Sé que puedo utilizar la opción AllowUserToDragDrop del controll. Sin embargo, desde mi control DataGridView tiene relativamente gran número de columnas, necesito una función de desplazamiento automático que sigue a la posición actual de arrastrar y soltar para que los usuarios puedan ver la columna de destino de la (s) antes de caer. He implementado el arrastre de encargo y soltar, pero todavía estoy teniendo problemas para activar la opción de desplazamiento automático.
Solución
Estoy utilizando la siguiente clase que se desplace automáticamente un TTreeView. El TScroller se crea en el marco de la Creación en la que se asienta, que pasa en el TreeView. Se destruye en el marco de destruir. En el OnDragOver del TreeView simplemente llamar MyDragScroller.Scroll (Estado);
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;
Notas: Si usted tiene más controles que necesitan auto-desplazamiento, lo que se necesita para crear un TScroller por el control. En ese caso, probablemente haría el rendimiento de la aplicación mucho bien a utilizar algún tipo de mecanismo de observador / observado que compartir un contador de tiempo entre todos los controles de desplazamiento.
Otros consejos
Se puede manejar OnMouseMove y programáticamente desplazamiento en consecuencia.