2010-05-20 2 views
0

DataGridView에서 열 끌기 및 놓기 (자동 스크롤 사용) 기능을 구현하는 방법을 제안 할 수있는 사람이 누구나 있습니다. 나는 controlI의 AllowUserToDragDrop 옵션을 사용할 수 있다는 것을 알고있다. 그러나, 내 datagridview 컨트롤의 열 수가 비교적 많기 때문에 사용자가 놓기 전에 대상 열을 볼 수 있도록 현재 끌어서 놓기 위치를 따르는 자동 스크롤 기능이 필요합니다. 사용자 지정 끌어서 놓기 기능을 구현했지만 여전히 자동 스크롤 옵션을 사용할 수있는 문제가 있습니다.DataGridView 자동 가로 스크롤을 사용하는 열 끌어서 놓기

답변

1

다음 클래스를 사용하여 TTreeView를 자동 스크롤합니다. TScroller는 TreeView를 통해 전달되는 Frame의 Create에서 생성됩니다. 그것은 프레임의 파괴에서 파괴됩니다. 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

+0

FirstDisplayedScrollingRowIndex 속성을 살펴 보셨습니까? – TreDubZedd

+0

예, 위의 지정된 이벤트에 FirstDisplayedColumnIndex를 사용했습니다. 자동 스크롤이 이런 방식으로 작동하기는하지만, 사용자가해야 할만큼 편리하지는 않습니다. – Bedasso