TITLE:JScrollPaneのViewPortをマウスで掴んでスクロール
Posted by aterai at 2006-01-02

JScrollPaneのViewPortをマウスで掴んでスクロール

JScrollPaneの窓の中をマウスで掴んで画像をスクロールします。
  • category: swing folder: HandScroll title: JScrollPaneのViewportをマウスで掴んでスクロール tags: [JScrollPane, JViewport, MouseListener, MouseMotionListener, JLabel] author: aterai pubdate: 2006-01-02T06:45:45+09:00 description: JScrollPaneの窓の中をマウスで掴んで画像をスクロールします。 image: https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTNqjajfcI/AAAAAAAAAbI/Km-h7tWdYOo/s800/HandScroll.png hreflang:
       href: https://java-swing-tips.blogspot.com/2009/03/mouse-dragging-viewport-scroll.html
       lang: en

概要

JScrollPaneの窓の中をマウスで掴んで画像をスクロールします。
HandScroll.png

サンプルコード

#spanend
#spandel
class HandScrollListener extends MouseInputAdapter {
#spanend
  private final Cursor defCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
class HandScrollListener extends MouseAdapter {
#spanend
  private final Cursor defCursor = Cursor.getDefaultCursor();
  private final Cursor hndCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
  private final Point pp = new Point();
  @Override
  public void mouseDragged(final MouseEvent e) {
#spanadd

#spanend
  @Override public void mouseDragged(MouseEvent e) {
    JViewport vport = (JViewport) e.getComponent();
    Point cp = e.getPoint();
    Point vp = vport.getViewPosition(); //= SwingUtilities.convertPoint(vport,0,0,label);
    vp.translate(pp.x-cp.x, pp.y-cp.y);
    //vport.setViewPosition(vp);
    label.scrollRectToVisible(
      new Rectangle(vp, vport.getSize()));
    Point vp = vport.getViewPosition();
          // = SwingUtilities.convertPoint(vport, 0, 0, label);
    vp.translate(pp.x - cp.x, pp.y - cp.y);
    // if (r1.isSelected()) {
    label.scrollRectToVisible(new Rectangle(vp, vport.getSize()));
    // } else {
    //   vport.setViewPosition(vp);
    // }
    pp.setLocation(cp);
  }
  @Override
  public void mousePressed(MouseEvent e) {
    label.setCursor(hndCursor);
#spanadd

#spanend
  @Override public void mousePressed(MouseEvent e) {
    e.getComponent().setCursor(hndCursor);
    pp.setLocation(e.getPoint());
  }
  @Override
  public void mouseReleased(MouseEvent e) {
    label.setCursor(defCursor);
    label.repaint();
#spanadd

#spanend
  @Override public void mouseReleased(MouseEvent e) {
    e.getComponent().setCursor(defCursor);
  }
}

解説

JViewportの原点(左上)を SwingUtilities.convertPointメソッドを使って中のJLabel(画像)の座標に変換し、これを基準座標としています。この座標を マウスの移動に応じて変更し、JComponent#scrollRectToVisibleメソッドの引数として使用することで、覗き窓のスクロールを行っています。

解説

JViewportの原点(左上)をマウスの移動に応じて変更し、JComponent#scrollRectToVisibleメソッドの引数として使用して覗き窓のスクロールを行っています。
  • JComponent#scrollRectToVisible(...)ではなくJViewport#setViewPosition(Point)を使用すると内部コンポーネントの外側に移動可能

JComponent#scrollRectToVisible(...)ではなく、JViewport#setViewPosition(Point)を使用すると、内部コンポーネントの外側に移動することができます。

参考リンク

  • JScrollPaneのオートスクロール
  • 2000ピクセル以上のフリー写真素材集
    • 大きな写真があったので拝借しています。
  • Bug ID: 6333318 JViewPort.scrollRectToVisible( Rectangle cr ) doesn't scroll if cr left or above
  • JScrollPaneでキネティックスクロール
    #spanend
    #spanadd
    // // JDK 1.6.0
    #spanend
    #spanadd
    // JScrollPane scroll = new JScrollPane(label);
    #spanend
    #spanadd
    // JViewport vport = scroll.getViewport();
    #spanend
    
    #spandel
    **コメント [#ubd1d4e0]
    #spanend
    - つかんで移動ということですが、移動方向が逆の気がします。 -- [[名無し]] &new{2006-02-25 (土) 01:24:46};
    -- ご指摘ありがとうございます。確かに逆ですね。画像を掴んでというより、スクロールバーを掴んでみたいな動きになってました。修正しておきます。 -- [[aterai]] &new{2006-02-25 (土) 03:33:50};
    - SwingUtilities.convertPointの代わりに、vport.getViewPosition()を使用するように変更。スクリーンショットの更新。 -- [[aterai]] &new{2009-01-19 (Mon) 16:58:27};
    - JDK 1.7.0 では、JViewport#setViewPosition(Point)を使って右下外部に移動できなくなっている。HeavyweightとLightweightコンポーネントが混在しても問題ないようにするために、内部でrevalidate()しているのが原因? このサンプルではLightweightコンポーネントしか使用しないので、revalidate()しないように対応。 -- [[aterai]] &new{2011-10-03 (月) 18:03:55};
    #spanadd
    // JDK 1.7.0 or later
    #spanend
    #spanadd
    JViewport vport = new JViewport() {
    #spanend
      private static final boolean WEIGHT_MIXING = false;
      private boolean isAdjusting;
      @Override public void revalidate() {
        if (!WEIGHT_MIXING && isAdjusting) {
          return;
        }
        super.revalidate();
      }
    
      @Override public void setViewPosition(Point p) {
        if (WEIGHT_MIXING) {
          super.setViewPosition(p);
        } else {
          isAdjusting = true;
          super.setViewPosition(p);
          isAdjusting = false;
        }
      }
    #spanadd
    };
    #spanend
    #spanadd
    vport.add(label);
    #spanend
    #spanadd
    JScrollPane scroll = new JScrollPane();
    #spanend
    #spanadd
    scroll.setViewport(vport);
    #spanend
    #spanadd
    

参考リンク

コメント