/*
 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javax.swing.plaf.basic;

import java.awt.event.*;
import java.awt.*;
import java.beans.*;
import java.util.Dictionary;
import java.util.Enumeration;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import sun.swing.DefaultLookup;
import sun.swing.SwingUtilities2;
import sun.swing.UIAction;


A Basic L&F implementation of SliderUI.
Author:Tom Santos
/** * A Basic L&F implementation of SliderUI. * * @author Tom Santos */
public class BasicSliderUI extends SliderUI{ // Old actions forward to an instance of this. private static final Actions SHARED_ACTION = new Actions();
Positive scroll
/** Positive scroll */
public static final int POSITIVE_SCROLL = +1;
Negative scroll
/** Negative scroll */
public static final int NEGATIVE_SCROLL = -1;
Minimum scroll
/** Minimum scroll */
public static final int MIN_SCROLL = -2;
Maximum scroll
/** Maximum scroll */
public static final int MAX_SCROLL = +2;
Scroll timer
/** Scroll timer */
protected Timer scrollTimer;
Slider
/** Slider */
protected JSlider slider;
Focus insets
/** Focus insets */
protected Insets focusInsets = null;
Inset cache
/** Inset cache */
protected Insets insetCache = null;
Left-to-right cache
/** Left-to-right cache */
protected boolean leftToRightCache = true;
Focus rectangle
/** Focus rectangle */
protected Rectangle focusRect = null;
Content rectangle
/** Content rectangle */
protected Rectangle contentRect = null;
Label rectangle
/** Label rectangle */
protected Rectangle labelRect = null;
Tick rectangle
/** Tick rectangle */
protected Rectangle tickRect = null;
Track rectangle
/** Track rectangle */
protected Rectangle trackRect = null;
Thumb rectangle
/** Thumb rectangle */
protected Rectangle thumbRect = null;
The distance that the track is from the side of the control
/** The distance that the track is from the side of the control */
protected int trackBuffer = 0; private transient boolean isDragging;
Track listener
/** Track listener */
protected TrackListener trackListener;
Change listener
/** Change listener */
protected ChangeListener changeListener;
Component listener
/** Component listener */
protected ComponentListener componentListener;
Focus listener
/** Focus listener */
protected FocusListener focusListener;
Scroll listener
/** Scroll listener */
protected ScrollListener scrollListener;
Property chane listener
/** Property chane listener */
protected PropertyChangeListener propertyChangeListener; private Handler handler; private int lastValue; // Colors private Color shadowColor; private Color highlightColor; private Color focusColor;
Whther or not sameLabelBaselines is up to date.
/** * Whther or not sameLabelBaselines is up to date. */
private boolean checkedLabelBaselines;
Whether or not all the entries in the labeltable have the same baseline.
/** * Whether or not all the entries in the labeltable have the same * baseline. */
private boolean sameLabelBaselines;
Returns the shadow color.
Returns:the shadow color
/** * Returns the shadow color. * @return the shadow color */
protected Color getShadowColor() { return shadowColor; }
Returns the highlight color.
Returns:the highlight color
/** * Returns the highlight color. * @return the highlight color */
protected Color getHighlightColor() { return highlightColor; }
Returns the focus color.
Returns:the focus color
/** * Returns the focus color. * @return the focus color */
protected Color getFocusColor() { return focusColor; }
Returns true if the user is dragging the slider.
Returns:true if the user is dragging the slider
Since:1.5
/** * Returns true if the user is dragging the slider. * * @return true if the user is dragging the slider * @since 1.5 */
protected boolean isDragging() { return isDragging; } ///////////////////////////////////////////////////////////////////////////// // ComponentUI Interface Implementation methods /////////////////////////////////////////////////////////////////////////////
Creates a UI.
Params:
  • b – a component
Returns:a UI
/** * Creates a UI. * @param b a component * @return a UI */
public static ComponentUI createUI(JComponent b) { return new BasicSliderUI((JSlider)b); }
Constructs a BasicSliderUI.
Params:
  • b – a slider
/** * Constructs a {@code BasicSliderUI}. * @param b a slider */
public BasicSliderUI(JSlider b) { }
Installs a UI.
Params:
  • c – a component
/** * Installs a UI. * @param c a component */
public void installUI(JComponent c) { slider = (JSlider) c; checkedLabelBaselines = false; slider.setEnabled(slider.isEnabled()); LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE); isDragging = false; trackListener = createTrackListener( slider ); changeListener = createChangeListener( slider ); componentListener = createComponentListener( slider ); focusListener = createFocusListener( slider ); scrollListener = createScrollListener( slider ); propertyChangeListener = createPropertyChangeListener( slider ); installDefaults( slider ); installListeners( slider ); installKeyboardActions( slider ); scrollTimer = new Timer( 100, scrollListener ); scrollTimer.setInitialDelay( 300 ); insetCache = slider.getInsets(); leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider); focusRect = new Rectangle(); contentRect = new Rectangle(); labelRect = new Rectangle(); tickRect = new Rectangle(); trackRect = new Rectangle(); thumbRect = new Rectangle(); lastValue = slider.getValue(); calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are. }
Uninstalls a UI.
Params:
  • c – a component
/** * Uninstalls a UI. * @param c a component */
public void uninstallUI(JComponent c) { if ( c != slider ) throw new IllegalComponentStateException( this + " was asked to deinstall() " + c + " when it only knows about " + slider + "."); scrollTimer.stop(); scrollTimer = null; uninstallDefaults(slider); uninstallListeners( slider ); uninstallKeyboardActions(slider); insetCache = null; leftToRightCache = true; focusRect = null; contentRect = null; labelRect = null; tickRect = null; trackRect = null; thumbRect = null; trackListener = null; changeListener = null; componentListener = null; focusListener = null; scrollListener = null; propertyChangeListener = null; slider = null; }
Installs the defaults.
Params:
  • slider – a slider
/** * Installs the defaults. * @param slider a slider */
protected void installDefaults( JSlider slider ) { LookAndFeel.installBorder(slider, "Slider.border"); LookAndFeel.installColorsAndFont(slider, "Slider.background", "Slider.foreground", "Slider.font"); highlightColor = UIManager.getColor("Slider.highlight"); shadowColor = UIManager.getColor("Slider.shadow"); focusColor = UIManager.getColor("Slider.focus"); focusInsets = (Insets)UIManager.get( "Slider.focusInsets" ); // use default if missing so that BasicSliderUI can be used in other // LAFs like Nimbus if (focusInsets == null) focusInsets = new InsetsUIResource(2,2,2,2); }
Uninstalls the defaults.
Params:
  • slider – a slider
/** * Uninstalls the defaults. * @param slider a slider */
protected void uninstallDefaults(JSlider slider) { LookAndFeel.uninstallBorder(slider); focusInsets = null; }
Creates a track listener.
Params:
  • slider – a slider
Returns:a track listener
/** * Creates a track listener. * @return a track listener * @param slider a slider */
protected TrackListener createTrackListener(JSlider slider) { return new TrackListener(); }
Creates a change listener.
Params:
  • slider – a slider
Returns:a change listener
/** * Creates a change listener. * @return a change listener * @param slider a slider */
protected ChangeListener createChangeListener(JSlider slider) { return getHandler(); }
Creates a composite listener.
Params:
  • slider – a slider
Returns:a composite listener
/** * Creates a composite listener. * @return a composite listener * @param slider a slider */
protected ComponentListener createComponentListener(JSlider slider) { return getHandler(); }
Creates a focus listener.
Params:
  • slider – a slider
Returns:a focus listener
/** * Creates a focus listener. * @return a focus listener * @param slider a slider */
protected FocusListener createFocusListener(JSlider slider) { return getHandler(); }
Creates a scroll listener.
Params:
  • slider – a slider
Returns:a scroll listener
/** * Creates a scroll listener. * @return a scroll listener * @param slider a slider */
protected ScrollListener createScrollListener( JSlider slider ) { return new ScrollListener(); }
Creates a property change listener.
Params:
  • slider – a slider
Returns:a property change listener
/** * Creates a property change listener. * @return a property change listener * @param slider a slider */
protected PropertyChangeListener createPropertyChangeListener( JSlider slider) { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; }
Installs listeners.
Params:
  • slider – a slider
/** * Installs listeners. * @param slider a slider */
protected void installListeners( JSlider slider ) { slider.addMouseListener(trackListener); slider.addMouseMotionListener(trackListener); slider.addFocusListener(focusListener); slider.addComponentListener(componentListener); slider.addPropertyChangeListener( propertyChangeListener ); slider.getModel().addChangeListener(changeListener); }
Uninstalls listeners.
Params:
  • slider – a slider
/** * Uninstalls listeners. * @param slider a slider */
protected void uninstallListeners( JSlider slider ) { slider.removeMouseListener(trackListener); slider.removeMouseMotionListener(trackListener); slider.removeFocusListener(focusListener); slider.removeComponentListener(componentListener); slider.removePropertyChangeListener( propertyChangeListener ); slider.getModel().removeChangeListener(changeListener); handler = null; }
Installs keyboard actions.
Params:
  • slider – a slider
/** * Installs keyboard actions. * @param slider a slider */
protected void installKeyboardActions( JSlider slider ) { InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider); SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km); LazyActionMap.installLazyActionMap(slider, BasicSliderUI.class, "Slider.actionMap"); } InputMap getInputMap(int condition, JSlider slider) { if (condition == JComponent.WHEN_FOCUSED) { InputMap keyMap = (InputMap)DefaultLookup.get(slider, this, "Slider.focusInputMap"); InputMap rtlKeyMap; if (slider.getComponentOrientation().isLeftToRight() || ((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this, "Slider.focusInputMap.RightToLeft")) == null)) { return keyMap; } else { rtlKeyMap.setParent(keyMap); return rtlKeyMap; } } return null; }
Populates ComboBox's actions.
/** * Populates ComboBox's actions. */
static void loadActionMap(LazyActionMap map) { map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT)); map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT)); map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT)); map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT)); map.put(new Actions(Actions.MIN_SCROLL_INCREMENT)); map.put(new Actions(Actions.MAX_SCROLL_INCREMENT)); }
Uninstalls keyboard actions.
Params:
  • slider – a slider
