Graphics32: Pan with mouse-drag, zoom to mouse cursor with mouse wheel

前端 未结 1 737
渐次进展
渐次进展 2020-12-09 00:30

I need to implement a pan as I click and drag the mouse, and zoom/unzoom towards/away from the mouse cursor that uses the mouse wheel. (In Delphi 2010, with the image anchor

相关标签:
1条回答
  • 2020-12-09 01:13

    Graphics32 provides a component named TImgView32 which can zoom by setting the Scale property. The appropriate way to do so is by using the OnMouseWheelUp and -Down events. Set TabStop to True for triggering these events and set Centered to False. But scaling in this manner does not comply with your wish to center the zooming operation at the mouse cursor. So repositioning and resizing around that point is a nicer solution. Further, as I understand, the image is always aligned in the top-left corner of the component, so panning must also be accomplished by repositioning the component.

    uses
      Windows, Classes, Controls, Forms, GR32_Image, GR32_Layers, Jpeg;
    
    type
      TForm1 = class(TForm)
        ImgView: TImgView32;
        procedure FormCreate(Sender: TObject);
        procedure ImgViewMouseWheel(Sender: TObject; Shift: TShiftState;
          WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
        procedure ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
        procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
          Y: Integer);
        procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
      private
        FDragging: Boolean;
        FFrom: TPoint;
      end;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      ImgView.Bitmap.LoadFromFile('D:\Pictures\Mona_Lisa.jpg');
      ImgView.TabStop := True;
      ImgView.ScrollBars.Visibility := svHidden;
      ImgView.ScaleMode := smResize;
    end;
    
    procedure TForm1.ImgViewMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    const
      ZoomFactor: array[Boolean] of Single = (0.9, 1.1);
    var
      R: TRect;
    begin
      MousePos := ImgView.ScreenToClient(MousePos);
      with ImgView, MousePos do
        if PtInRect(ClientRect, MousePos) then
        begin
          R := BoundsRect;
          R.Left := Left + X - Round(ZoomFactor[WheelDelta > 0] * X);
          R.Top := Top + Y - Round(ZoomFactor[WheelDelta > 0] * Y);
          R.Right := R.Left + Round(ZoomFactor[WheelDelta > 0] * Width);
          R.Bottom := R.Top + Round(ZoomFactor[WheelDelta > 0] * Height);
          BoundsRect := R;
          Handled := True;
        end;
    end;
    
    procedure TForm1.ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
    begin
      FDragging := True;
      ImgView.Enabled := False; { Temporarily, to get MouseMove to the parent }
      FFrom := Point(X, Y);
    end;
    
    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    begin
      if FDragging then
        ImgView.SetBounds(X - FFrom.X, Y - FFrom.Y, ImgView.Width, ImgView.Height);
    end;
    
    procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      FDragging := False;
      ImgView.Enabled := True;
      ImgView.SetFocus;
    end;
    

    Edit: Alternative with TImage instead of TImgView32:

    uses
      Windows, Classes, Controls, Forms, Jpeg, ExtCtrls;
    
    type
      TForm1 = class(TForm)
        Image: TImage;
        procedure FormCreate(Sender: TObject);
        procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
          WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
        procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
          Y: Integer);
        procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
        procedure ImageDblClick(Sender: TObject);
        procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
      private
        FDragging: Boolean;
        FFrom: TPoint;
        FOrgImgBounds: TRect;
      end;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      DoubleBuffered := True;
      Image.Picture.LoadFromFile('D:\Pictures\Mona_Lisa.jpg');
      Image.Stretch := True;
      Image.Height := Round(Image.Width * Image.Picture.Height / Image.Picture.Width);
      FOrgImgBounds := Image.BoundsRect;
    end;
    
    procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    const
      ZoomFactor: array[Boolean] of Single = (0.9, 1.1);
    var
      R: TRect;
    begin
      MousePos := Image.ScreenToClient(MousePos);
      with Image, MousePos do
        if PtInRect(ClientRect, MousePos) and ((WheelDelta > 0) and
          (Height < Self.ClientHeight) and (Width < Self.ClientWidth)) or
          ((WheelDelta < 0) and (Height > 20) and (Width > 20)) then
        begin
          R := BoundsRect;
          R.Left := Left + X - Round(ZoomFactor[WheelDelta > 0] * X);
          R.Top := Top + Y - Round(ZoomFactor[WheelDelta > 0] * Y);
          R.Right := R.Left + Round(ZoomFactor[WheelDelta > 0] * Width);
          R.Bottom := R.Top + Round(ZoomFactor[WheelDelta > 0] * Height);
          BoundsRect := R;
          Handled := True;
        end;
    end;
    
    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    begin
      if FDragging then
        Image.SetBounds(X - FFrom.X, Y - FFrom.Y, Image.Width, Image.Height);
    end;
    
    procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      Image.Enabled := True;
      FDragging := False;
    end;
    
    procedure TForm1.ImageDblClick(Sender: TObject);
    begin
      Image.BoundsRect := FOrgImgBounds;
    end;
    
    procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      if not (ssDouble in Shift) then
      begin
        FDragging := True;
        Image.Enabled := False;
        FFrom := Point(X, Y);
        MouseCapture := True;
      end;
    end;
    
    0 讨论(0)
提交回复
热议问题