Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I should have answered this ages ago as I did eventually find a work around.<br> I modified code for a range slider from here: <a href="http://ernienotes.wordpress.com/2010/12/27/creating-a-java-swing-range-slider/" rel="nofollow">http://ernienotes.wordpress.com/2010/12/27/creating-a-java-swing-range-slider/</a> Sorry, I had to remove the Java Doc comments to fit it in the 3000 chars limit.</p> <p>The slider class code is this:</p> <pre><code>import javax.swing.JSlider; public class RangeSlider extends JSlider { RangeSliderUI rangeUI; public RangeSlider() { initSlider(); } public RangeSlider(int min, int max) { super(min, max); initSlider(); } private void initSlider() { setOrientation(HORIZONTAL); } @Override public void updateUI() { rangeUI = new RangeSliderUI(this); setUI(rangeUI); // Update UI for slider labels. This must be called after updating the // UI of the slider. Refer to JSlider.updateUI(). updateLabelUIs(); } @Override public int getValue() { return super.getValue(); } public RangeSliderUI getRangeUI() { return rangeUI; } @Override public void setValue(int value) { int oldValue = getValue(); if (oldValue == value) { return; } // Compute new value and extent to maintain upper value. int oldExtent = getExtent(); int newValue = Math.min(Math.max(getMinimum(), value), oldValue + oldExtent); int newExtent = oldExtent + oldValue - newValue; // Set new value and extent, and fire a single change event. getModel().setRangeProperties(newValue, newExtent, getMinimum(), getMaximum(), getValueIsAdjusting()); } public int getUpperValue() { return getValue() + getExtent(); } /** * Sets the upper value in the range. */ public void setUpperValue(int value) { // Compute new extent. int lowerValue = getValue(); int newExtent = Math.min(Math.max(0, value - lowerValue), getMaximum() - lowerValue); // Set extent to set upper value. setExtent(newExtent); } public boolean isRangeSlider() { return rangeUI.isRangeSlider(); } /** * Sets whether this is currently a range slider or not. (true is range slider, false is not range slider) */ public void setRangeSlider(boolean rangeSlider) { this.rangeUI.setRangeSlider(rangeSlider); } } </code></pre> <p>The UI class is this:</p> <pre><code>package YourPackage; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.event.MouseEvent; import javax.swing.JComponent; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicSliderUI; /** * UI delegate for the RangeSlider component. RangeSliderUI paints two thumbs, * one for the lower value and one for the upper value. * * Setting rangeSlider = false; causes the slider to revert to being a normal slider * rather than a range slider. */ class RangeSliderUI extends BasicSliderUI { /** Color of selected range. */ private Color rangeColor = Color.darkGray; /** Location and size of thumb for upper value. */ private Rectangle upperThumbRect; /** Indicator that determines whether upper thumb is selected. */ private boolean upperThumbSelected; /** Indicator that determines whether lower thumb is being dragged. */ private transient boolean lowerDragging; /** Indicator that determines whether upper thumb is being dragged. */ private transient boolean upperDragging; // Range/single slider (true is range slider/ false is single slider) private boolean rangeSlider = false; public RangeSliderUI(RangeSlider b) { super(b); } public int getTrackRect() { return trackRect.x; } public boolean isRangeSlider() { return rangeSlider; } public void setRangeSlider(boolean rangeSlider) { this.rangeSlider = rangeSlider; } @Override public void installUI(JComponent c) { upperThumbRect = new Rectangle(); super.installUI(c); } @Override protected TrackListener createTrackListener(JSlider slider) { return new RangeTrackListener(); } @Override protected ChangeListener createChangeListener(JSlider slider) { return new ChangeHandler(); } @Override protected void calculateThumbSize() { // Call superclass method for lower thumb size. super.calculateThumbSize(); // Set upper thumb size. upperThumbRect.setSize(thumbRect.width, thumbRect.height); } @Override protected void calculateThumbLocation() { // Call superclass method for lower thumb location. super.calculateThumbLocation(); // Adjust upper value to snap to ticks if necessary. if (slider.getSnapToTicks()) { int upperValue = slider.getValue() + slider.getExtent(); int snappedValue = upperValue; int majorTickSpacing = slider.getMajorTickSpacing(); int minorTickSpacing = slider.getMinorTickSpacing(); int tickSpacing = 0; if (minorTickSpacing &gt; 0) { tickSpacing = minorTickSpacing; } else if (majorTickSpacing &gt; 0) { tickSpacing = majorTickSpacing; } if (tickSpacing != 0) { // If it's not on a tick, change the value if ((upperValue - slider.getMinimum()) % tickSpacing != 0) { float temp = (float) (upperValue - slider.getMinimum()) / (float) tickSpacing; int whichTick = Math.round(temp); snappedValue = slider.getMinimum() + (whichTick * tickSpacing); } if (snappedValue != upperValue) { slider.setExtent(snappedValue - slider.getValue()); } } } // Calculate upper thumb location. The thumb is centered over its value on the track. if (slider.getOrientation() == JSlider.HORIZONTAL) { int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent()); upperThumbRect.x = upperPosition - (upperThumbRect.width / 2); upperThumbRect.y = trackRect.y; } else { int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent()); upperThumbRect.x = trackRect.x; upperThumbRect.y = upperPosition - (upperThumbRect.height / 2); } } @Override protected Dimension getThumbSize() { return new Dimension(12, 12); } @Override public void paint(Graphics g, JComponent c) { super.paint(g, c); } @Override public void paintTrack(Graphics g) { // Draw track. super.paintTrack(g); Rectangle trackBounds = trackRect; if (rangeSlider) { if (slider.getOrientation() == JSlider.HORIZONTAL) { // Determine position of selected range by moving from the middle // of one thumb to the other. int lowerX = thumbRect.x + (thumbRect.width / 2); int upperX = upperThumbRect.x + (upperThumbRect.width / 2); // Determine track position. int cy = (trackBounds.height / 2) - 2; // Save color and shift position. Color oldColor = g.getColor(); g.translate(trackBounds.x, trackBounds.y + cy); // Draw selected range. g.setColor(rangeColor); for (int y = 0; y &lt;= 3; y++) { g.drawLine(lowerX - trackBounds.x, y, upperX - trackBounds.x, y); } // Restore position and color. g.translate(-trackBounds.x, -(trackBounds.y + cy)); g.setColor(oldColor); } else { // Determine position of selected range by moving from the middle // of one thumb to the other. int lowerY = thumbRect.x + (thumbRect.width / 2); int upperY = upperThumbRect.x + (upperThumbRect.width / 2); // Determine track position. int cx = (trackBounds.width / 2) - 2; // Save color and shift position. Color oldColor = g.getColor(); g.translate(trackBounds.x + cx, trackBounds.y); // Draw selected range. g.setColor(rangeColor); for (int x = 0; x &lt;= 3; x++) { g.drawLine(x, lowerY - trackBounds.y, x, upperY - trackBounds.y); } // Restore position and color. g.translate(-(trackBounds.x + cx), -trackBounds.y); g.setColor(oldColor); } } // Shifted the knob painting to here so it is painted with the track or not. Rectangle clipRect = g.getClipBounds(); if (upperThumbSelected) { // Paint lower thumb first, then upper thumb. if (clipRect.intersects(thumbRect)) { paintLowerThumb(g); } if (clipRect.intersects(upperThumbRect)) { paintUpperThumb(g); } } else { // Paint upper thumb first, then lower thumb. if (clipRect.intersects(upperThumbRect)) { paintUpperThumb(g); } if (clipRect.intersects(thumbRect)) { paintLowerThumb(g); } } } @Override public void paintThumb(Graphics g) { } private void paintLowerThumb(Graphics g) { Rectangle knobBounds = thumbRect; int w = knobBounds.width; int h = knobBounds.height; // Create graphics copy. Graphics2D g2d = (Graphics2D) g.create(); // Create default thumb shape. Shape thumbShape = createThumbShape(w - 1, h - 1); // Draw thumb. g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.translate(knobBounds.x, knobBounds.y); g2d.setColor(Color.CYAN); g2d.fill(thumbShape); g2d.setColor(Color.BLUE); g2d.draw(thumbShape); // Dispose graphics. g2d.dispose(); } private void paintUpperThumb(Graphics g) { if (rangeSlider) { Rectangle knobBounds = upperThumbRect; int w = knobBounds.width; int h = knobBounds.height; // Create graphics copy. Graphics2D g2d = (Graphics2D) g.create(); // Create default thumb shape. Shape thumbShape = createThumbShape(w - 1, h - 1); // Draw thumb. g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.translate(knobBounds.x, knobBounds.y); g2d.setColor(Color.orange); g2d.fill(thumbShape); g2d.setColor(Color.orange.darker().darker()); g2d.draw(thumbShape); // Dispose graphics. g2d.dispose(); } } private Shape createThumbShape(int width, int height) { Point p1 = new Point(0, 0); Point p2 = new Point(width, 0); Point p3 = new Point(width, (height / 2) + 1); Point p4 = new Point((width / 2) + 1, height); Point p5 = new Point(0, (height / 2) + 1); int[] xs = { p1.x, p2.x, p3.x, p4.x, p5.x }; int[] ys = { p1.y, p2.y, p3.y, p4.y, p5.y }; Polygon thumb = new Polygon(xs, ys, xs.length); return thumb; } private void setUpperThumbLocation(int x, int y) { Rectangle upperUnionRect = new Rectangle(); upperUnionRect.setBounds(upperThumbRect); upperThumbRect.setLocation(x, y); SwingUtilities.computeUnion(upperThumbRect.x, upperThumbRect.y, upperThumbRect.width, upperThumbRect.height, upperUnionRect); slider.repaint(upperUnionRect.x, upperUnionRect.y, upperUnionRect.width, upperUnionRect.height); } @Override public void scrollByBlock(int direction) { synchronized (slider) { int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / 10; if (blockIncrement &lt;= 0 &amp;&amp; slider.getMaximum() &gt; slider.getMinimum()) { blockIncrement = 1; } int delta = blockIncrement * ((direction &gt; 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); if (upperThumbSelected) { int oldValue = ((RangeSlider) slider).getUpperValue(); ((RangeSlider) slider).setUpperValue(oldValue + delta); } else { int oldValue = slider.getValue(); slider.setValue(oldValue + delta); } } } @Override public void scrollByUnit(int direction) { synchronized (slider) { int delta = 1 * ((direction &gt; 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); if (upperThumbSelected) { int oldValue = ((RangeSlider) slider).getUpperValue(); ((RangeSlider) slider).setUpperValue(oldValue + delta); } else { int oldValue = slider.getValue(); slider.setValue(oldValue + delta); } } } public class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent arg0) { if (!lowerDragging &amp;&amp; !upperDragging) { calculateThumbLocation(); slider.repaint(); } } } public class RangeTrackListener extends TrackListener { @Override public void mousePressed(MouseEvent e) { if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); if (slider.isRequestFocusEnabled()) { slider.requestFocus(); } // Determine which thumb is pressed. If the upper thumb is selected (last one dragged), then check its position first; // otherwise check the position of the lower thumb first. boolean lowerPressed = false; boolean upperPressed = false; if (upperThumbSelected) { // Only enable upper slider movement if in range mode. if (upperThumbRect.contains(currentMouseX, currentMouseY) &amp;&amp; rangeSlider) { upperPressed = true; } else { if (thumbRect.contains(currentMouseX, currentMouseY)) { lowerPressed = true; } } } else { if (thumbRect.contains(currentMouseX, currentMouseY)) { lowerPressed = true; } else { // Only enable if in range mode. if (upperThumbRect.contains(currentMouseX, currentMouseY) &amp;&amp; rangeSlider) { upperPressed = true; } } } // Handle lower thumb pressed. if (lowerPressed) { switch (slider.getOrientation()) { case JSlider.VERTICAL: offset = currentMouseY - thumbRect.y; break; case JSlider.HORIZONTAL: offset = currentMouseX - thumbRect.x; break; } upperThumbSelected = false; lowerDragging = true; return; } lowerDragging = false; // Handle upper thumb pressed. if (upperPressed) { switch (slider.getOrientation()) { case JSlider.VERTICAL: offset = currentMouseY - upperThumbRect.y; break; case JSlider.HORIZONTAL: offset = currentMouseX - upperThumbRect.x; break; } upperThumbSelected = true; upperDragging = true; return; } upperDragging = false; } @Override public void mouseReleased(MouseEvent e) { lowerDragging = false; upperDragging = false; slider.setValueIsAdjusting(false); super.mouseReleased(e); } @Override public void mouseDragged(MouseEvent e) { if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); if (lowerDragging) { slider.setValueIsAdjusting(true); moveLowerThumb(); } else if (upperDragging) { slider.setValueIsAdjusting(true); moveUpperThumb(); } } @Override public boolean shouldScroll(int direction) { return false; } private void moveLowerThumb() { int thumbMiddle = 0; switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = thumbRect.height / 2; int thumbTop = currentMouseY - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + (trackRect.height - 1); int vMax = yPositionForValue(slider.getValue() + slider.getExtent()); // Apply bounds to thumb position. if (drawInverted()) { trackBottom = vMax; } else { trackTop = vMax; } thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setThumbLocation(thumbRect.x, thumbTop); // Update slider value. thumbMiddle = thumbTop + halfThumbHeight; slider.setValue(valueForYPosition(thumbMiddle)); break; case JSlider.HORIZONTAL: int halfThumbWidth = thumbRect.width / 2; int thumbLeft = currentMouseX - offset; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); int hMax = xPositionForValue(slider.getValue() + slider.getExtent()); // Apply bounds to thumb position. if (drawInverted()) { trackLeft = hMax; } else { trackRight = hMax; } thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setThumbLocation(thumbLeft, thumbRect.y); // Update slider value. thumbMiddle = thumbLeft + halfThumbWidth; slider.setValue(valueForXPosition(thumbMiddle)); break; default: return; } } private void moveUpperThumb() { int thumbMiddle = 0; switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = thumbRect.height / 2; int thumbTop = currentMouseY - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + (trackRect.height - 1); int vMin = yPositionForValue(slider.getValue()); // Apply bounds to thumb position. if (drawInverted()) { trackTop = vMin; } else { trackBottom = vMin; } thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setUpperThumbLocation(thumbRect.x, thumbTop); // Update slider extent. thumbMiddle = thumbTop + halfThumbHeight; slider.setExtent(valueForYPosition(thumbMiddle) - slider.getValue()); break; case JSlider.HORIZONTAL: int halfThumbWidth = thumbRect.width / 2; int thumbLeft = currentMouseX - offset; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); int hMin = xPositionForValue(slider.getValue()); // Apply bounds to thumb position. if (drawInverted()) { trackRight = hMin; } else { trackLeft = hMin; } thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setUpperThumbLocation(thumbLeft, thumbRect.y); // Update slider extent. thumbMiddle = thumbLeft + halfThumbWidth; slider.setExtent(valueForXPosition(thumbMiddle) - slider.getValue()); break; default: return; } } } } </code></pre> <p>The x position for the track rectangle (which is also the position of the first tick mark) , to align your graph to the slider, is gotten by calling:</p> <pre><code>rangeSlider1.getRangeUI().getTrackRect() </code></pre> <p>I also didn't like their round knobs and changed them to the more traditional shape.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload