2010-05-20 165 views
0

任何人都可以請建議我應該如何在DataGridView中實現列拖放(自動滾動)功能。我知道我可以使用controll的AllowUserToDragDrop選項。但是,由於我的datagridview控件的列數相對較多,因此我需要一個跟隨當前拖放位置的自動滾動功能,以便用戶在刪除之前可以看到目標列。我已經實現了自定義拖放功能,但仍然遇到問題以啓用自動滾動選項。DataGridView自動水平滾動列拖放

回答

1

我正在使用以下類來自動滾動TTreeView。 TScroller在它所在的框架的創建中創建,傳遞給TreeView。它在框架的毀滅中被摧毀。在TreeView的OnDragOver中,我只需調用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。在這種情況下,應用程序的性能很可能會使用某種觀察者/觀察機制在所有滾動控件之間共享計時器。

0

您可以處理OnMouseMove,並以編程方式相應地進行滾動。

+0

謝謝,我試過(其實我試過OnMouseMove和OnDragDrop事件)。它工作正常,但不能靈活地向前和向後滾動。你會推薦什麼水平滾動條的方法來分配當前的鼠標光標藥水? – Bedasso 2010-05-20 21:41:55

+0

你看過FirstDisplayedScrollingRowIndex屬性嗎? – TreDubZedd 2010-05-20 22:01:33

+0

是的,我在上面指定的事件上使用了FirstDisplayedColumnIndex。雖然自動滾動以這種方式工作,但它不像用戶應該那樣得心應手。 – Bedasso 2010-05-24 14:34:11