/** * Uninstalls keyboard actions. * @param slider a slider */
protected void uninstallKeyboardActions( JSlider slider ) { SwingUtilities.replaceUIActionMap(slider, null); SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, null); }
Returns the baseline.
Throws:
See Also:
Since:1.6
/** * Returns the baseline. * * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */
public int getBaseline(JComponent c, int width, int height) { super.getBaseline(c, width, height); if (slider.getPaintLabels() && labelsHaveSameBaselines()) { FontMetrics metrics = slider.getFontMetrics(slider.getFont()); Insets insets = slider.getInsets(); Dimension thumbSize = getThumbSize(); if (slider.getOrientation() == JSlider.HORIZONTAL) { int tickLength = getTickLength(); int contentHeight = height - insets.top - insets.bottom - focusInsets.top - focusInsets.bottom; int thumbHeight = thumbSize.height; int centerSpacing = thumbHeight; if (slider.getPaintTicks()) { centerSpacing += tickLength; } // Assume uniform labels. centerSpacing += getHeightOfTallestLabel(); int trackY = insets.top + focusInsets.top + (contentHeight - centerSpacing - 1) / 2; int trackHeight = thumbHeight; int tickY = trackY + trackHeight; int tickHeight = tickLength; if (!slider.getPaintTicks()) { tickHeight = 0; } int labelY = tickY + tickHeight; return labelY + metrics.getAscent(); } else { // vertical boolean inverted = slider.getInverted(); Integer value = inverted ? getLowestValue() : getHighestValue(); if (value != null) { int thumbHeight = thumbSize.height; int trackBuffer = Math.max(metrics.getHeight() / 2, thumbHeight / 2); int contentY = focusInsets.top + insets.top; int trackY = contentY + trackBuffer; int trackHeight = height - focusInsets.top - focusInsets.bottom - insets.top - insets.bottom - trackBuffer - trackBuffer; int yPosition = yPositionForValue(value, trackY, trackHeight); return yPosition - metrics.getHeight() / 2 + metrics.getAscent(); } } } return 0; }
Returns an enum indicating how the baseline of the component changes as the size changes.
Throws:
  • NullPointerException – {@inheritDoc}
See Also:
Since:1.6
/** * Returns an enum indicating how the baseline of the component * changes as the size changes. * * @throws NullPointerException {@inheritDoc} * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */
public Component.BaselineResizeBehavior getBaselineResizeBehavior( JComponent c) { super.getBaselineResizeBehavior(c); // NOTE: BasicSpinner really provides for CENTER_OFFSET, but // the default min/pref size is smaller than it should be // so that getBaseline() doesn't implement the contract // for CENTER_OFFSET as defined in Component. return Component.BaselineResizeBehavior.OTHER; }
Returns true if all the labels from the label table have the same baseline.
Returns:true if all the labels from the label table have the same baseline
Since:1.6
/** * Returns true if all the labels from the label table have the same * baseline. * * @return true if all the labels from the label table have the * same baseline * @since 1.6 */
protected boolean labelsHaveSameBaselines() { if (!checkedLabelBaselines) { checkedLabelBaselines = true; @SuppressWarnings("rawtypes") Dictionary dictionary = slider.getLabelTable(); if (dictionary != null) { sameLabelBaselines = true; Enumeration<?> elements = dictionary.elements(); int baseline = -1; while (elements.hasMoreElements()) { JComponent label = (JComponent) elements.nextElement(); Dimension pref = label.getPreferredSize(); int labelBaseline = label.getBaseline(pref.width, pref.height); if (labelBaseline >= 0) { if (baseline == -1) { baseline = labelBaseline; } else if (baseline != labelBaseline) { sameLabelBaselines = false; break; } } else { sameLabelBaselines = false; break; } } } else { sameLabelBaselines = false; } } return sameLabelBaselines; }
Returns the preferred horizontal size.
Returns:the preferred horizontal size
/** * Returns the preferred horizontal size. * @return the preferred horizontal size */
public Dimension getPreferredHorizontalSize() { Dimension horizDim = (Dimension)DefaultLookup.get(slider, this, "Slider.horizontalSize"); if (horizDim == null) { horizDim = new Dimension(200, 21); } return horizDim; }
Returns the preferred vertical size.
Returns:the preferred vertical size
/** * Returns the preferred vertical size. * @return the preferred vertical size */
public Dimension getPreferredVerticalSize() { Dimension vertDim = (Dimension)DefaultLookup.get(slider, this, "Slider.verticalSize"); if (vertDim == null) { vertDim = new Dimension(21, 200); } return vertDim; }
Returns the minimum horizontal size.
Returns:the minimum horizontal size
/** * Returns the minimum horizontal size. * @return the minimum horizontal size */
public Dimension getMinimumHorizontalSize() { Dimension minHorizDim = (Dimension)DefaultLookup.get(slider, this, "Slider.minimumHorizontalSize"); if (minHorizDim == null) { minHorizDim = new Dimension(36, 21); } return minHorizDim; }
Returns the minimum vertical size.
Returns:the minimum vertical size
/** * Returns the minimum vertical size. * @return the minimum vertical size */
public Dimension getMinimumVerticalSize() { Dimension minVertDim = (Dimension)DefaultLookup.get(slider, this, "Slider.minimumVerticalSize"); if (minVertDim == null) { minVertDim = new Dimension(21, 36); } return minVertDim; }
Returns the preferred size.
Params:
  • c – a component
Returns:the preferred size
/** * Returns the preferred size. * @param c a component * @return the preferred size */
public Dimension getPreferredSize(JComponent c) { recalculateIfInsetsChanged(); Dimension d; if ( slider.getOrientation() == JSlider.VERTICAL ) { d = new Dimension(getPreferredVerticalSize()); d.width = insetCache.left + insetCache.right; d.width += focusInsets.left + focusInsets.right; d.width += trackRect.width + tickRect.width + labelRect.width; } else { d = new Dimension(getPreferredHorizontalSize()); d.height = insetCache.top + insetCache.bottom; d.height += focusInsets.top + focusInsets.bottom; d.height += trackRect.height + tickRect.height + labelRect.height; } return d; }
Returns the minimum size.
Params:
  • c – a component
Returns:the minimum size
/** * Returns the minimum size. * @param c a component * @return the minimum size */
public Dimension getMinimumSize(JComponent c) { recalculateIfInsetsChanged(); Dimension d; if ( slider.getOrientation() == JSlider.VERTICAL ) { d = new Dimension(getMinimumVerticalSize()); d.width = insetCache.left + insetCache.right; d.width += focusInsets.left + focusInsets.right; d.width += trackRect.width + tickRect.width + labelRect.width; } else { d = new Dimension(getMinimumHorizontalSize()); d.height = insetCache.top + insetCache.bottom; d.height += focusInsets.top + focusInsets.bottom; d.height += trackRect.height + tickRect.height + labelRect.height; } return d; }
Returns the maximum size.
Params:
  • c – a component
Returns:the maximum size
/** * Returns the maximum size. * @param c a component * @return the maximum size */
public Dimension getMaximumSize(JComponent c) { Dimension d = getPreferredSize(c); if ( slider.getOrientation() == JSlider.VERTICAL ) { d.height = Short.MAX_VALUE; } else { d.width = Short.MAX_VALUE; } return d; }
Calculates the geometry.
/** * Calculates the geometry. */
protected void calculateGeometry() { calculateFocusRect(); calculateContentRect(); calculateThumbSize(); calculateTrackBuffer(); calculateTrackRect(); calculateTickRect(); calculateLabelRect(); calculateThumbLocation(); }
Calculates the focus rectangle.
/** * Calculates the focus rectangle. */
protected void calculateFocusRect() { focusRect.x = insetCache.left; focusRect.y = insetCache.top; focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right); focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom); }
Calculates the thumb size rectangle.
/** * Calculates the thumb size rectangle. */
protected void calculateThumbSize() { Dimension size = getThumbSize(); thumbRect.setSize( size.width, size.height ); }
Calculates the content rectangle.
/** * Calculates the content rectangle. */
protected void calculateContentRect() { contentRect.x = focusRect.x + focusInsets.left; contentRect.y = focusRect.y + focusInsets.top; contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right); contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom); } private int getTickSpacing() { int majorTickSpacing = slider.getMajorTickSpacing(); int minorTickSpacing = slider.getMinorTickSpacing(); int result; if (minorTickSpacing > 0) { result = minorTickSpacing; } else if (majorTickSpacing > 0) { result = majorTickSpacing; } else { result = 0; } return result; }
Calculates the thumb location.
/** * Calculates the thumb location. */
protected void calculateThumbLocation() { if ( slider.getSnapToTicks() ) { int sliderValue = slider.getValue(); int snappedValue = sliderValue; int tickSpacing = getTickSpacing(); if ( tickSpacing != 0 ) { // If it's not on a tick, change the value if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) { float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing; int whichTick = Math.round( temp ); // This is the fix for the bug #6401380 if (temp - (int)temp == .5 && sliderValue < lastValue) { whichTick --; } snappedValue = slider.getMinimum() + (whichTick * tickSpacing); } if( snappedValue != sliderValue ) { slider.setValue( snappedValue ); } } } if ( slider.getOrientation() == JSlider.HORIZONTAL ) { int valuePosition = xPositionForValue(slider.getValue()); thumbRect.x = valuePosition - (thumbRect.width / 2); thumbRect.y = trackRect.y; } else { int valuePosition = yPositionForValue(slider.getValue()); thumbRect.x = trackRect.x; thumbRect.y = valuePosition - (thumbRect.height / 2); } }
Calculates the track buffer.
/** * Calculates the track buffer. */
protected void calculateTrackBuffer() { if ( slider.getPaintLabels() && slider.getLabelTable() != null ) { Component highLabel = getHighestValueLabel(); Component lowLabel = getLowestValueLabel(); if ( slider.getOrientation() == JSlider.HORIZONTAL ) { trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2; trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 ); } else { trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2; trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 ); } } else { if ( slider.getOrientation() == JSlider.HORIZONTAL ) { trackBuffer = thumbRect.width / 2; } else { trackBuffer = thumbRect.height / 2; } } }
Calculates the track rectangle.
/** * Calculates the track rectangle. */
protected void calculateTrackRect() { int centerSpacing; // used to center sliders added using BorderLayout.CENTER (bug 4275631) if ( slider.getOrientation() == JSlider.HORIZONTAL ) { 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 { centerSpacing = thumbRect.width; if (BasicGraphicsUtils.isLeftToRight(slider)) { if ( slider.getPaintTicks() ) centerSpacing += getTickLength(); if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel(); } else { if ( slider.getPaintTicks() ) centerSpacing -= getTickLength(); if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel(); } trackRect.x = contentRect.x + (contentRect.width - centerSpacing - 1)/2; trackRect.y = contentRect.y + trackBuffer; trackRect.width = thumbRect.width; trackRect.height = contentRect.height - (trackBuffer * 2); } }
Gets the height of the tick area for horizontal sliders and the width of the tick area for vertical sliders. BasicSliderUI uses the returned value to determine the tick area rectangle. If you want to give your ticks some room, make this larger than you need and paint your ticks away from the sides in paintTicks().
Returns:an integer representing the height of the tick area for horizontal sliders, and the width of the tick area for the vertical sliders
/** * Gets the height of the tick area for horizontal sliders and the width of * the tick area for vertical sliders. BasicSliderUI uses the returned value * to determine the tick area rectangle. If you want to give your ticks some * room, make this larger than you need and paint your ticks away from the * sides in paintTicks(). * * @return an integer representing the height of the tick area for * horizontal sliders, and the width of the tick area for the vertical * sliders */
protected int getTickLength() { return 8; }
Calculates the tick rectangle.
/** * Calculates the tick rectangle. */
protected void calculateTickRect() { if ( slider.getOrientation() == JSlider.HORIZONTAL ) { tickRect.x = trackRect.x; tickRect.y = trackRect.y + trackRect.height; tickRect.width = trackRect.width; tickRect.height = (slider.getPaintTicks()) ? getTickLength() : 0; } else { tickRect.width = (slider.getPaintTicks()) ? getTickLength() : 0; if(BasicGraphicsUtils.isLeftToRight(slider)) { tickRect.x = trackRect.x + trackRect.width; } else { tickRect.x = trackRect.x - tickRect.width; } tickRect.y = trackRect.y; tickRect.height = trackRect.height; } }
Calculates the label rectangle.
/** * Calculates the label rectangle. */
protected void calculateLabelRect() { if ( slider.getPaintLabels() ) { if ( slider.getOrientation() == JSlider.HORIZONTAL ) { labelRect.x = tickRect.x - trackBuffer; labelRect.y = tickRect.y + tickRect.height; labelRect.width = tickRect.width + (trackBuffer * 2); labelRect.height = getHeightOfTallestLabel(); } else { if(BasicGraphicsUtils.isLeftToRight(slider)) { labelRect.x = tickRect.x + tickRect.width; labelRect.width = getWidthOfWidestLabel(); } else { labelRect.width = getWidthOfWidestLabel(); labelRect.x = tickRect.x - labelRect.width; } labelRect.y = tickRect.y - trackBuffer; labelRect.height = tickRect.height + (trackBuffer * 2); } } else { if ( slider.getOrientation() == JSlider.HORIZONTAL ) { labelRect.x = tickRect.x; labelRect.y = tickRect.y + tickRect.height; labelRect.width = tickRect.width; labelRect.height = 0; } else { if(BasicGraphicsUtils.isLeftToRight(slider)) { labelRect.x = tickRect.x + tickRect.width; } else { labelRect.x = tickRect.x; } labelRect.y = tickRect.y; labelRect.width = 0; labelRect.height = tickRect.height; } } }
Returns the thumb size.
Returns:the thumb size
/** * Returns the thumb size. * @return the thumb size */
protected Dimension getThumbSize() { Dimension size = new Dimension(); if ( slider.getOrientation() == JSlider.VERTICAL ) { size.width = 20; size.height = 11; } else { size.width = 11; size.height = 20; } return size; }
A property change handler.
/** * A property change handler. */
public class PropertyChangeHandler implements PropertyChangeListener { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Handler. If you need to add // new functionality add it to the Handler, but make sure this // class calls into the Handler.
{@inheritDoc}
/** {@inheritDoc} */
public void propertyChange( PropertyChangeEvent e ) { getHandler().propertyChange(e); } }
Returns the width of the widest label.
Returns:the width of the widest label
/** * Returns the width of the widest label. * @return the width of the widest label */
protected int getWidthOfWidestLabel() { @SuppressWarnings("rawtypes") Dictionary dictionary = slider.getLabelTable(); int widest = 0; if ( dictionary != null ) { Enumeration<?> keys = dictionary.keys(); while ( keys.hasMoreElements() ) { JComponent label = (JComponent) dictionary.get(keys.nextElement()); widest = Math.max( label.getPreferredSize().width, widest ); } } return widest; }
Returns the height of the tallest label.
Returns:the height of the tallest label
/** * Returns the height of the tallest label. * @return the height of the tallest label */
protected int getHeightOfTallestLabel() { @SuppressWarnings("rawtypes") Dictionary dictionary = slider.getLabelTable(); int tallest = 0; if ( dictionary != null ) { Enumeration<?> keys = dictionary.keys(); while ( keys.hasMoreElements() ) { JComponent label = (JComponent) dictionary.get(keys.nextElement()); tallest = Math.max( label.getPreferredSize().height, tallest ); } } return tallest; }
Returns the width of the highest value label.
Returns:the width of the highest value label
/** * Returns the width of the highest value label. * @return the width of the highest value label */
protected int getWidthOfHighValueLabel() { Component label = getHighestValueLabel(); int width = 0; if ( label != null ) { width = label.getPreferredSize().width; } return width; }
Returns the width of the lowest value label.
Returns:the width of the lowest value label
/** * Returns the width of the lowest value label. * @return the width of the lowest value label */
protected int getWidthOfLowValueLabel() { Component label = getLowestValueLabel(); int width = 0; if ( label != null ) { width = label.getPreferredSize().width; } return width; }
Returns the height of the highest value label.
Returns:the height of the highest value label
/** * Returns the height of the highest value label. * @return the height of the highest value label */
protected int getHeightOfHighValueLabel() { Component label = getHighestValueLabel(); int height = 0; if ( label != null ) { height = label.getPreferredSize().height; } return height; }
Returns the height of the lowest value label.
Returns:the height of the lowest value label
/** * Returns the height of the lowest value label. * @return the height of the lowest value label */
protected int getHeightOfLowValueLabel() { Component label = getLowestValueLabel(); int height = 0; if ( label != null ) { height = label.getPreferredSize().height; } return height; }
Draws inverted.
Returns:the inverted-ness
/** * Draws inverted. * @return the inverted-ness */
protected boolean drawInverted() { if (slider.getOrientation()==JSlider.HORIZONTAL) { if(BasicGraphicsUtils.isLeftToRight(slider)) { return slider.getInverted(); } else { return !slider.getInverted(); } } else { return slider.getInverted(); } }
Returns the biggest value that has an entry in the label table.
Returns:biggest value that has an entry in the label table, or null.
Since:1.6
/** * Returns the biggest value that has an entry in the label table. * * @return biggest value that has an entry in the label table, or * null. * @since 1.6 */
protected Integer getHighestValue() { @SuppressWarnings("rawtypes") Dictionary dictionary = slider.getLabelTable(); if (dictionary == null) { return null; } Enumeration<?> keys = dictionary.keys(); Integer max = null; while (keys.hasMoreElements()) { Integer i = (Integer) keys.nextElement(); if (max == null || i > max) { max = i; } } return max; }
Returns the smallest value that has an entry in the label table.
Returns:smallest value that has an entry in the label table, or null.
Since:1.6
/** * Returns the smallest value that has an entry in the label table. * * @return smallest value that has an entry in the label table, or * null. * @since 1.6 */
protected Integer getLowestValue() { @SuppressWarnings("rawtypes") Dictionary dictionary = slider.getLabelTable(); if (dictionary == null) { return null; } Enumeration<?> keys = dictionary.keys(); Integer min = null; while (keys.hasMoreElements()) { Integer i = (Integer) keys.nextElement(); if (min == null || i < min) { min = i; } } return min; }
Returns the label that corresponds to the highest slider value in the label table.
See Also:
Returns:the label that corresponds to the highest slider value in the label table
/** * Returns the label that corresponds to the highest slider value in the * label table. * * @return the label that corresponds to the highest slider value in the * label table * @see JSlider#setLabelTable */
protected Component getLowestValueLabel() { Integer min = getLowestValue(); if (min != null) { return (Component)slider.getLabelTable().get(min); } return null; }
Returns the label that corresponds to the lowest slider value in the label table.
See Also:
Returns:the label that corresponds to the lowest slider value in the label table
/** * Returns the label that corresponds to the lowest slider value in the * label table. * * @return the label that corresponds to the lowest slider value in the * label table * @see JSlider#setLabelTable */
protected Component getHighestValueLabel() { Integer max = getHighestValue(); if (max != null) { return (Component)slider.getLabelTable().get(max); } return null; } public void paint( Graphics g, JComponent c ) { recalculateIfInsetsChanged(); recalculateIfOrientationChanged(); Rectangle clip = g.getClipBounds(); if ( !clip.intersects(trackRect) && slider.getPaintTrack()) calculateGeometry(); if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) { paintTrack( g ); } if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) { paintTicks( g ); } if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) { paintLabels( g ); } if ( slider.hasFocus() && clip.intersects( focusRect ) ) { paintFocus( g ); } if ( clip.intersects( thumbRect ) ) { paintThumb( g ); } }
Recalculates if the insets have changed.
/** * Recalculates if the insets have changed. */
protected void recalculateIfInsetsChanged() { Insets newInsets = slider.getInsets(); if ( !newInsets.equals( insetCache ) ) { insetCache = newInsets; calculateGeometry(); } }
Recalculates if the orientation has changed.
/** * Recalculates if the orientation has changed. */
protected void recalculateIfOrientationChanged() { boolean ltr = BasicGraphicsUtils.isLeftToRight(slider); if ( ltr!=leftToRightCache ) { leftToRightCache = ltr; calculateGeometry(); } }
Paints focus.
Params:
  • g – the graphics
