Mirror

Implement autoscroll for a TScrollbox when dragging (Views: 300)


Problem/Question/Abstract:

I have a form with a TScrollBox on it. At runtime I dynamically add any number of a custom control I created. These controls need to interact via Drag and Drop, however, when I drag from one control and move to the edge of the TScrollBox it doesn't automatically scroll to reveal the additional controls.

Answer:

Add a handler to the forms OnDragOver event so you get aware when the user drags the mouse outside the scrollbox. You can the start a timer that fires scroll messages at the scrollbox to get it to move. In the example below all edits are on the scrollbox and share the edit drag handlers. The timer is set to 100 msecs and initially disabled.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Buttons, ComCtrls, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    Edit6: TEdit;
    Edit7: TEdit;
    Edit8: TEdit;
    Edit9: TEdit;
    Edit10: TEdit;
    Edit11: TEdit;
    Edit12: TEdit;
    Edit13: TEdit;
    Label1: TLabel;
    Timer1: TTimer;
    procedure Edit1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState;
      var Accept: Boolean);
    procedure Edit1DragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure Timer1Timer(Sender: TObject);
    procedure FormDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState;
      var Accept: Boolean);
  private
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Edit1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := Source is TEdit and (Sender <> Source);
end;

procedure TForm1.Edit1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
  (Sender as TEdit).SelText := (Source as TEdit).Text;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  pt: TPoint;
begin
  {figure out where the mouse is}
  GetCursorPos(pt);
  pt := ScreenToClient(pt);
  with scrollbox1.boundsrect, pt do
    if (x > left) and (x < right) then
    begin
      if y < top then
        scrollbox1.perform(WM_VSCROLL, SB_LINEUP, 0)
      else if y > bottom then
        scrollbox1.perform(WM_VSCROLL, SB_LINEDOWN, 0)
      else
        timer1.enabled := false;
    end
    else
      timer1.enabled := false;
end;

procedure TForm1.FormDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  accept := false;
  if State = dsDragLeave then
    timer1.enabled := false
  else if (source is TEdit) then
  begin
    {Figure if mouse is above or below the scrollbox, that determines
    whether we enable the scroll timer.}
    with scrollbox1.boundsrect do
      timer1.enabled := (x > left) and (x < right) and ((y < top) or (y > bottom));
  end;
end;

end.

<< Back to main page