Swing/ZoomAndPanPanel のバックアップの現在との差分(No.1)
-
category: swing
folder: ZoomAndPanPanel
title: JScrollPane内に配置したJPanelをマウスで拡大、縮小、移動する
tags: [JScrollPane, JPanel, AffineTransform, Image, WheelListener]
tags: [JScrollPane, JPanel, AffineTransform, Image, MouseWheelListener]
author: aterai
pubdate: 2015-06-22T10:03:20+09:00
description: JScrollPane内に配置したJPanelを、マウスホイールを使った拡大縮小と、スクロールバーを使った表示領域の移動が可能になるように設定します。
description: JScrollPane内に配置したJPanelをマウスホイールを使った拡大縮小とスクロールバーを使った表示領域の移動が可能になるように設定します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2015/06/an-image-inside-jscrollpane-zooming-by.html lang: en
概要
JScrollPane
内に配置したJPanel
を、マウスホイールを使った拡大縮小と、スクロールバーを使った表示領域の移動が可能になるように設定します。
概要
JScrollPane
内に配置したJPanel
をマウスホイールを使った拡大縮小とスクロールバーを使った表示領域の移動が可能になるように設定します。
Screenshot
Advertisement
サンプルコード
サンプルコード
class ZoomAndPanePanel extends JPanel {
private final AffineTransform coordTransform = new AffineTransform();
private final AffineTransform zoomTransform = new AffineTransform();
private final transient Image img;
private final Rectangle imgrect;
private transient ZoomAndPanHandler handler;
private transient ZoomHandler handler;
private transient DragScrollListener listener;
public ZoomAndPanePanel(Image img) {
protected ZoomAndPanePanel(Image img) {
super();
this.img = img;
this.imgrect = new Rectangle(img.getWidth(null), img.getHeight(null));
this.imgrect = new Rectangle(img.getWidth(this), img.getHeight(this));
}
@Override public void paintComponent(Graphics g) {
#spanadd
#spanend
@Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(new Color(0x55FF0000, true));
g2.setPaint(new Color(0x55_FF_00_00, true));
Rectangle r = new Rectangle(500, 140, 150, 150);
//AffineTransform at = g2.getTransform();
//at.concatenate(coordTransform);
//g2.setTransform(at);
//g2.drawImage(img, 0, 0, this);
//g2.fill(new Rectangle(500, 140, 150, 150));
// use: AffineTransform#concatenate(...) and Graphics2D#setTransform(...)
// AffineTransform at = g2.getTransform();
// at.concatenate(zoomTransform);
// g2.setTransform(at);
// g2.drawImage(img, 0, 0, this);
// g2.fill(r);
//g2.drawRenderedImage((java.awt.image.RenderedImage) img, coordTransform);
g2.drawImage(img, coordTransform, this);
g2.fill(coordTransform.createTransformedShape(new Rectangle(500, 140, 150, 150)));
// or use: Graphics2D#drawImage(Image, AffineTransform, ImageObserver)
g2.drawImage(img, zoomTransform, this);
// or: g2.drawRenderedImage((RenderedImage) img, zoomTransform);
g2.fill(zoomTransform.createTransformedShape(r));
// BAD EXAMPLE
// g2.setTransform(zoomTransform);
// g2.drawImage(img, 0, 0, this);
#spanadd
#spanend
g2.dispose();
}
#spanadd
#spanend
@Override public Dimension getPreferredSize() {
Rectangle r = coordTransform.createTransformedShape(imgrect).getBounds();
Rectangle r = zoomTransform.createTransformedShape(imgrect).getBounds();
return new Dimension(r.width, r.height);
}
#spanadd
#spanend
@Override public void updateUI() {
removeMouseListener(handler);
removeMouseMotionListener(handler);
removeMouseListener(listener);
removeMouseMotionListener(listener);
removeMouseWheelListener(handler);
super.updateUI();
handler = new ZoomAndPanHandler();
addMouseListener(handler);
addMouseMotionListener(handler);
listener = new DragScrollListener();
addMouseListener(listener);
addMouseMotionListener(listener);
handler = new ZoomHandler();
addMouseWheelListener(handler);
}
protected class ZoomAndPanHandler extends MouseAdapter {
private static final int MIN_ZOOM = -9;
private static final int MAX_ZOOM = 16;
protected class ZoomHandler 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 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 = inversedPoint(dragStartPoint);
Point dragEnd = inversedPoint(dragEndPoint);
coordTransform.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()) {
Container c = SwingUtilities.getAncestorOfClass(
JViewport.class, e.getComponent());
if (c instanceof JViewport) {
Rectangle r = ((JViewport) c).getBounds();
Point p = new Point(r.x + r.width / 2, r.y + r.height / 2);
Point p1 = inversedPoint(p);
#spandel
#spanend
double s = 1d + zoomRange.getValue() * .1;
coordTransform.setToScale(s, s);
#spandel
#spanend
Point p2 = inversedPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
#spandel
#spanend
Component c = e.getComponent();
Container p = SwingUtilities.getAncestorOfClass(JViewport.class, c);
if (p instanceof JViewport) {
JViewport vport = (JViewport) p;
Rectangle ovr = vport.getViewRect();
double s = dir > 0 ? 1d / ZOOM_MULTIPLICATION_FACTOR
: ZOOM_MULTIPLICATION_FACTOR;
zoomTransform.scale(s, s);
// double s = 1d + zoomRange.getValue() * .1;
// zoomTransform.setToScale(s, s);
Rectangle nvr = AffineTransform.getScaleInstance(s, s)
.createTransformedShape(ovr)
.getBounds();
Point vp = nvr.getLocation();
vp.translate((nvr.width - ovr.width) / 2, (nvr.height - ovr.height) / 2);
vport.setViewPosition(vp);
c.revalidate();
c.repaint();
}
}
}
//https://community.oracle.com/thread/1263955
//How to implement Zoom & Pan in Java using Graphics2D
private Point inversedPoint(Point p1) {
Point p2 = new Point();
try {
AffineTransform inverse = coordTransform.createInverse();
inverse.transform(p1, p2);
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
return p2;
}
public AffineTransform getCoordTransform() {
return coordTransform;
}
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、JPanel#getPreferredSize()
を拡大後の画像サイズを返すようにオーバーライドすることで、画像がJViewport
より大きくなる場合は、スクロールバーが表示されるように設定しています。
解説
上記のサンプルでは、JPanel#getPreferredSize()
を拡大後の画像サイズを返すようにオーバーライドすることで、画像がJViewport
より大きくなる場合はスクロールバーが表示されるように設定しています。
- -
ズーム自体は、JPanelに表示した画像のズームとスクロールで使用しているものとほぼ同じ
MouseWheelListener
を設定して実行していますが、画像を描画しているJPanel
をJScrollPane
内に設定してスクロールバーでのスクロールを可能にしているため、JPanel#paintComponent(...)
内でのAffineTransform
の使用方法を変更しています。
- JPanelに表示した画像のズームとスクロールのようにズームや移動を行うための
AffineTransform
(このサンプルではcoordTransform
)を直接Graphics2D
に設定すると、元からあるGraphics2D
コンテキスト内のAffineTransform
(JScrollBar
による移動)と競合して描画が乱れてしまう - マウスホイールによるズーム自体はJPanelに表示した画像のズームとスクロールで使用しているものとほぼ同じ
MouseWheelListener
を使用- 画像を描画している
JPanel
をJScrollPane
内に設定してスクロールバーでのスクロールを可能にするためJPanel#paintComponent(...)
内でのAffineTransform
の適用方法などを変更
- 画像を描画している
- JPanelに表示した画像のズームとスクロールのようにズームを行うための
AffineTransform
(このサンプルではzoomTransform
)を直接Graphics2D
に設定すると、元からあるGraphics2D
コンテキスト内のAffineTransform
(JScrollBar
による移動)と競合して描画が乱れてしまう#spandel g2.setTransform(coordTransform); #spanend #spanadd // BAD EXAMPLE #spanend #spanadd g2.setTransform(zoomTransform); #spanend g2.drawImage(img, 0, 0, this);
- 2つの
AffineTransform
をAffineTransform#concatenate(AffineTransform)
で連結してから、Graphics2D#setTransform(AffineTransform)
で設定することで回避 -
2
つのAffineTransform
をAffineTransform#concatenate(AffineTransform)
で連結してから、Graphics2D#setTransform(AffineTransform)
で設定することで回避AffineTransform at = g2.getTransform(); #spandel at.concatenate(coordTransform); #spanend #spanadd at.concatenate(zoomTransform); #spanend g2.setTransform(at); g2.drawImage(img, 0, 0, this);
- または、Graphics2D#drawImage(Image, AffineTransform, ImageObserver) (Java Platform SE 8)を使用することで、
Graphics2D
コンテキスト内のAffineTransform
が適用される前にイメージにズーム、移動変換を適用しておくことで回避 - またはGraphics2D#drawImage(Image, AffineTransform, ImageObserver)メソッドを使用し、
Graphics2D
コンテキスト内のAffineTransform
が適用される前にイメージにズーム変換を適用しておくことで回避#spandel g2.drawImage(img, coordTransform, this); #spanend #spanadd g2.drawImage(img, zoomTransform, this); #spanend
参考リンク
参考リンク
- JPanelに表示した画像のズームとスクロール
- マウスホイールによるズーム用のリスナを引用
- JScrollPaneのViewportをマウスで掴んでスクロール
- マウスドラッグによるスクロール用のリスナを引用
- Graphics2D#drawImage(Image, AffineTransform, ImageObserver) (Java Platform SE 8)
- 2000ピクセル以上のフリー写真素材集