---
category: swing
folder: ChangeScrollBarWidthOnHover
title: JScrollBar上にマウスカーソルが入ったらその幅を拡張する
tags: [JScrollBar, JScrollPane, JLayer, LayoutManager, Animation]
author: aterai
pubdate: 2019-09-02T18:04:32+09:00
description: JScrollBar上へのマウスカーソルの出入りをJLayerで取得してその幅を拡大・縮小します。
image: https://drive.google.com/uc?id=1BAF8wRV7pfhmJTBiE9_cun0SbMVR2XFQ
---
* Summary [#summary]
`JScrollBar`上へのマウスカーソルの出入りを`JLayer`で取得してその幅を拡大・縮小します。
#download(https://drive.google.com/uc?id=1BAF8wRV7pfhmJTBiE9_cun0SbMVR2XFQ)
* Source Code Examples [#sourcecode]
#code(link){{
JScrollPane scroll = new JScrollPane(makeList());
scroll.setHorizontalScrollBarPolicy(
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
JPanel controls = new JPanel();
Timer animator = new Timer(10, e -> controls.revalidate());
controls.setLayout(new BorderLayout(0, 0) {
private int controlsWidth = MIN_WIDTH;
@Override public Dimension preferredLayoutSize(Container target) {
Dimension ps = super.preferredLayoutSize(target);
int controlsPreferredWidth = ps.width;
if (animator.isRunning()) {
if (willExpand) {
if (controls.getWidth() < controlsPreferredWidth) {
controlsWidth += 1;
}
} else {
if (controls.getWidth() > MIN_WIDTH) {
controlsWidth -= 1;
}
}
if (controlsWidth <= MIN_WIDTH) {
controlsWidth = MIN_WIDTH;
animator.stop();
} else if (controlsWidth >= controlsPreferredWidth) {
controlsWidth = controlsPreferredWidth;
animator.stop();
}
}
ps.width = controlsWidth;
return ps;
}
});
controls.add(scroll.getVerticalScrollBar());
JPanel p = new JPanel(new BorderLayout());
p.add(controls, BorderLayout.EAST);
p.add(scroll);
JPanel pp = new JPanel(new GridLayout(1, 2));
pp.add(new JLayer<>(p, new LayerUI<JPanel>() {
private boolean isDragging;
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK
| AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JPanel> l) {
int id = e.getID();
Component c = e.getComponent();
if (c instanceof JScrollBar && id == MouseEvent.MOUSE_DRAGGED) {
isDragging = true;
}
}
@Override protected void processMouseEvent(
MouseEvent e, JLayer<? extends JPanel> l) {
if (e.getComponent() instanceof JScrollBar) {
switch (e.getID()) {
case MouseEvent.MOUSE_ENTERED:
if (!animator.isRunning() && !isDragging) {
willExpand = true;
animator.setInitialDelay(0);
animator.start();
}
break;
case MouseEvent.MOUSE_EXITED:
if (!animator.isRunning() && !isDragging) {
willExpand = false;
animator.setInitialDelay(500);
animator.start();
}
break;
case MouseEvent.MOUSE_RELEASED:
isDragging = false;
if (!animator.isRunning()
&& !e.getComponent().getBounds().contains(e.getPoint())) {
willExpand = false;
animator.setInitialDelay(500);
animator.start();
}
break;
default:
break;
}
l.getView().repaint();
}
}
}));
pp.add(new JLayer<>(
makeTranslucentScrollBar(makeList()),
new ScrollBarOnHoverLayerUI()));
}}
* Description [#explanation]
* Description [#description]
- 左:
-- `JPanel`に`JScrollPane`と縦`JScrollBar`を分けて配置
-- `JPanel`に縦`JScrollBar`の幅を`Timer`を使用して拡大・縮小するレイアウトマネージャを設定
--- [[LayoutManagerを使ってパネルの展開アニメーションを行う>Swing/LayoutAnimation]]
-- `JPanel`を`JLayer`でラップして縦`JScrollBar`へのマウスカーソルの出入りなどを検知
--- `MouseEvent.MOUSE_ENTERED`と`MouseEvent.MOUSE_EXITED`で出入りを検知して`Timer`を起動する
--- ただしマウスドラッグ中でも`MouseEvent.MOUSE_ENTERED`と`MouseEvent.MOUSE_EXITED`イベントが発生する場合があるので`MouseEvent.MOUSE_DRAGGED`中は`Timer`を起動しない
--- `MouseEvent.MOUSE_RELEASED`イベントが発生したとき縦`JScrollBar`内にマウスカーソルがある場合は`Timer`を起動しない(幅を拡大した状態を維持する)
-- 縦`JScrollBar`の幅を縮小する場合`500`ミリ秒ウェイトを入れてすぐに`Timer`を起動しないよう設定
- 右:
-- 縦`JScrollBar`の矢印ボタンを非表示に設定
--- [[JScrollBarのArrowButtonを非表示にする>Swing/ArrowButtonlessScrollBar]]
-- マウスカーソルの出入りで縦`JScrollBar`の色と幅を変更
--- [[JScrollBarをJTable上に重ねて表示するJScrollPaneを作成する>Swing/OverlappedScrollBar]]
* Reference [#reference]
- [[JScrollPane上にマウスカーソルが存在する場合のみJScrollBarを表示する>Swing/ScrollBarOnHover]]
* Comment [#comment]
#comment
#comment