Datagridview-Spalte per Drag & Drop mit Auto-horizontaler Scroll
-
04-10-2019 - |
Frage
Kann jemand bitte vorschlagen, wie soll ich Spalte per Drag-and-Drop implementieren (mit Autoscroll) Funktion in Datagridview. Ich weiß, ich kann den AllowUserToDragDrop Wahl des controll verwenden. Da jedoch meine Datagridview Steuerung relativ große Anzahl von Spalten hat, muß ich eine Auto-Scroll-Funktion, die die aktuelle Drag & Drop-Position folgt, so dass Benutzer die Zielspalt sehen (e) vor Abwurf. Ich habe die benutzerdefinierte Drag-and-Drop-Funktion implementiert, aber immer noch ich Problem habe Autoscroll Option zu aktivieren.
Lösung
Ich bin die folgende Klasse mit Auto-Blättern eine TTreeView. Die TScroller wird in der Erstellen des Rahmens erstellt, auf dem er sitzt, in dem TreeView vorbei. Es wird Zerstören im Rahmen der zerstört. Im OnDragOver des TreeView ich einfach anrufen 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;
Weitere Informationen: Wenn Sie mehr Kontrollen haben die Notwendigkeit Auto-Scrolling, müssten Sie eine TScroller pro Steuerelement erstellen. In diesem Fall wäre es wahrscheinlich eine Menge guter Sie die Leistung Ihrer App tut irgendeine Art von Beobachtern / beobachteten Mechanismus zu verwenden, um einen Timer zwischen allen Scrolling-Kontrollen zu teilen.
Andere Tipps
Sie könnten OnMouseMove handhaben, und programmatisch blättern entsprechend.