Swing/ChangeScrollBarWidthOnHover のバックアップ(No.3)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/ChangeScrollBarWidthOnHover へ行く。
- 1 (2019-09-02 (月) 18:06:34)
- 2 (2019-11-28 (木) 15:52:09)
- 3 (2019-12-19 (木) 15:53:09)
- 4 (2021-06-19 (土) 17:21:49)
- 5 (2024-04-18 (木) 14:41:05)
- 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
概要
JScrollBar
上へのマウスカーソルの出入りをJLayer
で取得してその幅を拡大・縮小します。
Screenshot
Advertisement
サンプルコード
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()));
View in GitHub: Java, Kotlin解説
- 左:
JPanel
にJScrollPane
と縦JScrollBar
を分けて配置JPanel
に縦JScrollBar
の幅をTimer
を使用して拡大・縮小するレイアウトマネージャを設定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
の色と幅を変更
- 縦