/** * Paints focus. * @param g the graphics */
public void paintFocus(Graphics g) { g.setColor( getFocusColor() ); BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y, focusRect.width, focusRect.height ); }
Paints track.
Params:
  • g – the graphics
/** * Paints track. * @param g the graphics */
public void paintTrack(Graphics g) { Rectangle trackBounds = trackRect; if ( slider.getOrientation() == JSlider.HORIZONTAL ) { int cy = (trackBounds.height / 2) - 2; int cw = trackBounds.width; g.translate(trackBounds.x, trackBounds.y + cy); g.setColor(getShadowColor()); g.drawLine(0, 0, cw - 1, 0); g.drawLine(0, 1, 0, 2); g.setColor(getHighlightColor()); g.drawLine(0, 3, cw, 3); g.drawLine(cw, 0, cw, 3); g.setColor(Color.black); g.drawLine(1, 1, cw-2, 1); g.translate(-trackBounds.x, -(trackBounds.y + cy)); } else { int cx = (trackBounds.width / 2) - 2; int ch = trackBounds.height; g.translate(trackBounds.x + cx, trackBounds.y); g.setColor(getShadowColor()); g.drawLine(0, 0, 0, ch - 1); g.drawLine(1, 0, 2, 0); g.setColor(getHighlightColor()); g.drawLine(3, 0, 3, ch); g.drawLine(0, ch, 3, ch); g.setColor(Color.black); g.drawLine(1, 1, 1, ch-2); g.translate(-(trackBounds.x + cx), -trackBounds.y); } }
Paints ticks.
Params:
  • g – the graphics
