datagridview列列ドラッグアンドドロップで自動ホリゾントスクロールを使用します
-
04-10-2019 - |
質問
DatagridViewで列のドラッグアンドドロップ(自動スクロール付き)機能をどのように実装するかを提案できますか?コントロールのAlowusertOdRagDropオプションを使用できることは知っています。ただし、DatagridViewコントロールには比較的多数の列があるため、ドロップする前にユーザーが宛先列を見ることができるように、現在のドラッグドロップ位置に従って自動スクロール機能が必要です。カスタムドラッグアンドドロップ機能を実装しましたが、それでも自動スクロールオプションを有効にするための問題があります。
解決
次のクラスを使用して、Treeviewを自動スクロールしています。 Tscrollerは、ツリービューを通過するフレームの作成に作成されます。フレームの破壊で破壊されます。 TreeViewのオンドラゴーバーでは、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を作成する必要があります。その場合、アプリのパフォーマンスは、ある種のオブザーバー/観測メカニズムを使用して、すべてのスクロールコントロール間でタイマーを共有するために多くの良いことを行うでしょう。
他のヒント
OnMouseMoveを処理し、それに応じてプログラムでスクロールすることができます。
所属していません StackOverflow