JSliderのトラック内部に目盛りを描画する
Total: 1425
, Today: 2
, Yesterday: 0
Posted by aterai at
Last-modified:
概要
JSlider
のトラック内部に大目盛り、ノブ内部に現在値を描画します。
Screenshot
Advertisement
サンプルコード
JSlider slider = new JSlider();
slider.setSnapToTicks(true);
slider.setMajorTickSpacing(10);
slider.addMouseMotionListener(new MouseAdapter() {
@Override public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
e.getComponent().repaint();
}
});
UIDefaults d = new UIDefaults();
d.put("Slider.thumbWidth", 24);
d.put("Slider.thumbHeight", 24);
Painter<JSlider> thumbPainter = (g, c, w, h) -> {
g.setPaint(new Color(0x21_98_F6));
g.fillOval(0, 0, w, h);
NumberIcon icon = new NumberIcon(c.getValue());
int xx = (w - icon.getIconWidth()) / 2;
int yy = (h - icon.getIconHeight()) / 2;
icon.paintIcon(c, g, xx, yy);
};
d.put("Slider:SliderThumb[Disabled].backgroundPainter", thumbPainter);
d.put("Slider:SliderThumb[Enabled].backgroundPainter", thumbPainter);
d.put("Slider:SliderThumb[Focused+MouseOver].backgroundPainter", thumbPainter);
d.put("Slider:SliderThumb[Focused+Pressed].backgroundPainter", thumbPainter);
d.put("Slider:SliderThumb[Focused].backgroundPainter", thumbPainter);
d.put("Slider:SliderThumb[MouseOver].backgroundPainter", thumbPainter);
d.put("Slider:SliderThumb[Pressed].backgroundPainter", thumbPainter);
d.put("Slider:SliderTrack[Enabled].backgroundPainter", new Painter<JSlider>() {
@Override public void paint(Graphics2D g, JSlider c, int w, int h) {
int arc = 10;
int thumbSize = 24;
int trackHeight = 8;
int tickSize = 4;
int trackWidth = w - thumbSize;
int fillTop = (thumbSize - trackHeight) / 2;
int fillLeft = thumbSize / 2;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(new Color(0xC6_E4_FC));
g.fillRoundRect(fillLeft, fillTop + 2, trackWidth, trackHeight - 4, arc, arc);
// Paint track
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(new Color(0xC6_E4_FC));
g.fillRoundRect(fillLeft, fillTop + 2, trackWidth, trackHeight - 4, arc, arc);
int fillBottom = fillTop + trackHeight;
Rectangle r = new Rectangle(fillLeft, fillTop, trackWidth, fillBottom - fillTop);
// Paint the major tick marks on the track
g.setColor(new Color(0x31_A8_F8));
int value = c.getMinimum();
while (value <= c.getMaximum()) {
int xpt = getXPositionForValue(c, r, value);
g.fillOval(xpt, (int) r.getCenterY() - tickSize / 2, tickSize, tickSize);
// Overflow checking
if (Integer.MAX_VALUE - c.getMajorTickSpacing() < value) {
break;
}
value += c.getMajorTickSpacing();
}
// JSlider.isFilled
int fillRight = getXPositionForValue(c, r, c.getValue());
g.setColor(new Color(0x21_98_F6));
g.fillRoundRect(fillLeft, fillTop, fillRight - fillLeft, fillBottom - fillTop, arc, arc);
}
// @see javax/swing/plaf/basic/BasicSliderUI#xPositionForValue(int value)
private int getXPositionForValue(JSlider slider, Rectangle trackRect, float value) {
float min = slider.getMinimum();
float max = slider.getMaximum();
float pixelsPerValue = trackRect.width / (max - min);
int trackLeft = trackRect.x;
int trackRight = trackRect.x + trackRect.width - 1;
int pos = trackLeft + Math.round(pixelsPerValue * (value - min));
return Math.max(trackLeft, Math.min(trackRight, pos));
}
});
slider.putClientProperty("Nimbus.Overrides", d);
View in GitHub: Java, Kotlin解説
Slider:SliderTrack[Enabled].backgroundPainter
- トラック描画用の
Painter<JSlider>
を作成し、そのPainter#paint(...)
メソッドをオーバーライドしてトラック内部に大目盛りを描画 - NimbusLookAndFeelを適用したJSliderで範囲の塗りつぶしを行う
- 垂直
JSlider
やJSlider#setInverted(true)
で値が通常の順序と逆に設定されている場合には未対応
- トラック描画用の
Slider:SliderThumb[Enabled].backgroundPainter
- ノブ描画用の
Painter<JSlider>
を作成し、そのPainter#paint(...)
メソッドをオーバーライドしてノブ内にJSlider#getValue()
で取得した現在値を描画 - JLabel内のアイコンにJLayerを使用してバッジを表示する
- ノブ描画用の
参考リンク
- JSliderでオン・オフ切り替え可能なスイッチボタンを作成する
- JLabel内のアイコンにJLayerを使用してバッジを表示する
- NimbusLookAndFeelを適用したJSliderで範囲の塗りつぶしを行う