Swing/ZoomAndPanPanel のバックアップの現在との差分(No.5)
- バックアップ一覧
- 差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- バックアップ を表示
- Swing/ZoomAndPanPanel へ行く。
- 1 (2015-06-23 (火) 20:29:24)
- 2 (2015-06-24 (水) 17:11:50)
- 3 (2015-06-30 (火) 18:28:02)
- 4 (2016-01-13 (水) 14:58:14)
- 5 (2016-01-27 (水) 15:19:42)
- 6 (2016-05-24 (火) 19:52:57)
- 7 (2016-11-18 (金) 14:47:43)
- 8 (2017-04-04 (火) 14:13:45)
- 9 (2017-06-20 (火) 13:56:43)
- 10 (2018-02-24 (土) 19:51:30)
- 11 (2018-06-05 (火) 13:41:15)
- 12 (2018-12-07 (金) 15:22:07)
- 13 (2018-12-21 (金) 14:12:04)
- 14 (2020-11-17 (火) 12:52:52)
- 15 (2022-12-02 (金) 12:08:38)
- 追加された行はこの色です。
- 削除された行はこの色です。
--- 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: https://lh3.googleusercontent.com/-Um9j8O0t3Kg/VYdMPIUOfwI/AAAAAAAAN7A/LAJ5KRiDdp0/s800/ZoomAndPanPanel.png hreflang: href: http://java-swing-tips.blogspot.com/2015/06/an-image-inside-jscrollpane-zooming-by.html href: https://java-swing-tips.blogspot.com/2015/06/an-image-inside-jscrollpane-zooming-by.html lang: en --- * 概要 [#yfd80c64] `JScrollPane`内に配置した`JPanel`を、マウスホイールを使った拡大縮小と、スクロールバーを使った表示領域の移動が可能になるように設定します。 * 概要 [#summary] `JScrollPane`内に配置した`JPanel`をマウスホイールを使った拡大縮小とスクロールバーを使った表示領域の移動が可能になるように設定します。 #download(https://lh3.googleusercontent.com/-Um9j8O0t3Kg/VYdMPIUOfwI/AAAAAAAAN7A/LAJ5KRiDdp0/s800/ZoomAndPanPanel.png) * サンプルコード [#cf006c68] * サンプルコード [#sourcecode] #code(link){{ 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 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) { @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(r); // 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(r)); // 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(coordTransform); //g2.drawImage(img, 0, 0, this); // BAD EXAMPLE // g2.setTransform(zoomTransform); // g2.drawImage(img, 0, 0, this); g2.dispose(); } @Override public Dimension getPreferredSize() { Rectangle r = coordTransform.createTransformedShape(imgrect).getBounds(); Rectangle r = zoomTransform.createTransformedShape(imgrect).getBounds(); return new Dimension(r.width, r.height); } @Override public void updateUI() { removeMouseListener(listener); removeMouseMotionListener(listener); removeMouseWheelListener(handler); super.updateUI(); listener = new DragScrollListener(); addMouseListener(listener); addMouseMotionListener(listener); handler = new ZoomHandler(); addMouseWheelListener(handler); } protected class ZoomHandler extends MouseAdapter { private static final int MIN_ZOOM = -9; private static final int MAX_ZOOM = 16; 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); @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()) { 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 / 1.2 : 1.2; coordTransform.scale(s, s); //double s = 1d + zoomRange.getValue() * .1; //coordTransform.setToScale(s, s); AffineTransform at = AffineTransform.getScaleInstance(s, s); Rectangle nvr = at.createTransformedShape(ovr).getBounds(); 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); vp.translate((nvr.width - ovr.width) / 2, (nvr.height - ovr.height) / 2); vport.setViewPosition(vp); c.revalidate(); c.repaint(); } } } } } }} * 解説 [#w2dd6ea8] 上記のサンプルでは、`JPanel#getPreferredSize()`を拡大後の画像サイズを返すようにオーバーライドすることで、画像が`JViewport`より大きくなる場合は、スクロールバーが表示されるように設定しています。 * 解説 [#explanation] 上記のサンプルでは、`JPanel#getPreferredSize()`を拡大後の画像サイズを返すようにオーバーライドすることで、画像が`JViewport`より大きくなる場合はスクロールバーが表示されるように設定しています。 ---- ズーム自体は、[[JPanelに表示した画像のズームとスクロール>Swing/ZoomingAndPanning]]で使用しているものとほぼ同じ`MouseWheelListener`を設定して実行していますが、画像を描画している`JPanel`を`JScrollPane`内に設定してスクロールバーでのスクロールを可能にしているため、`JPanel#paintComponent(...)`内での`AffineTransform`の使用方法などを変更しています。 - [[JPanelに表示した画像のズームとスクロール>Swing/ZoomingAndPanning]]のようにズームを行うための`AffineTransform`(このサンプルでは`coordTransform`)を直接`Graphics2D`に設定すると、元からある`Graphics2D`コンテキスト内の`AffineTransform`(`JScrollBar`による移動)と競合して描画が乱れてしまう - マウスホイールによるズーム自体は[[JPanelに表示した画像のズームとスクロール>Swing/ZoomingAndPanning]]で使用しているものとほぼ同じ`MouseWheelListener`を使用 -- 画像を描画している`JPanel`を`JScrollPane`内に設定してスクロールバーでのスクロールを可能にするため`JPanel#paintComponent(...)`内での`AffineTransform`の適用方法などを変更 - [[JPanelに表示した画像のズームとスクロール>Swing/ZoomingAndPanning]]のようにズームを行うための`AffineTransform`(このサンプルでは`zoomTransform`)を直接`Graphics2D`に設定すると、元からある`Graphics2D`コンテキスト内の`AffineTransform`(`JScrollBar`による移動)と競合して描画が乱れてしまう #code{{ //BAD EXAMPLE g2.setTransform(coordTransform); // BAD EXAMPLE g2.setTransform(zoomTransform); g2.drawImage(img, 0, 0, this); }} - `2`つの`AffineTransform`を`AffineTransform#concatenate(AffineTransform)`で連結してから、`Graphics2D#setTransform(AffineTransform)`で設定することで回避 #code{{ AffineTransform at = g2.getTransform(); at.concatenate(coordTransform); at.concatenate(zoomTransform); g2.setTransform(at); g2.drawImage(img, 0, 0, this); }} - または、[http://docs.oracle.com/javase/jp/8/docs/api/java/awt/Graphics2D.html#drawImage-java.awt.Image-java.awt.geom.AffineTransform-java.awt.image.ImageObserver- Graphics2D#drawImage(Image, AffineTransform, ImageObserver) (Java Platform SE 8)]を使用し、`Graphics2D`コンテキスト内の`AffineTransform`が適用される前にイメージにズーム変換を適用しておくことで回避 - または[https://docs.oracle.com/javase/jp/8/docs/api/java/awt/Graphics2D.html#drawImage-java.awt.Image-java.awt.geom.AffineTransform-java.awt.image.ImageObserver- Graphics2D#drawImage(Image, AffineTransform, ImageObserver)]メソッドを使用し、`Graphics2D`コンテキスト内の`AffineTransform`が適用される前にイメージにズーム変換を適用しておくことで回避 #code{{ g2.drawImage(img, coordTransform, this); g2.drawImage(img, zoomTransform, this); }} * 参考リンク [#pd1ded23] * 参考リンク [#reference] - [[JPanelに表示した画像のズームとスクロール>Swing/ZoomingAndPanning]] -- マウスホイールによるズーム用のリスナを引用 - [[JScrollPaneのViewportをマウスで掴んでスクロール>Swing/HandScroll]] -- マウスドラッグによるスクロール用のリスナを引用 - [https://docs.oracle.com/javase/jp/8/docs/api/java/awt/Graphics2D.html#drawImage-java.awt.Image-java.awt.geom.AffineTransform-java.awt.image.ImageObserver- Graphics2D#drawImage(Image, AffineTransform, ImageObserver) (Java Platform SE 8)] - [http://sozai-free.com/ 2000ピクセル以上のフリー写真素材集] * コメント [#xd8ff1ff] * コメント [#comment] #comment - %%画像上でのマウスドラッグによる移動のあとで、スクロールバーを使用した移動を行うと表示位置がおかしくなるバグがある。%% -- &user(aterai); &new{2015-06-22 (月) 17:57:58}; -- ズームによるビュー移動には`JViewport#setViewPosition(Point)`を使用するように変更し、またマウスドラッグによるスクロールは別のリスナを使用するよう修正。 -- &user(aterai); &new{2015-06-23 (火) 17:57:58}; #comment