/** * Paints ticks. * @param g the graphics */
public void paintTicks(Graphics g) { Rectangle tickBounds = tickRect; g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black)); if ( slider.getOrientation() == JSlider.HORIZONTAL ) { g.translate(0, tickBounds.y); if (slider.getMinorTickSpacing() > 0) { int value = slider.getMinimum(); while ( value <= slider.getMaximum() ) { int xPos = xPositionForValue(value); paintMinorTickForHorizSlider( g, tickBounds, xPos ); // Overflow checking if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) { break; } value += slider.getMinorTickSpacing(); } } if (slider.getMajorTickSpacing() > 0) { int value = slider.getMinimum(); while ( value <= slider.getMaximum() ) { int xPos = xPositionForValue(value); paintMajorTickForHorizSlider( g, tickBounds, xPos ); // Overflow checking if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) { break; } value += slider.getMajorTickSpacing(); } } g.translate( 0, -tickBounds.y); } else { g.translate(tickBounds.x, 0); if (slider.getMinorTickSpacing() > 0) { int offset = 0; if(!BasicGraphicsUtils.isLeftToRight(slider)) { offset = tickBounds.width - tickBounds.width / 2; g.translate(offset, 0); } int value = slider.getMinimum(); while (value <= slider.getMaximum()) { int yPos = yPositionForValue(value); paintMinorTickForVertSlider( g, tickBounds, yPos ); // Overflow checking if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) { break; } value += slider.getMinorTickSpacing(); } if(!BasicGraphicsUtils.isLeftToRight(slider)) { g.translate(-offset, 0); } } if (slider.getMajorTickSpacing() > 0) { if(!BasicGraphicsUtils.isLeftToRight(slider)) { g.translate(2, 0); } int value = slider.getMinimum(); while (value <= slider.getMaximum()) { int yPos = yPositionForValue(value); paintMajorTickForVertSlider( g, tickBounds, yPos ); // Overflow checking if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) { break; } value += slider.getMajorTickSpacing(); } if(!BasicGraphicsUtils.isLeftToRight(slider)) { g.translate(-2, 0); } } g.translate(-tickBounds.x, 0); } }
Paints minor tick for horizontal slider.
Params:
  • g – the graphics
  • tickBounds – the tick bounds
  • x – the x coordinate
/** * Paints minor tick for horizontal slider. * @param g the graphics * @param tickBounds the tick bounds * @param x the x coordinate */
protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { g.drawLine( x, 0, x, tickBounds.height / 2 - 1 ); }
Paints major tick for horizontal slider.
Params:
  • g – the graphics
  • tickBounds – the tick bounds
  • x – the x coordinate
/** * Paints major tick for horizontal slider. * @param g the graphics * @param tickBounds the tick bounds * @param x the x coordinate */
protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { g.drawLine( x, 0, x, tickBounds.height - 2 ); }
Paints minor tick for vertical slider.
Params:
  • g – the graphics
  • tickBounds – the tick bounds
  • y – the y coordinate
/** * Paints minor tick for vertical slider. * @param g the graphics * @param tickBounds the tick bounds * @param y the y coordinate */
protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { g.drawLine( 0, y, tickBounds.width / 2 - 1, y ); }
Paints major tick for vertical slider.
Params:
  • g – the graphics
  • tickBounds – the tick bounds
  • y – the y coordinate
/** * Paints major tick for vertical slider. * @param g the graphics * @param tickBounds the tick bounds * @param y the y coordinate */
protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { g.drawLine( 0, y, tickBounds.width - 2, y ); }
Paints the labels.
Params:
  • g – the graphics
/** * Paints the labels. * @param g the graphics */
public void paintLabels( Graphics g ) { Rectangle labelBounds = labelRect; @SuppressWarnings("rawtypes") Dictionary dictionary = slider.getLabelTable(); if ( dictionary != null ) { Enumeration<?> keys = dictionary.keys(); int minValue = slider.getMinimum(); int maxValue = slider.getMaximum(); boolean enabled = slider.isEnabled(); while ( keys.hasMoreElements() ) { Integer key = (Integer)keys.nextElement(); int value = key.intValue(); if (value >= minValue && value <= maxValue) { JComponent label = (JComponent) dictionary.get(key); label.setEnabled(enabled); if (label instanceof JLabel) { Icon icon = label.isEnabled() ? ((JLabel) label).getIcon() : ((JLabel) label).getDisabledIcon(); if (icon instanceof ImageIcon) { // Register Slider as an image observer. It allows to catch notifications about // image changes (e.g. gif animation) Toolkit.getDefaultToolkit().checkImage(((ImageIcon) icon).getImage(), -1, -1, slider); } } if ( slider.getOrientation() == JSlider.HORIZONTAL ) { g.translate( 0, labelBounds.y ); paintHorizontalLabel( g, value, label ); g.translate( 0, -labelBounds.y ); } else { int offset = 0; if (!BasicGraphicsUtils.isLeftToRight(slider)) { offset = labelBounds.width - label.getPreferredSize().width; } g.translate( labelBounds.x + offset, 0 ); paintVerticalLabel( g, value, label ); g.translate( -labelBounds.x - offset, 0 ); } } } } }
Called for every label in the label table. Used to draw the labels for horizontal sliders. The graphics have been translated to labelRect.y already.
Params:
  • g – the graphics context in which to paint
  • value – the value of the slider
  • label – the component label in the label table that needs to be painted
See Also:
/** * Called for every label in the label table. Used to draw the labels for * horizontal sliders. The graphics have been translated to labelRect.y * already. * * @param g the graphics context in which to paint * @param value the value of the slider * @param label the component label in the label table that needs to be * painted * @see JSlider#setLabelTable */
protected void paintHorizontalLabel( Graphics g, int value, Component label ) { int labelCenter = xPositionForValue( value ); int labelLeft = labelCenter - (label.getPreferredSize().width / 2); g.translate( labelLeft, 0 ); label.paint( g ); g.translate( -labelLeft, 0 ); }
Called for every label in the label table. Used to draw the labels for vertical sliders. The graphics have been translated to labelRect.x already.
Params:
  • g – the graphics context in which to paint
  • value – the value of the slider
  • label – the component label in the label table that needs to be painted
See Also:
/** * Called for every label in the label table. Used to draw the labels for * vertical sliders. The graphics have been translated to labelRect.x * already. * * @param g the graphics context in which to paint * @param value the value of the slider * @param label the component label in the label table that needs to be * painted * @see JSlider#setLabelTable */
protected void paintVerticalLabel( Graphics g, int value, Component label ) { int labelCenter = yPositionForValue( value ); int labelTop = labelCenter - (label.getPreferredSize().height / 2); g.translate( 0, labelTop ); label.paint( g ); g.translate( 0, -labelTop ); }
Paints the thumb.
Params:
  • g – the graphics
/** * Paints the thumb. * @param g the graphics */
public void paintThumb(Graphics g) { Rectangle knobBounds = thumbRect; int w = knobBounds.width; int h = knobBounds.height; g.translate(knobBounds.x, knobBounds.y); if ( slider.isEnabled() ) { g.setColor(slider.getBackground()); } else { g.setColor(slider.getBackground().darker()); } Boolean paintThumbArrowShape = (Boolean)slider.getClientProperty("Slider.paintThumbArrowShape"); if ((!slider.getPaintTicks() && paintThumbArrowShape == null) || paintThumbArrowShape == Boolean.FALSE) { // "plain" version g.fillRect(0, 0, w, h); g.setColor(Color.black); g.drawLine(0, h-1, w-1, h-1); g.drawLine(w-1, 0, w-1, h-1); g.setColor(highlightColor); g.drawLine(0, 0, 0, h-2); g.drawLine(1, 0, w-2, 0); g.setColor(shadowColor); g.drawLine(1, h-2, w-2, h-2); g.drawLine(w-2, 1, w-2, h-3); } else if ( slider.getOrientation() == JSlider.HORIZONTAL ) { int cw = w / 2; g.fillRect(1, 1, w-3, h-1-cw); Polygon p = new Polygon(); p.addPoint(1, h-cw); p.addPoint(cw-1, h-1); p.addPoint(w-2, h-1-cw); g.fillPolygon(p); g.setColor(highlightColor); g.drawLine(0, 0, w-2, 0); g.drawLine(0, 1, 0, h-1-cw); g.drawLine(0, h-cw, cw-1, h-1); g.setColor(Color.black); g.drawLine(w-1, 0, w-1, h-2-cw); g.drawLine(w-1, h-1-cw, w-1-cw, h-1); g.setColor(shadowColor); g.drawLine(w-2, 1, w-2, h-2-cw); g.drawLine(w-2, h-1-cw, w-1-cw, h-2); } else { // vertical int cw = h / 2; if(BasicGraphicsUtils.isLeftToRight(slider)) { g.fillRect(1, 1, w-1-cw, h-3); Polygon p = new Polygon(); p.addPoint(w-cw-1, 0); p.addPoint(w-1, cw); p.addPoint(w-1-cw, h-2); g.fillPolygon(p); g.setColor(highlightColor); g.drawLine(0, 0, 0, h - 2); // left g.drawLine(1, 0, w-1-cw, 0); // top g.drawLine(w-cw-1, 0, w-1, cw); // top slant g.setColor(Color.black); g.drawLine(0, h-1, w-2-cw, h-1); // bottom g.drawLine(w-1-cw, h-1, w-1, h-1-cw); // bottom slant g.setColor(shadowColor); g.drawLine(1, h-2, w-2-cw, h-2 ); // bottom g.drawLine(w-1-cw, h-2, w-2, h-cw-1 ); // bottom slant } else { g.fillRect(5, 1, w-1-cw, h-3); Polygon p = new Polygon(); p.addPoint(cw, 0); p.addPoint(0, cw); p.addPoint(cw, h-2); g.fillPolygon(p); g.setColor(highlightColor); g.drawLine(cw-1, 0, w-2, 0); // top g.drawLine(0, cw, cw, 0); // top slant g.setColor(Color.black); g.drawLine(0, h-1-cw, cw, h-1 ); // bottom slant g.drawLine(cw, h-1, w-1, h-1); // bottom g.setColor(shadowColor); g.drawLine(cw, h-2, w-2, h-2 ); // bottom g.drawLine(w-1, 1, w-1, h-2 ); // right } } g.translate(-knobBounds.x, -knobBounds.y); } // Used exclusively by setThumbLocation() private static Rectangle unionRect = new Rectangle();
Sets the thumb location.
Params:
  • x – the x coordinate
  • y – the y coordinate
/** * Sets the thumb location. * @param x the x coordinate * @param y the y coordinate */
public void setThumbLocation(int x, int y) { unionRect.setBounds( thumbRect ); thumbRect.setLocation( x, y ); SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect ); slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height ); }
Scrolls by block.
Params:
  • direction – the direction
/** * Scrolls by block. * @param direction the direction */
public void scrollByBlock(int direction) { synchronized(slider) { int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / 10; if (blockIncrement == 0) { blockIncrement = 1; } int tickSpacing = getTickSpacing(); if (slider.getSnapToTicks()) { if (blockIncrement < tickSpacing) { blockIncrement = tickSpacing; } } else { if (tickSpacing > 0) { blockIncrement = tickSpacing; } } int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); slider.setValue(slider.getValue() + delta); } }
Scrolls by unit.
Params:
  • direction – the direction
/** * Scrolls by unit. * @param direction the direction */
public void scrollByUnit(int direction) { synchronized(slider) { int delta = ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); if (slider.getSnapToTicks()) { delta *= getTickSpacing(); } slider.setValue(slider.getValue() + delta); } }
This function is called when a mousePressed was detected in the track, not in the thumb. The default behavior is to scroll by block. You can override this method to stop it from scrolling or to add additional behavior.
Params:
  • dir – the direction and number of blocks to scroll
/** * This function is called when a mousePressed was detected in the track, * not in the thumb. The default behavior is to scroll by block. You can * override this method to stop it from scrolling or to add additional * behavior. * * @param dir the direction and number of blocks to scroll */
protected void scrollDueToClickInTrack( int dir ) { scrollByBlock( dir ); }
Returns the x position for a value.
Params:
  • value – the value
Returns:the x position for a value
/** * Returns the x position for a value. * @param value the value * @return the x position for a value */
protected int xPositionForValue( int value ) { int min = slider.getMinimum(); int max = slider.getMaximum(); int trackLength = trackRect.width; double valueRange = (double)max - (double)min; double pixelsPerValue = (double)trackLength / valueRange; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); int xPosition; if ( !drawInverted() ) { xPosition = trackLeft; xPosition += Math.round( pixelsPerValue * ((double)value - min) ); } else { xPosition = trackRight; xPosition -= Math.round( pixelsPerValue * ((double)value - min) ); } xPosition = Math.max( trackLeft, xPosition ); xPosition = Math.min( trackRight, xPosition ); return xPosition; }
Returns the y position for a value.
Params:
  • value – the value
Returns:the y position for a value
/** * Returns the y position for a value. * @param value the value * @return the y position for a value */
protected int yPositionForValue( int value ) { return yPositionForValue(value, trackRect.y, trackRect.height); }
Returns the y location for the specified value. No checking is done on the arguments. In particular if trackHeight is negative undefined results may occur.
Params:
  • value – the slider value to get the location for
  • trackY – y-origin of the track
  • trackHeight – the height of the track
Returns:the y location for the specified value of the slider
Since:1.6
/** * Returns the y location for the specified value. No checking is * done on the arguments. In particular if <code>trackHeight</code> is * negative undefined results may occur. * * @param value the slider value to get the location for * @param trackY y-origin of the track * @param trackHeight the height of the track * @return the y location for the specified value of the slider * @since 1.6 */
protected int yPositionForValue(int value, int trackY, int trackHeight) { int min = slider.getMinimum(); int max = slider.getMaximum(); double valueRange = (double)max - (double)min; double pixelsPerValue = (double)trackHeight / valueRange; int trackBottom = trackY + (trackHeight - 1); int yPosition; if ( !drawInverted() ) { yPosition = trackY; yPosition += Math.round( pixelsPerValue * ((double)max - value ) ); } else { yPosition = trackY; yPosition += Math.round( pixelsPerValue * ((double)value - min) ); } yPosition = Math.max( trackY, yPosition ); yPosition = Math.min( trackBottom, yPosition ); return yPosition; }
Returns the value at the y position. If yPos is beyond the track at the bottom or the top, this method sets the value to either the minimum or maximum value of the slider, depending on if the slider is inverted or not.
Params:
  • yPos – the location of the slider along the y axis
Returns:the value at the y position
/** * Returns the value at the y position. If {@code yPos} is beyond the * track at the bottom or the top, this method sets the value to either * the minimum or maximum value of the slider, depending on if the slider * is inverted or not. * * @param yPos the location of the slider along the y axis * @return the value at the y position */
public int valueForYPosition( int yPos ) { int value; final int minValue = slider.getMinimum(); final int maxValue = slider.getMaximum(); final int trackLength = trackRect.height; final int trackTop = trackRect.y; final int trackBottom = trackRect.y + (trackRect.height - 1); if ( yPos <= trackTop ) { value = drawInverted() ? minValue : maxValue; } else if ( yPos >= trackBottom ) { value = drawInverted() ? maxValue : minValue; } else { int distanceFromTrackTop = yPos - trackTop; double valueRange = (double)maxValue - (double)minValue; double valuePerPixel = valueRange / (double)trackLength; int valueFromTrackTop = (int)Math.round( distanceFromTrackTop * valuePerPixel ); value = drawInverted() ? minValue + valueFromTrackTop : maxValue - valueFromTrackTop; } return value; }
Returns the value at the x position. If xPos is beyond the track at the left or the right, this method sets the value to either the minimum or maximum value of the slider, depending on if the slider is inverted or not.
Params:
  • xPos – the location of the slider along the x axis
Returns:the value of the x position
/** * Returns the value at the x position. If {@code xPos} is beyond the * track at the left or the right, this method sets the value to either the * minimum or maximum value of the slider, depending on if the slider is * inverted or not. * * @param xPos the location of the slider along the x axis * @return the value of the x position */
public int valueForXPosition( int xPos ) { int value; final int minValue = slider.getMinimum(); final int maxValue = slider.getMaximum(); final int trackLength = trackRect.width; final int trackLeft = trackRect.x; final int trackRight = trackRect.x + (trackRect.width - 1); if ( xPos <= trackLeft ) { value = drawInverted() ? maxValue : minValue; } else if ( xPos >= trackRight ) { value = drawInverted() ? minValue : maxValue; } else { int distanceFromTrackLeft = xPos - trackLeft; double valueRange = (double)maxValue - (double)minValue; double valuePerPixel = valueRange / (double)trackLength; int valueFromTrackLeft = (int)Math.round( distanceFromTrackLeft * valuePerPixel ); value = drawInverted() ? maxValue - valueFromTrackLeft : minValue + valueFromTrackLeft; } return value; } private class Handler implements ChangeListener, ComponentListener, FocusListener, PropertyChangeListener { // Change Handler public void stateChanged(ChangeEvent e) { if (!isDragging) { calculateThumbLocation(); slider.repaint(); } lastValue = slider.getValue(); } // Component Handler public void componentHidden(ComponentEvent e) { } public void componentMoved(ComponentEvent e) { } public void componentResized(ComponentEvent e) { calculateGeometry(); slider.repaint(); } public void componentShown(ComponentEvent e) { } // Focus Handler public void focusGained(FocusEvent e) { slider.repaint(); } public void focusLost(FocusEvent e) { slider.repaint(); } // Property Change Handler public void propertyChange(PropertyChangeEvent e) { String propertyName = e.getPropertyName(); if (propertyName == "orientation" || propertyName == "inverted" || propertyName == "labelTable" || propertyName == "majorTickSpacing" || propertyName == "minorTickSpacing" || propertyName == "paintTicks" || propertyName == "paintTrack" || propertyName == "font" || SwingUtilities2.isScaleChanged(e) || propertyName == "paintLabels" || propertyName == "Slider.paintThumbArrowShape") { checkedLabelBaselines = false; calculateGeometry(); slider.repaint(); } else if (propertyName == "componentOrientation") { calculateGeometry(); slider.repaint(); InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider); SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km); } else if (propertyName == "model") { ((BoundedRangeModel)e.getOldValue()).removeChangeListener( changeListener); ((BoundedRangeModel)e.getNewValue()).addChangeListener( changeListener); calculateThumbLocation(); slider.repaint(); } } } ///////////////////////////////////////////////////////////////////////// /// Model Listener Class /////////////////////////////////////////////////////////////////////////
Data model listener. This class should be treated as a "protected" inner class. Instantiate it only within subclasses of Foo.
/** * Data model listener. * * This class should be treated as a &quot;protected&quot; inner class. * Instantiate it only within subclasses of <code>Foo</code>. */
public class ChangeHandler implements ChangeListener { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Handler. If you need to add // new functionality add it to the Handler, but make sure this // class calls into the Handler. public void stateChanged(ChangeEvent e) { getHandler().stateChanged(e); } } ///////////////////////////////////////////////////////////////////////// /// Track Listener Class /////////////////////////////////////////////////////////////////////////
Track mouse movements. This class should be treated as a "protected" inner class. Instantiate it only within subclasses of Foo.
/** * Track mouse movements. * * This class should be treated as a &quot;protected&quot; inner class. * Instantiate it only within subclasses of <code>Foo</code>. */
public class TrackListener extends MouseInputAdapter {
The offset
/** The offset */
protected transient int offset;
Current mouse x.
/** Current mouse x. */
protected transient int currentMouseX;
Current mouse y.
/** Current mouse y. */
protected transient int currentMouseY;
{@inheritDoc}
/** * {@inheritDoc} */
public void mouseReleased(MouseEvent e) { if (!slider.isEnabled()) { return; } offset = 0; scrollTimer.stop(); isDragging = false; slider.setValueIsAdjusting(false); slider.repaint(); }
If the mouse is pressed above the "thumb" component then reduce the scrollbars value by one page ("page up"), otherwise increase it by one page. If there is no thumb then page up if the mouse is in the upper half of the track.
/** * If the mouse is pressed above the "thumb" component * then reduce the scrollbars value by one page ("page up"), * otherwise increase it by one page. If there is no * thumb then page up if the mouse is in the upper half * of the track. */
public void mousePressed(MouseEvent e) { if (!slider.isEnabled()) { return; } // We should recalculate geometry just before // calculation of the thumb movement direction. // It is important for the case, when JSlider // is a cell editor in JTable. See 6348946. calculateGeometry(); currentMouseX = e.getX(); currentMouseY = e.getY(); if (slider.isRequestFocusEnabled()) { slider.requestFocus(); } // Clicked in the Thumb area? if (thumbRect.contains(currentMouseX, currentMouseY)) { if (UIManager.getBoolean("Slider.onlyLeftMouseButtonDrag") && !SwingUtilities.isLeftMouseButton(e)) { return; } switch (slider.getOrientation()) { case JSlider.VERTICAL: offset = currentMouseY - thumbRect.y; break; case JSlider.HORIZONTAL: offset = currentMouseX - thumbRect.x; break; } isDragging = true; return; } if (!SwingUtilities.isLeftMouseButton(e)) { return; } isDragging = false; slider.setValueIsAdjusting(true); Dimension sbSize = slider.getSize(); int direction = POSITIVE_SCROLL; switch (slider.getOrientation()) { case JSlider.VERTICAL: if ( thumbRect.isEmpty() ) { int scrollbarCenter = sbSize.height / 2; if ( !drawInverted() ) { direction = (currentMouseY < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; } else { direction = (currentMouseY < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; } } else { int thumbY = thumbRect.y; if ( !drawInverted() ) { direction = (currentMouseY < thumbY) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; } else { direction = (currentMouseY < thumbY) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; } } break; case JSlider.HORIZONTAL: if ( thumbRect.isEmpty() ) { int scrollbarCenter = sbSize.width / 2; if ( !drawInverted() ) { direction = (currentMouseX < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; } else { direction = (currentMouseX < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; } } else { int thumbX = thumbRect.x; if ( !drawInverted() ) { direction = (currentMouseX < thumbX) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; } else { direction = (currentMouseX < thumbX) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; } } break; } if (shouldScroll(direction)) { scrollDueToClickInTrack(direction); } if (shouldScroll(direction)) { scrollTimer.stop(); scrollListener.setDirection(direction); scrollTimer.start(); } }
Returns if scrolling should occur
Params:
  • direction – the direction.
Returns:if scrolling should occur
/** * Returns if scrolling should occur * @param direction the direction. * @return if scrolling should occur */
public boolean shouldScroll(int direction) { Rectangle r = thumbRect; if (slider.getOrientation() == JSlider.VERTICAL) { if (drawInverted() ? direction < 0 : direction > 0) { if (r.y <= currentMouseY) { return false; } } else if (r.y + r.height >= currentMouseY) { return false; } } else { if (drawInverted() ? direction < 0 : direction > 0) { if (r.x + r.width >= currentMouseX) { return false; } } else if (r.x <= currentMouseX) { return false; } } if (direction > 0 && slider.getValue() + slider.getExtent() >= slider.getMaximum()) { return false; } else if (direction < 0 && slider.getValue() <= slider.getMinimum()) { return false; } return true; }
Set the models value to the position of the top/left of the thumb relative to the origin of the track.
/** * Set the models value to the position of the top/left * of the thumb relative to the origin of the track. */
public void mouseDragged(MouseEvent e) { int thumbMiddle; if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); if (!isDragging) { return; } slider.setValueIsAdjusting(true); switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = thumbRect.height / 2; int thumbTop = e.getY() - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + (trackRect.height - 1); int vMax = yPositionForValue(slider.getMaximum() - slider.getExtent()); if (drawInverted()) { trackBottom = vMax; } else { trackTop = vMax; } thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setThumbLocation(thumbRect.x, thumbTop); thumbMiddle = thumbTop + halfThumbHeight; slider.setValue( valueForYPosition( thumbMiddle ) ); break; case JSlider.HORIZONTAL: int halfThumbWidth = thumbRect.width / 2; int thumbLeft = e.getX() - offset; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); int hMax = xPositionForValue(slider.getMaximum() - slider.getExtent()); if (drawInverted()) { trackLeft = hMax; } else { trackRight = hMax; } thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setThumbLocation(thumbLeft, thumbRect.y); thumbMiddle = thumbLeft + halfThumbWidth; slider.setValue(valueForXPosition(thumbMiddle)); break; } }
{@inheritDoc}
/** {@inheritDoc} */
public void mouseMoved(MouseEvent e) { } }
Scroll-event listener. This class should be treated as a "protected" inner class. Instantiate it only within subclasses of Foo.
/** * Scroll-event listener. * * This class should be treated as a &quot;protected&quot; inner class. * Instantiate it only within subclasses of <code>Foo</code>. */
public class ScrollListener implements ActionListener { // changed this class to public to avoid bogus IllegalAccessException // bug in InternetExplorer browser. It was protected. Work around // for 4109432 int direction = POSITIVE_SCROLL; boolean useBlockIncrement;
Constructs a ScrollListener
/** * Constructs a {@code ScrollListener} */
public ScrollListener() { direction = POSITIVE_SCROLL; useBlockIncrement = true; }
Constructs a ScrollListener
Params:
  • dir – the direction
  • block – whether or not to scroll by block
/** * Constructs a {@code ScrollListener} * @param dir the direction * @param block whether or not to scroll by block */
public ScrollListener(int dir, boolean block) { direction = dir; useBlockIncrement = block; }
Sets the direction.
Params:
  • direction – the new direction
/** * Sets the direction. * @param direction the new direction */
public void setDirection(int direction) { this.direction = direction; }
Sets scrolling by block
Params:
  • block – the new scroll by block value
/** * Sets scrolling by block * @param block the new scroll by block value */
public void setScrollByBlock(boolean block) { this.useBlockIncrement = block; }
{@inheritDoc}
/** {@inheritDoc} */
public void actionPerformed(ActionEvent e) { if (useBlockIncrement) { scrollByBlock(direction); } else { scrollByUnit(direction); } if (!trackListener.shouldScroll(direction)) { ((Timer)e.getSource()).stop(); } } }
Listener for resizing events.

This class should be treated as a "protected" inner class. Instantiate it only within subclasses of Foo.

/** * Listener for resizing events. * <p> * This class should be treated as a &quot;protected&quot; inner class. * Instantiate it only within subclasses of <code>Foo</code>. */
public class ComponentHandler extends ComponentAdapter { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Handler. If you need to add // new functionality add it to the Handler, but make sure this // class calls into the Handler. public void componentResized(ComponentEvent e) { getHandler().componentResized(e); } }
Focus-change listener.

This class should be treated as a "protected" inner class. Instantiate it only within subclasses of Foo.

/** * Focus-change listener. * <p> * This class should be treated as a &quot;protected&quot; inner class. * Instantiate it only within subclasses of <code>Foo</code>. */
public class FocusHandler implements FocusListener { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Handler. If you need to add // new functionality add it to the Handler, but make sure this // class calls into the Handler. public void focusGained(FocusEvent e) { getHandler().focusGained(e); } public void focusLost(FocusEvent e) { getHandler().focusLost(e); } }
As of Java 2 platform v1.3 this undocumented class is no longer used. The recommended approach to creating bindings is to use a combination of an ActionMap, to contain the action, and an InputMap to contain the mapping from KeyStroke to action description. The InputMap is usually described in the LookAndFeel tables.

Please refer to the key bindings specification for further details.

This class should be treated as a "protected" inner class. Instantiate it only within subclasses of Foo.

/** * As of Java 2 platform v1.3 this undocumented class is no longer used. * The recommended approach to creating bindings is to use a * combination of an <code>ActionMap</code>, to contain the action, * and an <code>InputMap</code> to contain the mapping from KeyStroke * to action description. The InputMap is usually described in the * LookAndFeel tables. * <p> * Please refer to the key bindings specification for further details. * <p> * This class should be treated as a &quot;protected&quot; inner class. * Instantiate it only within subclasses of <code>Foo</code>. */
@SuppressWarnings("serial") // Superclass is not serializable across versions public class ActionScroller extends AbstractAction { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Actions. If you need to add // new functionality add it to the Actions, but make sure this // class calls into the Actions. int dir; boolean block; JSlider slider;
Constructs an ActionScroller.
Params:
  • slider – a slider
  • dir – the direction
  • block – block scrolling or not
/** * Constructs an {@code ActionScroller}. * @param slider a slider * @param dir the direction * @param block block scrolling or not */
public ActionScroller( JSlider slider, int dir, boolean block) { this.dir = dir; this.block = block; this.slider = slider; }
{@inheritDoc}
/** {@inheritDoc} */
public void actionPerformed(ActionEvent e) { SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block); }
{@inheritDoc}
/** {@inheritDoc} */
public boolean isEnabled() { boolean b = true; if (slider != null) { b = slider.isEnabled(); } return b; } }
A static version of the above.
/** * A static version of the above. */
@SuppressWarnings("serial") // Superclass is not serializable across versions static class SharedActionScroller extends AbstractAction { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Actions. If you need to add // new functionality add it to the Actions, but make sure this // class calls into the Actions. int dir; boolean block; public SharedActionScroller(int dir, boolean block) { this.dir = dir; this.block = block; } public void actionPerformed(ActionEvent evt) { JSlider slider = (JSlider)evt.getSource(); BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType( slider.getUI(), BasicSliderUI.class); if (ui == null) { return; } SHARED_ACTION.scroll(slider, ui, dir, block); } } private static class Actions extends UIAction { public static final String POSITIVE_UNIT_INCREMENT = "positiveUnitIncrement"; public static final String POSITIVE_BLOCK_INCREMENT = "positiveBlockIncrement"; public static final String NEGATIVE_UNIT_INCREMENT = "negativeUnitIncrement"; public static final String NEGATIVE_BLOCK_INCREMENT = "negativeBlockIncrement"; public static final String MIN_SCROLL_INCREMENT = "minScroll"; public static final String MAX_SCROLL_INCREMENT = "maxScroll"; Actions() { super(null); } public Actions(String name) { super(name); } public void actionPerformed(ActionEvent evt) { JSlider slider = (JSlider)evt.getSource(); BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType( slider.getUI(), BasicSliderUI.class); String name = getName(); if (ui == null) { return; } if (POSITIVE_UNIT_INCREMENT == name) { scroll(slider, ui, POSITIVE_SCROLL, false); } else if (NEGATIVE_UNIT_INCREMENT == name) { scroll(slider, ui, NEGATIVE_SCROLL, false); } else if (POSITIVE_BLOCK_INCREMENT == name) { scroll(slider, ui, POSITIVE_SCROLL, true); } else if (NEGATIVE_BLOCK_INCREMENT == name) { scroll(slider, ui, NEGATIVE_SCROLL, true); } else if (MIN_SCROLL_INCREMENT == name) { scroll(slider, ui, MIN_SCROLL, false); } else if (MAX_SCROLL_INCREMENT == name) { scroll(slider, ui, MAX_SCROLL, false); } } private void scroll(JSlider slider, BasicSliderUI ui, int direction, boolean isBlock) { boolean invert = slider.getInverted(); if (direction == NEGATIVE_SCROLL || direction == POSITIVE_SCROLL) { if (invert) { direction = (direction == POSITIVE_SCROLL) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; } if (isBlock) { ui.scrollByBlock(direction); } else { ui.scrollByUnit(direction); } } else { // MIN or MAX if (invert) { direction = (direction == MIN_SCROLL) ? MAX_SCROLL : MIN_SCROLL; } slider.setValue((direction == MIN_SCROLL) ? slider.getMinimum() : slider.getMaximum()); } } } }