• category: swing folder: ZoomingAndPanning title: JPanelに表示した画像のズームとスクロール tags: [AffineTransform, Graphics, JPanel, MouseListener, MouseMotionListener, MouseWheelListener] author: aterai pubdate: 2014-04-21T00:28:49+09:00 description: JPanelに表示した画像にAffineTransformによる変換を適用して、マウスを使った拡大・縮小・移動を実行します。 image: https://lh3.googleusercontent.com/-c5Y9hCoRQbU/U1PhhnitgFI/AAAAAAAACD0/ZXIcyPywcr0/s800/ZoomingAndPanning.png

概要

JPanelに表示した画像にAffineTransformによる変換を適用して、マウスを使った拡大・縮小・移動を実行します。How to implement Zoom & Pan in Java using Graphics2Dに投稿されているコードを参考・引用しています。

サンプルコード

class ZoomAndPanHandler extends MouseAdapter {
  private static final double ZOOM_MULTIPLICATION_FACTOR = 1.2;
  private static final int MIN_ZOOM = -10;
  private static final int MAX_ZOOM = 10;
  private static final int EXTENT = 1;
  private final BoundedRangeModel zoomRange = new DefaultBoundedRangeModel(
      0, EXTENT, MIN_ZOOM, MAX_ZOOM + EXTENT);
  private final AffineTransform coordAndZoomTransform = new AffineTransform();
  private final Point dragStartPoint = new Point();

  @Override public void mousePressed(MouseEvent e) {
    dragStartPoint.setLocation(e.getPoint());
  }

  @Override public void mouseDragged(MouseEvent e) {
    Point dragEndPoint = e.getPoint();
    Point dragStart = transformPoint(dragStartPoint);
    Point dragEnd   = transformPoint(dragEndPoint);
    coordAndZoomTransform.translate(dragEnd.x - dragStart.x, dragEnd.y - dragStart.y);
    dragStartPoint.setLocation(dragEndPoint);
    e.getComponent().repaint();
  }

  @Override public void mouseWheelMoved(MouseWheelEvent e) {
    int dir = e.getWheelRotation();
    int z = zoomRange.getValue();
    zoomRange.setValue(z + EXTENT * (dir > 0 ? -1 : 1));
    if (z == zoomRange.getValue()) {
      return;
    }
    Component c = e.getComponent();
    Rectangle r = c.getBounds();
    // Point p = e.getPoint();
    Point p = new Point(r.x + r.width / 2, r.y + r.height / 2);
    Point p1 = transformPoint(p);
    double scale = dir > 0 ? 1 / ZOOM_MULTIPLICATION_FACTOR
                           : ZOOM_MULTIPLICATION_FACTOR;
    coordAndZoomTransform.scale(scale, scale);
    Point p2 = transformPoint(p);
    coordAndZoomTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
    c.repaint();
  }

  // https://community.oracle.com/thread/1263955
  // How to implement Zoom & Pan in Java using Graphics2D
  private Point transformPoint(Point p1) {
    Point p2 = new Point();
    try {
      AffineTransform inverse = coordAndZoomTransform.createInverse();
      inverse.transform(p1, p2);
    } catch (NoninvertibleTransformException ex) {
      ex.printStackTrace();
    }
    return p2;
  }

  public AffineTransform getCoordAndZoomTransform() {
    return coordAndZoomTransform;
  }
}
View in GitHub: Java, Kotlin

解説

AffineTransform#createInverse()で取得したAffineTransformオブジェクトでマウス位置の逆変換を行い、現在表示されている倍率でのズームの中心や移動距離などを計算しています。

  • ズーム
    • ホイール上回転で拡大
    • ホイール下回転で縮小
  • スクロール
    • マウスドラッグで移動

参考リンク

コメント