• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JScrollPane内にある複数Componentを配置したJPanelをJLayerを使ってドラッグスクロール
#navi(../)
#tags(JScrollPane, JPanel, JLayer)
RIGHT:Posted by &author(aterai); at 2013-08-05
*JScrollPane内にある複数Componentを配置したJPanelをJLayerを使ってドラッグスクロール [#s1cfff1c]
複数のネストした``Component``を配置した``JPanel``のドラッグイベントを、``JScrollPane``をラップした``JLayer``で受け取ってスクロール可能にします。
---
title: JScrollPane内にある複数Componentを配置したJPanelをJLayerを使ってドラッグスクロール
tags: [JScrollPane, JPanel, JLayer]
author: aterai
pubdate: 2013-08-05T11:49:22+09:00
description: 複数のネストしたComponentを配置したJPanelのドラッグイベントを、JScrollPaneをラップしたJLayerで受け取ってスクロール可能にします。
---
* 概要 [#s1cfff1c]
複数のネストした`Component`を配置した`JPanel`のドラッグイベントを、`JScrollPane`をラップした`JLayer`で受け取ってスクロール可能にします。

-&jnlp;
-&jar;
-&zip;
#download(https://lh5.googleusercontent.com/-5zBF0JOr6kM/UfuiEj7Do7I/AAAAAAAABxg/7tKYnrOl9eo/s800/DragScrollLayer.png)

//#screenshot
#ref(https://lh5.googleusercontent.com/-5zBF0JOr6kM/UfuiEj7Do7I/AAAAAAAABxg/7tKYnrOl9eo/s800/DragScrollLayer.png)

**サンプルコード [#k3c044c8]
* サンプルコード [#k3c044c8]
#code(link){{
class DragScrollLayerUI extends LayerUI<JScrollPane> {
  private final Point pp = new Point();
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    JLayer jlayer = (JLayer)c;
    jlayer.setLayerEventMask(
        AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
  }
  @Override public void uninstallUI(JComponent c) {
    JLayer jlayer = (JLayer)c;
    jlayer.setLayerEventMask(0);
    super.uninstallUI(c);
  }
  @Override protected void processMouseEvent(
      MouseEvent e, JLayer<? extends JScrollPane> l) {
    Component c = e.getComponent();
    if(c instanceof JScrollBar || c instanceof JSlider) {
      return;
    }
    if(e.getID()==MouseEvent.MOUSE_PRESSED) {
      JViewport vport = l.getView().getViewport();
      Point cp = SwingUtilities.convertPoint(c, e.getPoint(), vport);
      pp.setLocation(cp);
    }
  }
  @Override protected void processMouseMotionEvent(
      MouseEvent e, JLayer<? extends JScrollPane> l) {
    Component c = e.getComponent();
    if(c instanceof JScrollBar || c instanceof JSlider) {
      return;
    }
    if(e.getID()==MouseEvent.MOUSE_DRAGGED) {
      JViewport vport = l.getView().getViewport();
      JComponent cmp = (JComponent)vport.getView();
      Point cp = SwingUtilities.convertPoint(c, e.getPoint(), vport);
      Point vp = vport.getViewPosition();
      vp.translate(pp.x-cp.x, pp.y-cp.y);
      cmp.scrollRectToVisible(new Rectangle(vp, vport.getSize()));
      pp.setLocation(cp);
    }
  }
}
}}

**解説 [#u8652939]
- 左: ``DragScrollListener``
* 解説 [#u8652939]
- 左: `DragScrollListener`
-- [[JTreeの余白をドラッグしてスクロール>Swing/TreeDragScroll]]
-- このリスナーを追加した一つのComponentをドラッグしてスクロールが可能
-- ``JPanel``を掴んでスクロールすることができるが、その子コンポーネントの``JTabbedPane``などをドラッグしてもスクロールはできない
- 右: ``DragScrollLayer``
-- すべての下位コンポーネントの``MouseEvent``をキャッチするようJLayer#setLayerEventMask(...)と設定した``JLayer``を作成
-- この``JLayer``で``JScrollPane``をラップし、子にマウスイベントを消費するコンポーネントがあっても、ビューである``JPanel``をドラッグに応じてスクロール
-- ``JScrollBar``や``JSlider``のように、ノブのドラッグを使用するコンポーネントは二重にスクロールしてしまうので除外
-- このリスナーを追加した一つの`Component`をドラッグしてスクロールが可能
-- `JPanel`を掴んでスクロールすることができるが、その子コンポーネントの`JTabbedPane`などをドラッグしてもスクロールはできない
- 右: `DragScrollLayer`
-- すべての下位コンポーネントの`MouseEvent`をキャッチするよう`JLayer#setLayerEventMask(...)`と設定した`JLayer`を作成
-- この`JLayer`で`JScrollPane`をラップし、子にマウスイベントを消費するコンポーネントがあっても、ビューである`JPanel`をドラッグに応じてスクロール
-- `JScrollBar`や`JSlider`のように、ノブのドラッグを使用するコンポーネントは二重にスクロールしてしまうので除外

**参考リンク [#y3afd013]
* 参考リンク [#y3afd013]
- [http://java-swing-tips.blogspot.jp/2009/03/mouse-dragging-viewport-scroll.html Java Swing Tips: Mouse Dragging ViewPort Scroll]
- [[JTreeの余白をドラッグしてスクロール>Swing/TreeDragScroll]]
- [[JScrollPaneのViewportをマウスで掴んでスクロール>Swing/HandScroll]]

**コメント [#i29c712d]
* コメント [#i29c712d]
#comment
#comment