1. Home
  2. Computing & Technology
  3. Delphi Programming
Moving the contest of a ScrollBox with mouse (like drag - drop)
How to move a TImage object in a ScrollBox with the mouse, like a drag and drop operation - without the scroll bars
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Drag and drop operations in Delphi
• Using Components
• Graphics programming

Recently, I was developing a project that included an image preview form. The code needed to display a picture (desktop screen shot) inside a TImage control. Since the image was larger than the form, I've placed the TImage control inside a ScrollBox component - to create a scrolling area and enable a user to use the scroll bars to "see" the entire picture.

All ok, but one of the users asked if he could use the mouse to drag (and drop) a picture inside this scrolling area - he was not happy with the scroll bars.

This article presents one of the answers to the question: how to move a TImage object in a ScrollBox with the mouse, like a Drag and Drop operation - without the scroll bars.

An example
To create a working environment for this article, start Delphi, drop the TScrollBox component on a form, and drop one TImage component inside a TScrollBox. Now, use the Object Inspector to set the Picture property and specify the image for the TImage component - make sure the dimensions of the image are larger than the width and height of the scroll box. Of course, set the AutoSize property to true; and place the image in the upper left corner of the Scroll Box (Left:=0; Top:=0).

All we have to do now, is to enable drag and drop for the Image inside the ScrollBox. The article "Drag and drop operations in Delphi" has all the "startup" code we need. In general, we have to create event handling code for three events:

  • TImage MouseDown : starts the dragging operation by setting Image.BeginDrag(True)
  • TScrollBox DragOver : we say "Accept := True" to signal that the TScrollBox can accept a dragged object (Timage)
  • TScrollBox DragDrop : we use it to specify what we want to happen when the user drops a TImage on (inside) TScrollBox.

A problem
Yes, there's always a problem. By default, dropping an object on some other object means that you pick the first object and move it by mouse to some point "over" the second object. However, in our scenario, you'll need to move the image slightly to either direction - this will result in a need to be able to drop the Image on "itself". Therefore, what we need is to create DragDrop and DragOver event handlers for both the ScrollBox and the Image.

Moving an image inside a ScrollBox Moving an image inside a ScrollBox

The (solution) code
First some code for the DragOver event:

procedure TForm1.MyDragOver
  (Sender, Source: TObject; 
  X, Y: Integer; State: TDragState; 
  var Accept: Boolean);
begin
  Accept := (Source is TImage);
end;

Second, the Image MouseDown event handler. We have to make sure we save the coordinates of the point where we have picked the image. The TheSpot variable is declared in the implementation var section as var TheSpot : TPoint;

procedure TForm1.Image1MouseDown
  (Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  TheSpot.X:=X;
  TheSpot.Y:=Y;

  Image1.BeginDrag(True);
end;

Third, the DragDrop event handler:

procedure TForm1.MyDragDrop
  (Sender, Source: TObject; X, Y: Integer);
begin
  //dropping an Image?
  if Source is TImage then
  begin
    //on itself?
    if Sender is TImage then
    begin
      TImage(Source).Left := TImage(Source).Left + x - TheSpot.X;
      TImage(Source).Top := TImage(Source).Top + y  - TheSpot.Y;
    end
    else
    //or, somewhere inside ScrollBox!
    begin
      TImage(Source).Left := X - TheSpot.X;
      TImage(Source).Top := Y - TheSpot.Y;
    end;
  end;
end;

And finally, we assign the appropriate events with event handlers:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.OnDragOver := MyDragOver;
  Image1.OnDragDrop := MyDragDrop;

  ScrollBox1.OnDragOver := MyDragOver;
  ScrollBox1.OnDragDrop := MyDragDrop;
end;

Note 1: the above run-time assignment uses event-handle sharing. Here's "How To share an event handler in Delphi"

Note 2: The MyDragOver and MyDragDrop procedures are declared inside the private section of the Form declaration, like:

type
  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    Image1: TImage;
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
  private
    procedure MyDragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure MyDragOver(Sender, Source: TObject; X, Y: Integer; 
                         State: TDragState; var Accept: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  TheSpot : TPoint;

That's all, if you have any questions or suggestion be sure to post to the Delphi Programming Forum.

~ Zarko Gajic

Explore Delphi Programming

More from About.com

  1. Home
  2. Computing & Technology
  3. Delphi Programming

©2008 About.com, a part of The New York Times Company.

All rights reserved.