Link to home
Start Free TrialLog in
Avatar of wipnav
wipnav

asked on

How to pan an image with the mouse

I have a TImage component on a form, where the image is larger than the form. The form's AutoScroll property is set to True. I can use the scroll bars to move the image around on the form, but I want to use the mouse. I want to click on the image and drag it to move it on the form. As I do this, the form's scroll bars should move correspondingly. I am going to set the image cursor to crHandPoint so that people will expect that they can move the image around.

My question is, how do I code this?
Avatar of Ferruccio Accalai
Ferruccio Accalai
Flag of Italy image

use a tscrollbox with align alclient and put the image into it
Avatar of wipnav
wipnav

ASKER

I did that, but the image still doesn't move when I click on it and drag it.
SOLUTION
Avatar of SteveBay
SteveBay
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Another way is to put a Tpanel on your form.
Drop a Timage to the panel with align alClient and cursor crHandPoint
Now, In TImage.onMouseDown event

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
const
  SC_DragMove = $F012;
begin
  Begin
   ReleaseCapture;
   panel1.perform(WM_SysCommand, SC_DragMove, 0);
  End;
end;

This will drag the panel, and so the image.
Avatar of wipnav

ASKER

SteveBay,

You seem to be on the right track. The scroll box isn't necessary because the form can be scrolled as well. The problem is that the image movement is very jerky. The scroll bars jump around like crazy. Also, I don't want the image to scroll such that it ever moves away from the edge of the window.

Ferruccio68,

Your code doesn't do what I'm looking for.
Gosh, I've completely misunderstood (or forgot the real one) the question

Try this one, without TScroolBox


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  down: boolean;

implementation

{$R *.dfm}

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

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  if down then
  begin
    vertscrollbar.Position := Y;
    horzscrollbar.Position := X;
  end;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  down := false;
end;

end.

Open in new window

Avatar of wipnav

ASKER

Not good. Did you run your code?

The idea is to be able to pan the image around the form so that all parts of it can be seen.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Inversion:
vertscrollbar.Position := vertscrollbar.Position+dy;
horzscrollbar.Position := horzscrollbar.Position+dx;
Avatar of wipnav

ASKER

Progress yes, a final solution, not yet.

1. The image moves the opposite way that you would expect. The "Hand" should grab the image and move it in the direction that the hand is moved, not the opposite way as with your code.
2. If I attempt to move the image only in the Y direction it also moves in the X direction. The same for movement in only the X direction.
3. Sometimes the image doesn't want to move all of the way to the edge.
Avatar of wipnav

ASKER

Your inversion comment helped with #2 above.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of wipnav

ASKER

I think we are getting real close. The functionality seems to be there, but there is still a lot of jitter when I move the image. I recall that there some sort of double buffering thing that might help. Have you heard of that?
Yes, you can set the Tform property doublebuffered to true.
This should reduce the flickering
Avatar of wipnav

ASKER

I tried it, and it helps a little.

There is still a problem. As you move the mouse slowly, the image jumps back and forth. It's like it is too sensitive to the mouse movement.
Maybe due to the vetrscrollbar and horzscrollbar increment?
In my test is set to 1
Avatar of wipnav

ASKER

I set the increment to 1 also.

When I move the mouse as slowly as possible, I see the image jump around more than I'm moving the mouse. Do you see the same thing? I think something must be wrong with the logic.
Avatar of wipnav

ASKER

I think something needs to be done to reduce the sensitivity to mouse movement. Maybe if the mouse only moves a pixel or two, that the image doesn't move.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of wipnav

ASKER

Here is my final code with the correct the setting of the cursor.
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormResize(Sender: TObject);
  private
     FMouseIsDown : Boolean;
     FLastX : integer;
     FLastY : integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormResize(Sender: TObject);
begin
  if (Image1.Height > ClientHeight) or (Image1.Width > ClientWidth) then
    Cursor := crHandPoint
  else
    Cursor := crDefault;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FMouseIsDown := True;
  FLastX := X;
  FLastY := Y;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  Dx, Dy: Integer;
begin
  if FMouseIsDown then
  begin
    Dx := X - FLastX;
    Dy := y - FLasty;
    VertScrollBar.Position :=
     VertScrollBar.Position - (Dy * Image1.Height div VertScrollBar.Range);
    HorzScrollBar.Position :=
     HorzScrollBar.Position - (Dx * Image1.Width div HorzScrollBar.Range);
    FLastX := X - Dx;
    FLastY := Y - Dy;
  end
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FMouseIsDown := False;
end;

end.

Open in new window

Well, I'm back after my deserved relaxing weekend :)
In fact I was guessing about this
FLastX := X - Dx;
FLastY := Y - Dy;
but I'm glad to see you've adjusted the final code by yourself.

Regards
Ferruccio