JPopupMenuに垂直JSliderを配置してJToggleButtonの上部に表示する
Total: 1170
, Today: 3
, Yesterday: 0
Posted by aterai at
Last-modified:
概要
JPopupMenu
に垂直JSlider
を配置し、JToggleButton
に設定したJToolTip
を表示するときにその上部に重ねて表示します。
Screenshot
Advertisement
サンプルコード
JPopupMenu popup = new JPopupMenu();
popup.setLayout(new BorderLayout());
popup.addMouseWheelListener(InputEvent::consume);
UIManager.put("Slider.paintValue", Boolean.TRUE);
UIManager.put("Slider.focus", UIManager.get("Slider.background"));
JSlider slider = new JSlider(SwingConstants.VERTICAL, 0, 100, 80);
slider.addMouseWheelListener(e -> {
JSlider s = (JSlider) e.getComponent();
if (s.isEnabled()) {
BoundedRangeModel m = s.getModel();
m.setValue(m.getValue() - e.getWheelRotation() * 2);
}
e.consume();
});
popup.add(slider);
JToggleButton button = new JToggleButton("🔊") {
@Override public JToolTip createToolTip() {
JToolTip tip = super.createToolTip();
tip.addHierarchyListener(e -> {
long flg = e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED;
if (flg != 0 && e.getComponent().isShowing()) {
Dimension d = popup.getPreferredSize();
popup.show(this, (getWidth() - d.width) / 2, -d.height);
}
});
return tip;
}
@Override public Point getToolTipLocation(MouseEvent e) {
return new Point(getWidth() / 2, -getHeight());
}
@Override public void setEnabled(boolean b) {
super.setEnabled(b);
setText(b ? "🔊" : "🔇");
}
};
button.setToolTipText("");
button.addMouseListener(new MouseAdapter() {
@Override public void mousePressed(MouseEvent e) {
if (!button.isEnabled()) {
slider.setValue(80);
button.setEnabled(true);
}
Component b = (Component) e.getSource();
Dimension d = popup.getPreferredSize();
popup.show(b, (b.getWidth() - d.width) / 2, -d.height);
}
@Override public void mouseEntered(MouseEvent e) {
if (!popup.isVisible()) {
ToolTipManager.sharedInstance().setEnabled(true);
}
}
@Override public void mouseExited(MouseEvent e) {
if (!popup.isVisible()) {
ToolTipManager.sharedInstance().setEnabled(true);
}
}
});
popup.addPopupMenuListener(new PopupMenuListener() {
@Override public void popupMenuCanceled(PopupMenuEvent e) {
/* not needed */
}
@Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
EventQueue.invokeLater(() -> ToolTipManager.sharedInstance().setEnabled(false));
}
@Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
button.setSelected(false);
}
});
View in GitHub: Java, Kotlin解説
JPopupMenu
- レイアウトを
BorderLayout
に変更して垂直JSlider
をひとつだけ追加 JPopupMenu#addMouseWheelListener(InputEvent::consume)
を追加して余白などでマウスホイールを回転しても閉じないよう設定PopupMenuListener
を追加してJPopupMenu
が開いたあとはJToolTip
を無効化、閉じる前にJToggleButton
の選択状態を解除
- レイアウトを
JSlider
MouseWheelListener
を追加してマウスホイールの回転で値を変更可能に設定ChangeListener
を追加して値が0
(最小値)になったらJToggleButton
を無効化UIManager.put("Slider.paintValue", Boolean.TRUE)
で垂直JSlider
上部に値を常時表示
JToggleButton
JToggleButton#setToolTipText("")
で空文字(JPopupMenu
の幅より短くなる文字)をToolTipText
として設定JToggleButton#createToolTip()
をオーバーライドしJToolTip
にHierarchyListener
を追加JToggleButton#getToolTipLocation()
をオーバーライドし常にJPopupMenu
の背面に表示されるよう位置を調整JToggleButton#setEnabled(...)
をオーバーライドし、有効なら🔊
、無効なら🔇
にテキストを変更JSlider
の値が0
でJToggleButton
が無効状態でもJToolTip
は有効- 無効状態の
JToggleButton
をクリックした場合もJPopupMenu
を開くようにするためActionListener
ではなくMouseListener
を追加MouseListener#mousePressed(...)
でJPopupMenu
を開く前にJToggleButton
が無効状態の場合は値をデフォルトの80
まで戻す- マウスカーソルが出入りしたとき
JPopupMenu
が非表示の場合はJPopupMenu
を開くときに無効化したJToolTip
を有効に戻す
JToolTip
- 追加した
HierarchyListener
でJToolTip
の表示後、重ねてJPopupMenu
を表示するよう設定JPopupMenu
の表示後にJPopupMenu
に追加した上記のPopupMenuListener#popupMenuWillBecomeVisible(...)
でEventQueue.invokeLater( () -> ToolTipManager.sharedInstance().setEnabled(false))
を実行してJToolTip
を無効化
- 追加した
参考リンク
- JSliderの上部に現在値を常時表示する
- JSliderのUIや色を変更する
- WhitespaceAround misrecognizes white spaces after emojis · Issue #10837 · checkstyle/checkstyle
- 「🔊(
U+1F50A
)(\uD83D\uDD0A
)」などの0x0A
(CR/LF
)が誤判定されているようで、このサンプルコードでもWhitespaceAround
の警告が発生するがcheckstyle-9.0.2
で修正されそう?た
- 「🔊(