---
category: swing
folder: SliderTicksPosition
title: JSliderの目盛り表示位置をトラック上部に変更する
tags: [JSlider, JLayer]
author: aterai
pubdate: 2022-07-18T09:24:25+09:00
description: 水平JSliderの目盛りをトラック上部に表示し、つまみの矢印も上向きに描画するよう変更します。
image: https://drive.google.com/uc?id=1Jm5tHOewLJQ6ExRVgFWdzBBTezrNjzZA
hreflang:
href: https://java-swing-tips.blogspot.com/2022/12/inverse-display-position-of-jsliders.html
lang: en
---
* Summary [#summary]
水平`JSlider`の目盛りをトラック上部に表示し、つまみの矢印も上向きに描画するよう変更します。
#download(https://drive.google.com/uc?id=1Jm5tHOewLJQ6ExRVgFWdzBBTezrNjzZA)
* Source Code Examples [#sourcecode]
#code(link){{
class VerticalFlipLayerUI extends LayerUI<JComponent> {
@Override public void paint(Graphics g, JComponent c) {
if (c instanceof JLayer) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setTransform(getAffineTransform(c.getSize()));
super.paint(g2, c);
g2.dispose();
} else {
super.paint(g, c);
}
}
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
JLayer<?> l = (JLayer<?>) c;
l.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 public void eventDispatched(AWTEvent e, JLayer<? extends JComponent> l) {
if (e instanceof MouseEvent) {
MouseEvent me = (MouseEvent) e;
Point2D pt = me.getPoint();
try {
pt = getAffineTransform(l.getSize()).inverseTransform(pt, null);
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
UIManager.getLookAndFeel().provideErrorFeedback(me.getComponent());
}
// Horizontal: me.translatePoint((int) pt.getX() - me.getX(), 0);
me.translatePoint(0, (int) pt.getY() - me.getY());
me.getComponent().repaint();
}
super.eventDispatched(e, l);
}
private AffineTransform getAffineTransform(Dimension d) {
AffineTransform at = AffineTransform.getTranslateInstance(0d, d.height);
at.scale(1d, -1d);
return at;
}
}
}}
* Description [#explanation]
* Description [#description]
- `VerticalFlipLayerUI`
-- `JLayer`を使用して水平`JSlider`とその内部の`MouseEvent`の上下を反転
-- ラベルの数字も上下反転してしまう
-- `Ubuntu 20.04.4 LTS`で`JLayer`が表示されない場合がある?
--- このサンプルでは`BorderLayout.NORTH`で表示されて`BorderLayout.SOUTH`で非表示になる?
- `UpArrowThumbSliderUI`
-- `BasicSliderUI`の`calculateTrackRect()`、`calculateTickRect()`、`calculateLabelRect()`をオーバーライドしてこの`3`つの領域の描画位置を入れ替える
-- つまみの矢印は`BasicSliderUI#paintThumb()`をオーバーライドしてその場で上下反転描画
-- `MetalLookAndFeel`%%や`WindowsLookAndFeel`%%ではつまみだけ反転するのは難しい?
#code{{
class UpArrowThumbSliderUI extends BasicSliderUI {
protected UpArrowThumbSliderUI(JSlider slider) {
super(slider);
}
@Override protected void calculateTrackRect() {
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
int centerSpacing = thumbRect.height;
if (slider.getPaintTicks()) {
centerSpacing -= getTickLength();
}
if (slider.getPaintLabels()) {
centerSpacing -= getHeightOfTallestLabel();
}
trackRect.x = contentRect.x + trackBuffer;
trackRect.y = contentRect.y + (contentRect.height + centerSpacing + 1) / 2;
trackRect.width = contentRect.width - (trackBuffer * 2);
trackRect.height = thumbRect.height;
} else {
super.calculateTrackRect();
}
}
@Override protected void calculateTickRect() {
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
tickRect.x = trackRect.x;
// tickRect.y = trackRect.y + trackRect.height;
tickRect.y = trackRect.y;
tickRect.width = trackRect.width;
tickRect.height = slider.getPaintTicks() ? getTickLength() : 0;
} else {
super.calculateTickRect();
}
}
@Override protected void calculateLabelRect() {
if (slider.getPaintLabels()) {
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
labelRect.width = tickRect.width + (trackBuffer * 2);
labelRect.height = getHeightOfTallestLabel();
labelRect.x = tickRect.x - trackBuffer;
labelRect.y = tickRect.y - labelRect.height;
} else {
super.calculateLabelRect();
}
} else {
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
labelRect.x = tickRect.x;
labelRect.y = tickRect.y; // + tickRect.height;
labelRect.width = tickRect.width;
labelRect.height = 0;
} else {
super.calculateLabelRect();
}
}
}
@Override public void paintThumb(Graphics g) {
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(0, contentRect.y + contentRect.height + thumbRect.height);
g2.scale(1d, -1d);
super.paintThumb(g2);
g2.dispose();
} else {
super.paintThumb(g);
}
}
}
}}
* Reference [#reference]
- [[JSliderの順序を反転>Swing/InvertedSlider]]
-- 垂直`JSlider`の目盛りをデフォルトの右側から左側に変更する場合は`JSlider#setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT)`が使用可能
* Comment [#comment]
#comment
#comment