Swing/KineticScrolling のバックアップの現在との差分(No.6)
- バックアップ一覧
- 差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- バックアップ を表示
- Swing/KineticScrolling へ行く。
- 1 (2010-08-16 (月) 13:34:26)
- 2 (2010-08-17 (火) 12:51:12)
- 3 (2011-10-03 (月) 18:08:23)
- 4 (2012-12-28 (金) 12:38:39)
- 5 (2014-12-02 (火) 01:49:49)
- 6 (2014-12-30 (火) 15:27:03)
- 7 (2016-03-04 (金) 13:37:58)
- 8 (2017-03-29 (水) 19:49:24)
- 9 (2018-02-20 (火) 15:30:45)
- 10 (2018-02-24 (土) 19:51:30)
- 11 (2020-01-29 (水) 18:50:11)
- 12 (2021-05-09 (日) 03:05:32)
- 追加された行はこの色です。
- 削除された行はこの色です。
--- category: swing folder: KineticScrolling title: JScrollPaneでキネティックスクロール tags: [JScrollPane, Animation, MouseListener, JViewport] author: aterai pubdate: 2010-08-16T13:34:26+09:00 description: JScrollPaneにキネティックスクロール(慣性スクロール)風の動作をするマウスリスナーを設定します。 image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTO32D08pI/AAAAAAAAAdE/TpuoGrYo-Q0/s800/KineticScrolling.png hreflang: href: http://java-swing-tips.blogspot.com/2010/08/kinetic-scrolling-jscrollpane.html href: https://java-swing-tips.blogspot.com/2010/08/kinetic-scrolling-jscrollpane.html lang: en --- * 概要 [#dad5d28f] * 概要 [#summary] `JScrollPane`にキネティックスクロール(慣性スクロール)風の動作をするマウスリスナーを設定します。 #download(https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTO32D08pI/AAAAAAAAAdE/TpuoGrYo-Q0/s800/KineticScrolling.png) * サンプルコード [#dca6c47f] * サンプルコード [#sourcecode] #code(link){{ class KineticScrollingListener2 extends MouseAdapter { private static final int SPEED = 6; private static final double D = 0.7; private final Cursor dc; private final Cursor hc = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); private final javax.swing.Timer inside; private final javax.swing.Timer outside; private final JComponent label; private Point startPt = new Point(); private Point delta = new Point(); private static boolean isInside(JViewport vport, JComponent comp) { Point vp = vport.getViewPosition(); return (vp.x>=0 && vp.x+vport.getWidth()-comp.getWidth()<=0 && vp.y>=0 && vp.y+vport.getHeight()-comp.getHeight()<=0); class KineticScrollingListener2 extends MouseAdapter implements HierarchyListener { protected static final int SPEED = 4; protected static final int DELAY = 10; protected static final double D = .8; protected final JComponent label; protected final Point startPt = new Point(); protected final Point delta = new Point(); protected final Cursor dc; protected final Cursor hc = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); protected final Timer inside = new Timer(DELAY, null); protected final Timer outside = new Timer(DELAY, null); protected static boolean isInside(JViewport viewport, JComponent comp) { Point vp = viewport.getViewPosition(); return vp.x >= 0 && vp.x + viewport.getWidth() - comp.getWidth() <= 0 && vp.y >= 0 && vp.y + viewport.getHeight() - comp.getHeight() <= 0; } public KineticScrollingListener2(JComponent comp) { protected KineticScrollingListener2(JComponent comp) { super(); this.label = comp; this.dc = comp.getCursor(); this.inside = new javax.swing.Timer(20, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JViewport vport = (JViewport)label.getParent(); Point vp = vport.getViewPosition(); //System.out.format("s: %s, %s\n", delta, vp); vp.translate(-delta.x, -delta.y); vport.setViewPosition(vp); inside.addActionListener(e -> dragInside()); outside.addActionListener(e -> dragOutside()); } if (Math.abs(delta.x)>0 || Math.abs(delta.y)>0) { delta.setLocation((int)(delta.x*D), (int)(delta.y*D)); //Outside if (vp.x<0 || vp.x+vport.getWidth()-label.getWidth()>0 ) delta.x = (int)(delta.x*D); if (vp.y<0 || vp.y+vport.getHeight()-label.getHeight()>0) delta.y = (int)(delta.y*D); } else { inside.stop(); if (!isInside(vport, label)) outside.start(); } private void dragInside() { JViewport viewport = (JViewport) SwingUtilities.getUnwrappedParent(label); Point vp = viewport.getViewPosition(); // System.out.format("s: %s, %s%n", delta, vp); vp.translate(-delta.x, -delta.y); viewport.setViewPosition(vp); if (Math.abs(delta.x) > 0 || Math.abs(delta.y) > 0) { delta.setLocation((int) (delta.x * D), (int) (delta.y * D)); // Outside if (vp.x < 0 || vp.x + viewport.getWidth() - label.getWidth() > 0) { delta.x = (int) (delta.x * D); } }); this.outside = new javax.swing.Timer(20, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JViewport vport = (JViewport)label.getParent(); Point vp = vport.getViewPosition(); //System.out.format("r: %s\n", vp); if (vp.x<0) vp.x = (int)(vp.x*D); if (vp.y<0) vp.y = (int)(vp.y*D); if (vp.x+vport.getWidth()-label.getWidth()>0) vp.x = (int) (vp.x - (vp.x+vport.getWidth()-label.getWidth())*(1.0-D)); if (vp.y+vport.getHeight()>label.getHeight()) vp.y = (int) (vp.y - (vp.y+vport.getHeight()-label.getHeight())*(1.0-D)); vport.setViewPosition(vp); if (isInside(vport, label)) outside.stop(); if (vp.y < 0 || vp.y + viewport.getHeight() - label.getHeight() > 0) { delta.y = (int) (delta.y * D); } }); } else { inside.stop(); if (!isInside(viewport, label)) { outside.start(); } } } private void dragOutside() { JViewport viewport = (JViewport) SwingUtilities.getUnwrappedParent(label); Point vp = viewport.getViewPosition(); // System.out.format("r: %s%n", vp); if (vp.x < 0) { vp.x = (int) (vp.x * D); } if (vp.y < 0) { vp.y = (int) (vp.y * D); } if (vp.x + viewport.getWidth() - label.getWidth() > 0) { vp.x = (int) (vp.x - (vp.x + viewport.getWidth() - label.getWidth()) * (1d - D)); } if (vp.y + viewport.getHeight() > label.getHeight()) { vp.y = (int) (vp.y - (vp.y + viewport.getHeight() - label.getHeight()) * (1d - D)); } viewport.setViewPosition(vp); if (isInside(viewport, label)) { outside.stop(); } } @Override public void mousePressed(MouseEvent e) { label.setCursor(hc); e.getComponent().setCursor(hc); startPt.setLocation(e.getPoint()); inside.stop(); outside.stop(); } @Override public void mouseDragged(MouseEvent e) { Point pt = e.getPoint(); JViewport vport = (JViewport)label.getParent(); Point vp = vport.getViewPosition(); vp.translate(startPt.x-pt.x, startPt.y-pt.y); vport.setViewPosition(vp); delta.setLocation(SPEED*(pt.x-startPt.x), SPEED*(pt.y-startPt.y)); JViewport viewport = (JViewport) SwingUtilities.getUnwrappedParent(label); Point vp = viewport.getViewPosition(); vp.translate(startPt.x - pt.x, startPt.y - pt.y); viewport.setViewPosition(vp); delta.setLocation(SPEED * (pt.x - startPt.x), SPEED * (pt.y - startPt.y)); startPt.setLocation(pt); } @Override public void mouseReleased(MouseEvent e) { label.setCursor(dc); if (isInside((JViewport)label.getParent(), label)) { e.getComponent().setCursor(dc); JViewport viewport = (JViewport) SwingUtilities.getUnwrappedParent(label); if (isInside(viewport, label)) { inside.start(); } else { outside.start(); } } @Override public void hierarchyChanged(HierarchyEvent e) { Component c = e.getComponent(); if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0 && !c.isDisplayable()) { inside.stop(); outside.stop(); } } } }} * 解説 [#ne8d550b] * 解説 [#explanation] - `scrollRectToVisible` -- マウスを放したあと、タイマーを起動し、`JComponent#scrollRectToVisible(Rectangle)`メソッドでスクロール -- マウスがリリースされたらタイマーを起動し、`JComponent#scrollRectToVisible(Rectangle)`メソッドでスクロール - `setViewPosition` -- マウスを放したあと、タイマーを起動し、`JViewport#setViewPosition(Point)`メソッドでスクロール -- `View`である`JLabel`の外で、移動が止まった(またはマウスがリリースされた)場合は、別のタイマーで`JLabel`の縁まで戻る -- マウスがリリースされたらタイマーを起動し、`JViewport#setViewPosition(Point)`メソッドでスクロール -- `View`として設定されている`JLabel`の外で移動が止まった(またはマウスがリリースされた)場合は、別のタイマーで`JLabel`の縁まで戻る * 参考リンク [#edac2f7a] * 参考リンク [#reference] - [[JScrollPaneのViewportをマウスで掴んでスクロール>Swing/HandScroll]] - [[JScrollPaneのオートスクロール>Swing/AutoScroll]] - [http://sozai-free.com/ 2000ピクセル以上のフリー写真素材集] * コメント [#h5b61d84] * コメント [#comment] #comment - 慣性(モーメンタム)スクロール、フリックスクロール(フリック+慣性スクロール?)、・・・でもやっぱり猫の掌スクロールを最初に思い出してしまう。 -- &user(aterai); &new{2010-08-16 (月) 13:41:47}; - `JDK 1.7.0`では、`JViewport#setViewPosition(Point)`を使って右下外部に移動できなくなっているので、[[JScrollPaneのViewportをマウスで掴んでスクロール>Swing/HandScroll]]と同じ対応をしてソースを更新。 -- &user(aterai); &new{2011-10-03 (月) 18:08:23}; #comment