1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing; 27 28 import javax.swing.event.*; 29 import javax.swing.plaf.*; 30 import javax.accessibility.*; 31 32 import java.io.Serializable; 33 import java.io.ObjectOutputStream; 34 import java.io.IOException; 35 36 import java.awt.*; 37 import java.util.*; 38 import java.beans.*; 39 40 41 /** 42 * A component that lets the user graphically select a value by sliding 43 * a knob within a bounded interval. The knob is always positioned 44 * at the points that match integer values within the specified interval. 45 * <p> 46 * The slider can show both 47 * major tick marks, and minor tick marks between the major ones. The number of 48 * values between the tick marks is controlled with 49 * <code>setMajorTickSpacing</code> and <code>setMinorTickSpacing</code>. 50 * Painting of tick marks is controlled by {@code setPaintTicks}. 51 * <p> 52 * Sliders can also print text labels at regular intervals (or at 53 * arbitrary locations) along the slider track. Painting of labels is 54 * controlled by {@code setLabelTable} and {@code setPaintLabels}. 55 * <p> 56 * For further information and examples see 57 * <a 58 href="http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html">How to Use Sliders</a>, 59 * a section in <em>The Java Tutorial.</em> 60 * <p> 61 * <strong>Warning:</strong> Swing is not thread safe. For more 62 * information see <a 63 * href="package-summary.html#threading">Swing's Threading 64 * Policy</a>. 65 * <p> 66 * <strong>Warning:</strong> 67 * Serialized objects of this class will not be compatible with 68 * future Swing releases. The current serialization support is 69 * appropriate for short term storage or RMI between applications running 70 * the same version of Swing. As of 1.4, support for long term storage 71 * of all JavaBeans™ 72 * has been added to the <code>java.beans</code> package. 73 * Please see {@link java.beans.XMLEncoder}. 74 * 75 * @beaninfo 76 * attribute: isContainer false 77 * description: A component that supports selecting a integer value from a range. 78 * 79 * @author David Kloba 80 * @since 1.2 81 */ 82 @SuppressWarnings("serial") // Same-version serialization only 83 public class JSlider extends JComponent implements SwingConstants, Accessible { 84 /** 85 * @see #getUIClassID 86 * @see #readObject 87 */ 88 private static final String uiClassID = "SliderUI"; 89 90 private boolean paintTicks = false; 91 private boolean paintTrack = true; 92 private boolean paintLabels = false; 93 private boolean isInverted = false; 94 95 /** 96 * The data model that handles the numeric maximum value, 97 * minimum value, and current-position value for the slider. 98 */ 99 protected BoundedRangeModel sliderModel; 100 101 /** 102 * The number of values between the major tick marks -- the 103 * larger marks that break up the minor tick marks. 104 */ 105 protected int majorTickSpacing; 106 107 /** 108 * The number of values between the minor tick marks -- the 109 * smaller marks that occur between the major tick marks. 110 * @see #setMinorTickSpacing 111 */ 112 protected int minorTickSpacing; 113 114 /** 115 * If true, the knob (and the data value it represents) 116 * resolve to the closest tick mark next to where the user 117 * positioned the knob. The default is false. 118 * @see #setSnapToTicks 119 */ 120 protected boolean snapToTicks = false; 121 122 /** 123 * If true, the knob (and the data value it represents) 124 * resolve to the closest slider value next to where the user 125 * positioned the knob. 126 */ 127 boolean snapToValue = true; 128 129 /** 130 * Whether the slider is horizontal or vertical 131 * The default is horizontal. 132 * 133 * @see #setOrientation 134 */ 135 protected int orientation; 136 137 138 /** 139 * {@code Dictionary} of what labels to draw at which values 140 */ 141 @SuppressWarnings("rawtypes") 142 private Dictionary labelTable; 143 // For better source compatibility, the labelTable field and 144 // associated getter and setter methods are being left as raw 145 // types. 146 147 /** 148 * The changeListener (no suffix) is the listener we add to the 149 * slider's model. This listener is initialized to the 150 * {@code ChangeListener} returned from {@code createChangeListener}, 151 * which by default just forwards events 152 * to {@code ChangeListener}s (if any) added directly to the slider. 153 * 154 * @see #addChangeListener 155 * @see #createChangeListener 156 */ 157 protected ChangeListener changeListener = createChangeListener(); 158 159 160 /** 161 * Only one <code>ChangeEvent</code> is needed per slider instance since the 162 * event's only (read-only) state is the source property. The source 163 * of events generated here is always "this". The event is lazily 164 * created the first time that an event notification is fired. 165 * 166 * @see #fireStateChanged 167 */ 168 protected transient ChangeEvent changeEvent = null; 169 170 171 private void checkOrientation(int orientation) { 172 switch (orientation) { 173 case VERTICAL: 174 case HORIZONTAL: 175 break; 176 default: 177 throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL"); 178 } 179 } 180 181 182 /** 183 * Creates a horizontal slider with the range 0 to 100 and 184 * an initial value of 50. 185 */ 186 public JSlider() { 187 this(HORIZONTAL, 0, 100, 50); 188 } 189 190 191 /** 192 * Creates a slider using the specified orientation with the 193 * range {@code 0} to {@code 100} and an initial value of {@code 50}. 194 * The orientation can be 195 * either <code>SwingConstants.VERTICAL</code> or 196 * <code>SwingConstants.HORIZONTAL</code>. 197 * 198 * @param orientation the orientation of the slider 199 * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL} 200 * @see #setOrientation 201 */ 202 public JSlider(int orientation) { 203 this(orientation, 0, 100, 50); 204 } 205 206 207 /** 208 * Creates a horizontal slider using the specified min and max 209 * with an initial value equal to the average of the min plus max. 210 * <p> 211 * The <code>BoundedRangeModel</code> that holds the slider's data 212 * handles any issues that may arise from improperly setting the 213 * minimum and maximum values on the slider. See the 214 * {@code BoundedRangeModel} documentation for details. 215 * 216 * @param min the minimum value of the slider 217 * @param max the maximum value of the slider 218 * 219 * @see BoundedRangeModel 220 * @see #setMinimum 221 * @see #setMaximum 222 */ 223 public JSlider(int min, int max) { 224 this(HORIZONTAL, min, max, (min + max) / 2); 225 } 226 227 228 /** 229 * Creates a horizontal slider using the specified min, max and value. 230 * <p> 231 * The <code>BoundedRangeModel</code> that holds the slider's data 232 * handles any issues that may arise from improperly setting the 233 * minimum, initial, and maximum values on the slider. See the 234 * {@code BoundedRangeModel} documentation for details. 235 * 236 * @param min the minimum value of the slider 237 * @param max the maximum value of the slider 238 * @param value the initial value of the slider 239 * 240 * @see BoundedRangeModel 241 * @see #setMinimum 242 * @see #setMaximum 243 * @see #setValue 244 */ 245 public JSlider(int min, int max, int value) { 246 this(HORIZONTAL, min, max, value); 247 } 248 249 250 /** 251 * Creates a slider with the specified orientation and the 252 * specified minimum, maximum, and initial values. 253 * The orientation can be 254 * either <code>SwingConstants.VERTICAL</code> or 255 * <code>SwingConstants.HORIZONTAL</code>. 256 * <p> 257 * The <code>BoundedRangeModel</code> that holds the slider's data 258 * handles any issues that may arise from improperly setting the 259 * minimum, initial, and maximum values on the slider. See the 260 * {@code BoundedRangeModel} documentation for details. 261 * 262 * @param orientation the orientation of the slider 263 * @param min the minimum value of the slider 264 * @param max the maximum value of the slider 265 * @param value the initial value of the slider 266 * 267 * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL} 268 * 269 * @see BoundedRangeModel 270 * @see #setOrientation 271 * @see #setMinimum 272 * @see #setMaximum 273 * @see #setValue 274 */ 275 public JSlider(int orientation, int min, int max, int value) 276 { 277 checkOrientation(orientation); 278 this.orientation = orientation; 279 setModel(new DefaultBoundedRangeModel(value, 0, min, max)); 280 updateUI(); 281 } 282 283 284 /** 285 * Creates a horizontal slider using the specified 286 * BoundedRangeModel. 287 * 288 * @param brm a {@code BoundedRangeModel} for the slider 289 */ 290 public JSlider(BoundedRangeModel brm) 291 { 292 this.orientation = JSlider.HORIZONTAL; 293 setModel(brm); 294 updateUI(); 295 } 296 297 298 /** 299 * Gets the UI object which implements the L&F for this component. 300 * 301 * @return the SliderUI object that implements the Slider L&F 302 */ 303 public SliderUI getUI() { 304 return(SliderUI)ui; 305 } 306 307 308 /** 309 * Sets the UI object which implements the L&F for this component. 310 * 311 * @param ui the SliderUI L&F object 312 * @see UIDefaults#getUI 313 * @beaninfo 314 * bound: true 315 * hidden: true 316 * attribute: visualUpdate true 317 * description: The UI object that implements the slider's LookAndFeel. 318 */ 319 public void setUI(SliderUI ui) { 320 super.setUI(ui); 321 } 322 323 324 /** 325 * Resets the UI property to a value from the current look and feel. 326 * 327 * @see JComponent#updateUI 328 */ 329 public void updateUI() { 330 setUI((SliderUI)UIManager.getUI(this)); 331 // The labels preferred size may be derived from the font 332 // of the slider, so we must update the UI of the slider first, then 333 // that of labels. This way when setSize is called the right 334 // font is used. 335 updateLabelUIs(); 336 } 337 338 339 /** 340 * Returns the name of the L&F class that renders this component. 341 * 342 * @return "SliderUI" 343 * @see JComponent#getUIClassID 344 * @see UIDefaults#getUI 345 */ 346 public String getUIClassID() { 347 return uiClassID; 348 } 349 350 351 /** 352 * We pass Change events along to the listeners with the 353 * the slider (instead of the model itself) as the event source. 354 */ 355 private class ModelListener implements ChangeListener, Serializable { 356 public void stateChanged(ChangeEvent e) { 357 fireStateChanged(); 358 } 359 } 360 361 362 /** 363 * Subclasses that want to handle {@code ChangeEvent}s 364 * from the model differently 365 * can override this to return 366 * an instance of a custom <code>ChangeListener</code> implementation. 367 * The default {@code ChangeListener} simply calls the 368 * {@code fireStateChanged} method to forward {@code ChangeEvent}s 369 * to the {@code ChangeListener}s that have been added directly to the 370 * slider. 371 * 372 * @return a instance of new {@code ChangeListener} 373 * @see #changeListener 374 * @see #fireStateChanged 375 * @see javax.swing.event.ChangeListener 376 * @see javax.swing.BoundedRangeModel 377 */ 378 protected ChangeListener createChangeListener() { 379 return new ModelListener(); 380 } 381 382 383 /** 384 * Adds a ChangeListener to the slider. 385 * 386 * @param l the ChangeListener to add 387 * @see #fireStateChanged 388 * @see #removeChangeListener 389 */ 390 public void addChangeListener(ChangeListener l) { 391 listenerList.add(ChangeListener.class, l); 392 } 393 394 395 /** 396 * Removes a ChangeListener from the slider. 397 * 398 * @param l the ChangeListener to remove 399 * @see #fireStateChanged 400 * @see #addChangeListener 401 402 */ 403 public void removeChangeListener(ChangeListener l) { 404 listenerList.remove(ChangeListener.class, l); 405 } 406 407 408 /** 409 * Returns an array of all the <code>ChangeListener</code>s added 410 * to this JSlider with addChangeListener(). 411 * 412 * @return all of the <code>ChangeListener</code>s added or an empty 413 * array if no listeners have been added 414 * @since 1.4 415 */ 416 public ChangeListener[] getChangeListeners() { 417 return listenerList.getListeners(ChangeListener.class); 418 } 419 420 421 /** 422 * Send a {@code ChangeEvent}, whose source is this {@code JSlider}, to 423 * all {@code ChangeListener}s that have registered interest in 424 * {@code ChangeEvent}s. 425 * This method is called each time a {@code ChangeEvent} is received from 426 * the model. 427 * <p> 428 * The event instance is created if necessary, and stored in 429 * {@code changeEvent}. 430 * 431 * @see #addChangeListener 432 * @see EventListenerList 433 */ 434 protected void fireStateChanged() { 435 Object[] listeners = listenerList.getListenerList(); 436 for (int i = listeners.length - 2; i >= 0; i -= 2) { 437 if (listeners[i]==ChangeListener.class) { 438 if (changeEvent == null) { 439 changeEvent = new ChangeEvent(this); 440 } 441 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 442 } 443 } 444 } 445 446 447 /** 448 * Returns the {@code BoundedRangeModel} that handles the slider's three 449 * fundamental properties: minimum, maximum, value. 450 * 451 * @return the data model for this component 452 * @see #setModel 453 * @see BoundedRangeModel 454 */ 455 public BoundedRangeModel getModel() { 456 return sliderModel; 457 } 458 459 460 /** 461 * Sets the {@code BoundedRangeModel} that handles the slider's three 462 * fundamental properties: minimum, maximum, value. 463 *<p> 464 * Attempts to pass a {@code null} model to this method result in 465 * undefined behavior, and, most likely, exceptions. 466 * 467 * @param newModel the new, {@code non-null} <code>BoundedRangeModel</code> to use 468 * 469 * @see #getModel 470 * @see BoundedRangeModel 471 * @beaninfo 472 * bound: true 473 * description: The sliders BoundedRangeModel. 474 */ 475 public void setModel(BoundedRangeModel newModel) 476 { 477 BoundedRangeModel oldModel = getModel(); 478 479 if (oldModel != null) { 480 oldModel.removeChangeListener(changeListener); 481 } 482 483 sliderModel = newModel; 484 485 if (newModel != null) { 486 newModel.addChangeListener(changeListener); 487 } 488 489 if (accessibleContext != null) { 490 accessibleContext.firePropertyChange( 491 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, 492 (oldModel == null 493 ? null : Integer.valueOf(oldModel.getValue())), 494 (newModel == null 495 ? null : Integer.valueOf(newModel.getValue()))); 496 } 497 498 firePropertyChange("model", oldModel, sliderModel); 499 } 500 501 502 /** 503 * Returns the slider's current value 504 * from the {@code BoundedRangeModel}. 505 * 506 * @return the current value of the slider 507 * @see #setValue 508 * @see BoundedRangeModel#getValue 509 */ 510 public int getValue() { 511 return getModel().getValue(); 512 } 513 514 /** 515 * Sets the slider's current value to {@code n}. This method 516 * forwards the new value to the model. 517 * <p> 518 * The data model (an instance of {@code BoundedRangeModel}) 519 * handles any mathematical 520 * issues arising from assigning faulty values. See the 521 * {@code BoundedRangeModel} documentation for details. 522 * <p> 523 * If the new value is different from the previous value, 524 * all change listeners are notified. 525 * 526 * @param n the new value 527 * @see #getValue 528 * @see #addChangeListener 529 * @see BoundedRangeModel#setValue 530 * @beaninfo 531 * preferred: true 532 * description: The sliders current value. 533 */ 534 public void setValue(int n) { 535 BoundedRangeModel m = getModel(); 536 int oldValue = m.getValue(); 537 if (oldValue == n) { 538 return; 539 } 540 m.setValue(n); 541 542 if (accessibleContext != null) { 543 accessibleContext.firePropertyChange( 544 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, 545 Integer.valueOf(oldValue), 546 Integer.valueOf(m.getValue())); 547 } 548 } 549 550 551 /** 552 * Returns the minimum value supported by the slider 553 * from the <code>BoundedRangeModel</code>. 554 * 555 * @return the value of the model's minimum property 556 * @see #setMinimum 557 * @see BoundedRangeModel#getMinimum 558 */ 559 public int getMinimum() { 560 return getModel().getMinimum(); 561 } 562 563 564 /** 565 * Sets the slider's minimum value to {@code minimum}. This method 566 * forwards the new minimum value to the model. 567 * <p> 568 * The data model (an instance of {@code BoundedRangeModel}) 569 * handles any mathematical 570 * issues arising from assigning faulty values. See the 571 * {@code BoundedRangeModel} documentation for details. 572 * <p> 573 * If the new minimum value is different from the previous minimum value, 574 * all change listeners are notified. 575 * 576 * @param minimum the new minimum 577 * @see #getMinimum 578 * @see #addChangeListener 579 * @see BoundedRangeModel#setMinimum 580 * @beaninfo 581 * bound: true 582 * preferred: true 583 * description: The sliders minimum value. 584 */ 585 public void setMinimum(int minimum) { 586 int oldMin = getModel().getMinimum(); 587 getModel().setMinimum(minimum); 588 firePropertyChange( "minimum", Integer.valueOf( oldMin ), Integer.valueOf( minimum ) ); 589 } 590 591 592 /** 593 * Returns the maximum value supported by the slider 594 * from the <code>BoundedRangeModel</code>. 595 * 596 * @return the value of the model's maximum property 597 * @see #setMaximum 598 * @see BoundedRangeModel#getMaximum 599 */ 600 public int getMaximum() { 601 return getModel().getMaximum(); 602 } 603 604 605 /** 606 * Sets the slider's maximum value to {@code maximum}. This method 607 * forwards the new maximum value to the model. 608 * <p> 609 * The data model (an instance of {@code BoundedRangeModel}) 610 * handles any mathematical 611 * issues arising from assigning faulty values. See the 612 * {@code BoundedRangeModel} documentation for details. 613 * <p> 614 * If the new maximum value is different from the previous maximum value, 615 * all change listeners are notified. 616 * 617 * @param maximum the new maximum 618 * @see #getMaximum 619 * @see #addChangeListener 620 * @see BoundedRangeModel#setMaximum 621 * @beaninfo 622 * bound: true 623 * preferred: true 624 * description: The sliders maximum value. 625 */ 626 public void setMaximum(int maximum) { 627 int oldMax = getModel().getMaximum(); 628 getModel().setMaximum(maximum); 629 firePropertyChange( "maximum", Integer.valueOf( oldMax ), Integer.valueOf( maximum ) ); 630 } 631 632 633 /** 634 * Returns the {@code valueIsAdjusting} property from the model. For 635 * details on how this is used, see the {@code setValueIsAdjusting} 636 * documentation. 637 * 638 * @return the value of the model's {@code valueIsAdjusting} property 639 * @see #setValueIsAdjusting 640 */ 641 public boolean getValueIsAdjusting() { 642 return getModel().getValueIsAdjusting(); 643 } 644 645 646 /** 647 * Sets the model's {@code valueIsAdjusting} property. Slider look and 648 * feel implementations should set this property to {@code true} when 649 * a knob drag begins, and to {@code false} when the drag ends. 650 * 651 * @param b the new value for the {@code valueIsAdjusting} property 652 * @see #getValueIsAdjusting 653 * @see BoundedRangeModel#setValueIsAdjusting 654 * @beaninfo 655 * expert: true 656 * description: True if the slider knob is being dragged. 657 */ 658 public void setValueIsAdjusting(boolean b) { 659 BoundedRangeModel m = getModel(); 660 boolean oldValue = m.getValueIsAdjusting(); 661 m.setValueIsAdjusting(b); 662 663 if ((oldValue != b) && (accessibleContext != null)) { 664 accessibleContext.firePropertyChange( 665 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 666 ((oldValue) ? AccessibleState.BUSY : null), 667 ((b) ? AccessibleState.BUSY : null)); 668 } 669 } 670 671 672 /** 673 * Returns the "extent" from the <code>BoundedRangeModel</code>. 674 * This represents the range of values "covered" by the knob. 675 * 676 * @return an int representing the extent 677 * @see #setExtent 678 * @see BoundedRangeModel#getExtent 679 */ 680 public int getExtent() { 681 return getModel().getExtent(); 682 } 683 684 685 /** 686 * Sets the size of the range "covered" by the knob. Most look 687 * and feel implementations will change the value by this amount 688 * if the user clicks on either side of the knob. This method just 689 * forwards the new extent value to the model. 690 * <p> 691 * The data model (an instance of {@code BoundedRangeModel}) 692 * handles any mathematical 693 * issues arising from assigning faulty values. See the 694 * {@code BoundedRangeModel} documentation for details. 695 * <p> 696 * If the new extent value is different from the previous extent value, 697 * all change listeners are notified. 698 * 699 * @param extent the new extent 700 * @see #getExtent 701 * @see BoundedRangeModel#setExtent 702 * @beaninfo 703 * expert: true 704 * description: Size of the range covered by the knob. 705 */ 706 public void setExtent(int extent) { 707 getModel().setExtent(extent); 708 } 709 710 711 /** 712 * Return this slider's vertical or horizontal orientation. 713 * @return {@code SwingConstants.VERTICAL} or 714 * {@code SwingConstants.HORIZONTAL} 715 * @see #setOrientation 716 */ 717 public int getOrientation() { 718 return orientation; 719 } 720 721 722 /** 723 * Set the slider's orientation to either {@code SwingConstants.VERTICAL} or 724 * {@code SwingConstants.HORIZONTAL}. 725 * 726 * @param orientation {@code HORIZONTAL} or {@code VERTICAL} 727 * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL} 728 * @see #getOrientation 729 * @beaninfo 730 * preferred: true 731 * bound: true 732 * attribute: visualUpdate true 733 * description: Set the scrollbars orientation to either VERTICAL or HORIZONTAL. 734 * enum: VERTICAL JSlider.VERTICAL 735 * HORIZONTAL JSlider.HORIZONTAL 736 * 737 */ 738 public void setOrientation(int orientation) 739 { 740 checkOrientation(orientation); 741 int oldValue = this.orientation; 742 this.orientation = orientation; 743 firePropertyChange("orientation", oldValue, orientation); 744 745 if ((oldValue != orientation) && (accessibleContext != null)) { 746 accessibleContext.firePropertyChange( 747 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 748 ((oldValue == VERTICAL) 749 ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL), 750 ((orientation == VERTICAL) 751 ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL)); 752 } 753 if (orientation != oldValue) { 754 revalidate(); 755 } 756 } 757 758 759 /** 760 * {@inheritDoc} 761 * 762 * @since 1.6 763 */ 764 public void setFont(Font font) { 765 super.setFont(font); 766 updateLabelSizes(); 767 } 768 769 /** 770 * {@inheritDoc} 771 * @since 1.7 772 */ 773 public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { 774 if (!isShowing()) { 775 return false; 776 } 777 778 // Check that there is a label with such image 779 Enumeration<?> elements = labelTable.elements(); 780 781 while (elements.hasMoreElements()) { 782 Component component = (Component) elements.nextElement(); 783 784 if (component instanceof JLabel) { 785 JLabel label = (JLabel) component; 786 787 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) || 788 SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) { 789 return super.imageUpdate(img, infoflags, x, y, w, h); 790 } 791 } 792 } 793 794 return false; 795 } 796 797 /** 798 * Returns the dictionary of what labels to draw at which values. 799 * 800 * @return the <code>Dictionary</code> containing labels and 801 * where to draw them 802 */ 803 @SuppressWarnings("rawtypes") 804 public Dictionary getLabelTable() { 805 /* 806 if ( labelTable == null && getMajorTickSpacing() > 0 ) { 807 setLabelTable( createStandardLabels( getMajorTickSpacing() ) ); 808 } 809 */ 810 return labelTable; 811 } 812 813 814 /** 815 * Used to specify what label will be drawn at any given value. 816 * The key-value pairs are of this format: 817 * <code>{ Integer value, java.swing.JComponent label }</code>. 818 * <p> 819 * An easy way to generate a standard table of value labels is by using the 820 * {@code createStandardLabels} method. 821 * <p> 822 * Once the labels have been set, this method calls {@link #updateLabelUIs}. 823 * Note that the labels are only painted if the {@code paintLabels} 824 * property is {@code true}. 825 * 826 * @param labels new {@code Dictionary} of labels, or {@code null} to 827 * remove all labels 828 * @see #createStandardLabels(int) 829 * @see #getLabelTable 830 * @see #setPaintLabels 831 * @beaninfo 832 * hidden: true 833 * bound: true 834 * attribute: visualUpdate true 835 * description: Specifies what labels will be drawn for any given value. 836 */ 837 @SuppressWarnings("rawtypes") 838 public void setLabelTable( Dictionary labels ) { 839 Dictionary oldTable = labelTable; 840 labelTable = labels; 841 updateLabelUIs(); 842 firePropertyChange("labelTable", oldTable, labelTable ); 843 if (labels != oldTable) { 844 revalidate(); 845 repaint(); 846 } 847 } 848 849 850 /** 851 * Updates the UIs for the labels in the label table by calling 852 * {@code updateUI} on each label. The UIs are updated from 853 * the current look and feel. The labels are also set to their 854 * preferred size. 855 * 856 * @see #setLabelTable 857 * @see JComponent#updateUI 858 */ 859 protected void updateLabelUIs() { 860 @SuppressWarnings("rawtypes") 861 Dictionary labelTable = getLabelTable(); 862 863 if (labelTable == null) { 864 return; 865 } 866 Enumeration<?> labels = labelTable.keys(); 867 while ( labels.hasMoreElements() ) { 868 JComponent component = (JComponent) labelTable.get(labels.nextElement()); 869 component.updateUI(); 870 component.setSize(component.getPreferredSize()); 871 } 872 } 873 874 private void updateLabelSizes() { 875 @SuppressWarnings("rawtypes") 876 Dictionary labelTable = getLabelTable(); 877 if (labelTable != null) { 878 Enumeration<?> labels = labelTable.elements(); 879 while (labels.hasMoreElements()) { 880 JComponent component = (JComponent) labels.nextElement(); 881 component.setSize(component.getPreferredSize()); 882 } 883 } 884 } 885 886 887 /** 888 * Creates a {@code Hashtable} of numerical text labels, starting at the 889 * slider minimum, and using the increment specified. 890 * For example, if you call <code>createStandardLabels( 10 )</code> 891 * and the slider minimum is zero, 892 * then labels will be created for the values 0, 10, 20, 30, and so on. 893 * <p> 894 * For the labels to be drawn on the slider, the returned {@code Hashtable} 895 * must be passed into {@code setLabelTable}, and {@code setPaintLabels} 896 * must be set to {@code true}. 897 * <p> 898 * For further details on the makeup of the returned {@code Hashtable}, see 899 * the {@code setLabelTable} documentation. 900 * 901 * @param increment distance between labels in the generated hashtable 902 * @return a new {@code Hashtable} of labels 903 * @see #setLabelTable 904 * @see #setPaintLabels 905 * @throws IllegalArgumentException if {@code increment} is less than or 906 * equal to zero 907 */ 908 public Hashtable<Integer, JComponent> createStandardLabels( int increment ) { 909 return createStandardLabels( increment, getMinimum() ); 910 } 911 912 913 /** 914 * Creates a {@code Hashtable} of numerical text labels, starting at the 915 * starting point specified, and using the increment specified. 916 * For example, if you call 917 * <code>createStandardLabels( 10, 2 )</code>, 918 * then labels will be created for the values 2, 12, 22, 32, and so on. 919 * <p> 920 * For the labels to be drawn on the slider, the returned {@code Hashtable} 921 * must be passed into {@code setLabelTable}, and {@code setPaintLabels} 922 * must be set to {@code true}. 923 * <p> 924 * For further details on the makeup of the returned {@code Hashtable}, see 925 * the {@code setLabelTable} documentation. 926 * 927 * @param increment distance between labels in the generated hashtable 928 * @param start value at which the labels will begin 929 * @return a new {@code Hashtable} of labels 930 * @see #setLabelTable 931 * @see #setPaintLabels 932 * @exception IllegalArgumentException if {@code start} is 933 * out of range, or if {@code increment} is less than or equal 934 * to zero 935 */ 936 public Hashtable<Integer, JComponent> createStandardLabels( int increment, int start ) { 937 if ( start > getMaximum() || start < getMinimum() ) { 938 throw new IllegalArgumentException( "Slider label start point out of range." ); 939 } 940 941 if ( increment <= 0 ) { 942 throw new IllegalArgumentException( "Label incremement must be > 0" ); 943 } 944 945 class SmartHashtable extends Hashtable<Integer, JComponent> implements PropertyChangeListener { 946 int increment = 0; 947 int start = 0; 948 boolean startAtMin = false; 949 950 class LabelUIResource extends JLabel implements UIResource { 951 public LabelUIResource( String text, int alignment ) { 952 super( text, alignment ); 953 setName("Slider.label"); 954 } 955 956 public Font getFont() { 957 Font font = super.getFont(); 958 if (font != null && !(font instanceof UIResource)) { 959 return font; 960 } 961 return JSlider.this.getFont(); 962 } 963 964 public Color getForeground() { 965 Color fg = super.getForeground(); 966 if (fg != null && !(fg instanceof UIResource)) { 967 return fg; 968 } 969 if (!(JSlider.this.getForeground() instanceof UIResource)) { 970 return JSlider.this.getForeground(); 971 } 972 return fg; 973 } 974 } 975 976 public SmartHashtable( int increment, int start ) { 977 super(); 978 this.increment = increment; 979 this.start = start; 980 startAtMin = start == getMinimum(); 981 createLabels(); 982 } 983 984 public void propertyChange( PropertyChangeEvent e ) { 985 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) { 986 start = getMinimum(); 987 } 988 989 if ( e.getPropertyName().equals( "minimum" ) || 990 e.getPropertyName().equals( "maximum" ) ) { 991 992 Enumeration<?> keys = getLabelTable().keys(); 993 Hashtable<Integer, JComponent> hashtable = new Hashtable<>(); 994 995 // Save the labels that were added by the developer 996 while ( keys.hasMoreElements() ) { 997 Integer key = (Integer) keys.nextElement(); 998 JComponent value = (JComponent) labelTable.get(key); 999 if ( !(value instanceof LabelUIResource) ) { 1000 hashtable.put( key, value ); 1001 } 1002 } 1003 1004 clear(); 1005 createLabels(); 1006 1007 // Add the saved labels 1008 keys = hashtable.keys(); 1009 while ( keys.hasMoreElements() ) { 1010 Integer key = (Integer) keys.nextElement(); 1011 put( key, hashtable.get( key ) ); 1012 } 1013 1014 ((JSlider)e.getSource()).setLabelTable( this ); 1015 } 1016 } 1017 1018 void createLabels() { 1019 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) { 1020 put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) ); 1021 } 1022 } 1023 } 1024 1025 SmartHashtable table = new SmartHashtable( increment, start ); 1026 1027 @SuppressWarnings("rawtypes") 1028 Dictionary labelTable = getLabelTable(); 1029 1030 if (labelTable != null && (labelTable instanceof PropertyChangeListener)) { 1031 removePropertyChangeListener((PropertyChangeListener) labelTable); 1032 } 1033 1034 addPropertyChangeListener( table ); 1035 1036 return table; 1037 } 1038 1039 1040 /** 1041 * Returns true if the value-range shown for the slider is reversed, 1042 * 1043 * @return true if the slider values are reversed from their normal order 1044 * @see #setInverted 1045 */ 1046 public boolean getInverted() { 1047 return isInverted; 1048 } 1049 1050 1051 /** 1052 * Specify true to reverse the value-range shown for the slider and false to 1053 * put the value range in the normal order. The order depends on the 1054 * slider's <code>ComponentOrientation</code> property. Normal (non-inverted) 1055 * horizontal sliders with a <code>ComponentOrientation</code> value of 1056 * <code>LEFT_TO_RIGHT</code> have their maximum on the right. 1057 * Normal horizontal sliders with a <code>ComponentOrientation</code> value of 1058 * <code>RIGHT_TO_LEFT</code> have their maximum on the left. Normal vertical 1059 * sliders have their maximum on the top. These labels are reversed when the 1060 * slider is inverted. 1061 * <p> 1062 * By default, the value of this property is {@code false}. 1063 * 1064 * @param b true to reverse the slider values from their normal order 1065 * @beaninfo 1066 * bound: true 1067 * attribute: visualUpdate true 1068 * description: If true reverses the slider values from their normal order 1069 * 1070 */ 1071 public void setInverted( boolean b ) { 1072 boolean oldValue = isInverted; 1073 isInverted = b; 1074 firePropertyChange("inverted", oldValue, isInverted); 1075 if (b != oldValue) { 1076 repaint(); 1077 } 1078 } 1079 1080 1081 /** 1082 * This method returns the major tick spacing. The number that is returned 1083 * represents the distance, measured in values, between each major tick mark. 1084 * If you have a slider with a range from 0 to 50 and the major tick spacing 1085 * is set to 10, you will get major ticks next to the following values: 1086 * 0, 10, 20, 30, 40, 50. 1087 * 1088 * @return the number of values between major ticks 1089 * @see #setMajorTickSpacing 1090 */ 1091 public int getMajorTickSpacing() { 1092 return majorTickSpacing; 1093 } 1094 1095 1096 /** 1097 * This method sets the major tick spacing. The number that is passed in 1098 * represents the distance, measured in values, between each major tick mark. 1099 * If you have a slider with a range from 0 to 50 and the major tick spacing 1100 * is set to 10, you will get major ticks next to the following values: 1101 * 0, 10, 20, 30, 40, 50. 1102 * <p> 1103 * In order for major ticks to be painted, {@code setPaintTicks} must be 1104 * set to {@code true}. 1105 * <p> 1106 * This method will also set up a label table for you. 1107 * If there is not already a label table, and the major tick spacing is 1108 * {@code > 0}, and {@code getPaintLabels} returns 1109 * {@code true}, a standard label table will be generated (by calling 1110 * {@code createStandardLabels}) with labels at the major tick marks. 1111 * For the example above, you would get text labels: "0", 1112 * "10", "20", "30", "40", "50". 1113 * The label table is then set on the slider by calling 1114 * {@code setLabelTable}. 1115 * 1116 * @param n new value for the {@code majorTickSpacing} property 1117 * @see #getMajorTickSpacing 1118 * @see #setPaintTicks 1119 * @see #setLabelTable 1120 * @see #createStandardLabels(int) 1121 * @beaninfo 1122 * bound: true 1123 * attribute: visualUpdate true 1124 * description: Sets the number of values between major tick marks. 1125 * 1126 */ 1127 public void setMajorTickSpacing(int n) { 1128 int oldValue = majorTickSpacing; 1129 majorTickSpacing = n; 1130 if ( labelTable == null && getMajorTickSpacing() > 0 && getPaintLabels() ) { 1131 setLabelTable( createStandardLabels( getMajorTickSpacing() ) ); 1132 } 1133 firePropertyChange("majorTickSpacing", oldValue, majorTickSpacing); 1134 if (majorTickSpacing != oldValue && getPaintTicks()) { 1135 repaint(); 1136 } 1137 } 1138 1139 1140 1141 /** 1142 * This method returns the minor tick spacing. The number that is returned 1143 * represents the distance, measured in values, between each minor tick mark. 1144 * If you have a slider with a range from 0 to 50 and the minor tick spacing 1145 * is set to 10, you will get minor ticks next to the following values: 1146 * 0, 10, 20, 30, 40, 50. 1147 * 1148 * @return the number of values between minor ticks 1149 * @see #getMinorTickSpacing 1150 */ 1151 public int getMinorTickSpacing() { 1152 return minorTickSpacing; 1153 } 1154 1155 1156 /** 1157 * This method sets the minor tick spacing. The number that is passed in 1158 * represents the distance, measured in values, between each minor tick mark. 1159 * If you have a slider with a range from 0 to 50 and the minor tick spacing 1160 * is set to 10, you will get minor ticks next to the following values: 1161 * 0, 10, 20, 30, 40, 50. 1162 * <p> 1163 * In order for minor ticks to be painted, {@code setPaintTicks} must be 1164 * set to {@code true}. 1165 * 1166 * @param n new value for the {@code minorTickSpacing} property 1167 * @see #getMinorTickSpacing 1168 * @see #setPaintTicks 1169 * @beaninfo 1170 * bound: true 1171 * attribute: visualUpdate true 1172 * description: Sets the number of values between minor tick marks. 1173 */ 1174 public void setMinorTickSpacing(int n) { 1175 int oldValue = minorTickSpacing; 1176 minorTickSpacing = n; 1177 firePropertyChange("minorTickSpacing", oldValue, minorTickSpacing); 1178 if (minorTickSpacing != oldValue && getPaintTicks()) { 1179 repaint(); 1180 } 1181 } 1182 1183 1184 /** 1185 * Returns true if the knob (and the data value it represents) 1186 * resolve to the closest tick mark next to where the user 1187 * positioned the knob. 1188 * 1189 * @return true if the value snaps to the nearest tick mark, else false 1190 * @see #setSnapToTicks 1191 */ 1192 public boolean getSnapToTicks() { 1193 return snapToTicks; 1194 } 1195 1196 1197 /** 1198 * Returns true if the knob (and the data value it represents) 1199 * resolve to the closest slider value next to where the user 1200 * positioned the knob. 1201 * 1202 * @return true if the value snaps to the nearest slider value, else false 1203 * @see #setSnapToValue 1204 */ 1205 boolean getSnapToValue() { 1206 return snapToValue; 1207 } 1208 1209 1210 /** 1211 * Specifying true makes the knob (and the data value it represents) 1212 * resolve to the closest tick mark next to where the user 1213 * positioned the knob. 1214 * By default, this property is {@code false}. 1215 * 1216 * @param b true to snap the knob to the nearest tick mark 1217 * @see #getSnapToTicks 1218 * @beaninfo 1219 * bound: true 1220 * description: If true snap the knob to the nearest tick mark. 1221 */ 1222 public void setSnapToTicks(boolean b) { 1223 boolean oldValue = snapToTicks; 1224 snapToTicks = b; 1225 firePropertyChange("snapToTicks", oldValue, snapToTicks); 1226 } 1227 1228 1229 /** 1230 * Specifying true makes the knob (and the data value it represents) 1231 * resolve to the closest slider value next to where the user 1232 * positioned the knob. If the {@code snapToTicks} property has also been 1233 * set to {@code true}, the snap-to-ticks behavior will prevail. 1234 * By default, the snapToValue property is {@code true}. 1235 * 1236 * @param b true to snap the knob to the nearest slider value 1237 * @see #getSnapToValue 1238 * @see #setSnapToTicks 1239 * @beaninfo 1240 * bound: true 1241 * description: If true snap the knob to the nearest slider value. 1242 */ 1243 void setSnapToValue(boolean b) { 1244 boolean oldValue = snapToValue; 1245 snapToValue = b; 1246 firePropertyChange("snapToValue", oldValue, snapToValue); 1247 } 1248 1249 1250 /** 1251 * Tells if tick marks are to be painted. 1252 * @return true if tick marks are painted, else false 1253 * @see #setPaintTicks 1254 */ 1255 public boolean getPaintTicks() { 1256 return paintTicks; 1257 } 1258 1259 1260 /** 1261 * Determines whether tick marks are painted on the slider. 1262 * By default, this property is {@code false}. 1263 * 1264 * @param b whether or not tick marks should be painted 1265 * @see #getPaintTicks 1266 * @beaninfo 1267 * bound: true 1268 * attribute: visualUpdate true 1269 * description: If true tick marks are painted on the slider. 1270 */ 1271 public void setPaintTicks(boolean b) { 1272 boolean oldValue = paintTicks; 1273 paintTicks = b; 1274 firePropertyChange("paintTicks", oldValue, paintTicks); 1275 if (paintTicks != oldValue) { 1276 revalidate(); 1277 repaint(); 1278 } 1279 } 1280 1281 /** 1282 * Tells if the track (area the slider slides in) is to be painted. 1283 * @return true if track is painted, else false 1284 * @see #setPaintTrack 1285 */ 1286 public boolean getPaintTrack() { 1287 return paintTrack; 1288 } 1289 1290 1291 /** 1292 * Determines whether the track is painted on the slider. 1293 * By default, this property is {@code true}. 1294 * 1295 * @param b whether or not to paint the slider track 1296 * @see #getPaintTrack 1297 * @beaninfo 1298 * bound: true 1299 * attribute: visualUpdate true 1300 * description: If true, the track is painted on the slider. 1301 */ 1302 public void setPaintTrack(boolean b) { 1303 boolean oldValue = paintTrack; 1304 paintTrack = b; 1305 firePropertyChange("paintTrack", oldValue, paintTrack); 1306 if (paintTrack != oldValue) { 1307 repaint(); 1308 } 1309 } 1310 1311 1312 /** 1313 * Tells if labels are to be painted. 1314 * @return true if labels are painted, else false 1315 * @see #setPaintLabels 1316 */ 1317 public boolean getPaintLabels() { 1318 return paintLabels; 1319 } 1320 1321 1322 /** 1323 * Determines whether labels are painted on the slider. 1324 * <p> 1325 * This method will also set up a label table for you. 1326 * If there is not already a label table, and the major tick spacing is 1327 * {@code > 0}, 1328 * a standard label table will be generated (by calling 1329 * {@code createStandardLabels}) with labels at the major tick marks. 1330 * The label table is then set on the slider by calling 1331 * {@code setLabelTable}. 1332 * <p> 1333 * By default, this property is {@code false}. 1334 * 1335 * @param b whether or not to paint labels 1336 * @see #getPaintLabels 1337 * @see #getLabelTable 1338 * @see #createStandardLabels(int) 1339 * @beaninfo 1340 * bound: true 1341 * attribute: visualUpdate true 1342 * description: If true labels are painted on the slider. 1343 */ 1344 public void setPaintLabels(boolean b) { 1345 boolean oldValue = paintLabels; 1346 paintLabels = b; 1347 if ( labelTable == null && getMajorTickSpacing() > 0 ) { 1348 setLabelTable( createStandardLabels( getMajorTickSpacing() ) ); 1349 } 1350 firePropertyChange("paintLabels", oldValue, paintLabels); 1351 if (paintLabels != oldValue) { 1352 revalidate(); 1353 repaint(); 1354 } 1355 } 1356 1357 1358 /** 1359 * See readObject() and writeObject() in JComponent for more 1360 * information about serialization in Swing. 1361 */ 1362 private void writeObject(ObjectOutputStream s) throws IOException { 1363 s.defaultWriteObject(); 1364 if (getUIClassID().equals(uiClassID)) { 1365 byte count = JComponent.getWriteObjCounter(this); 1366 JComponent.setWriteObjCounter(this, --count); 1367 if (count == 0 && ui != null) { 1368 ui.installUI(this); 1369 } 1370 } 1371 } 1372 1373 1374 /** 1375 * Returns a string representation of this JSlider. This method 1376 * is intended to be used only for debugging purposes, and the 1377 * content and format of the returned string may vary between 1378 * implementations. The returned string may be empty but may not 1379 * be <code>null</code>. 1380 * 1381 * @return a string representation of this JSlider. 1382 */ 1383 protected String paramString() { 1384 String paintTicksString = (paintTicks ? 1385 "true" : "false"); 1386 String paintTrackString = (paintTrack ? 1387 "true" : "false"); 1388 String paintLabelsString = (paintLabels ? 1389 "true" : "false"); 1390 String isInvertedString = (isInverted ? 1391 "true" : "false"); 1392 String snapToTicksString = (snapToTicks ? 1393 "true" : "false"); 1394 String snapToValueString = (snapToValue ? 1395 "true" : "false"); 1396 String orientationString = (orientation == HORIZONTAL ? 1397 "HORIZONTAL" : "VERTICAL"); 1398 1399 return super.paramString() + 1400 ",isInverted=" + isInvertedString + 1401 ",majorTickSpacing=" + majorTickSpacing + 1402 ",minorTickSpacing=" + minorTickSpacing + 1403 ",orientation=" + orientationString + 1404 ",paintLabels=" + paintLabelsString + 1405 ",paintTicks=" + paintTicksString + 1406 ",paintTrack=" + paintTrackString + 1407 ",snapToTicks=" + snapToTicksString + 1408 ",snapToValue=" + snapToValueString; 1409 } 1410 1411 1412 ///////////////// 1413 // Accessibility support 1414 //////////////// 1415 1416 /** 1417 * Gets the AccessibleContext associated with this JSlider. 1418 * For sliders, the AccessibleContext takes the form of an 1419 * AccessibleJSlider. 1420 * A new AccessibleJSlider instance is created if necessary. 1421 * 1422 * @return an AccessibleJSlider that serves as the 1423 * AccessibleContext of this JSlider 1424 */ 1425 public AccessibleContext getAccessibleContext() { 1426 if (accessibleContext == null) { 1427 accessibleContext = new AccessibleJSlider(); 1428 } 1429 return accessibleContext; 1430 } 1431 1432 /** 1433 * This class implements accessibility support for the 1434 * <code>JSlider</code> class. It provides an implementation of the 1435 * Java Accessibility API appropriate to slider user-interface elements. 1436 * <p> 1437 * <strong>Warning:</strong> 1438 * Serialized objects of this class will not be compatible with 1439 * future Swing releases. The current serialization support is 1440 * appropriate for short term storage or RMI between applications running 1441 * the same version of Swing. As of 1.4, support for long term storage 1442 * of all JavaBeans™ 1443 * has been added to the <code>java.beans</code> package. 1444 * Please see {@link java.beans.XMLEncoder}. 1445 */ 1446 @SuppressWarnings("serial") // Same-version serialization only 1447 protected class AccessibleJSlider extends AccessibleJComponent 1448 implements AccessibleValue { 1449 1450 /** 1451 * Get the state set of this object. 1452 * 1453 * @return an instance of AccessibleState containing the current state 1454 * of the object 1455 * @see AccessibleState 1456 */ 1457 public AccessibleStateSet getAccessibleStateSet() { 1458 AccessibleStateSet states = super.getAccessibleStateSet(); 1459 if (getValueIsAdjusting()) { 1460 states.add(AccessibleState.BUSY); 1461 } 1462 if (getOrientation() == VERTICAL) { 1463 states.add(AccessibleState.VERTICAL); 1464 } 1465 else { 1466 states.add(AccessibleState.HORIZONTAL); 1467 } 1468 return states; 1469 } 1470 1471 /** 1472 * Get the role of this object. 1473 * 1474 * @return an instance of AccessibleRole describing the role of the object 1475 */ 1476 public AccessibleRole getAccessibleRole() { 1477 return AccessibleRole.SLIDER; 1478 } 1479 1480 /** 1481 * Get the AccessibleValue associated with this object. In the 1482 * implementation of the Java Accessibility API for this class, 1483 * return this object, which is responsible for implementing the 1484 * AccessibleValue interface on behalf of itself. 1485 * 1486 * @return this object 1487 */ 1488 public AccessibleValue getAccessibleValue() { 1489 return this; 1490 } 1491 1492 /** 1493 * Get the accessible value of this object. 1494 * 1495 * @return The current value of this object. 1496 */ 1497 public Number getCurrentAccessibleValue() { 1498 return Integer.valueOf(getValue()); 1499 } 1500 1501 /** 1502 * Set the value of this object as a Number. 1503 * 1504 * @return True if the value was set. 1505 */ 1506 public boolean setCurrentAccessibleValue(Number n) { 1507 // TIGER - 4422535 1508 if (n == null) { 1509 return false; 1510 } 1511 setValue(n.intValue()); 1512 return true; 1513 } 1514 1515 /** 1516 * Get the minimum accessible value of this object. 1517 * 1518 * @return The minimum value of this object. 1519 */ 1520 public Number getMinimumAccessibleValue() { 1521 return Integer.valueOf(getMinimum()); 1522 } 1523 1524 /** 1525 * Get the maximum accessible value of this object. 1526 * 1527 * @return The maximum value of this object. 1528 */ 1529 public Number getMaximumAccessibleValue() { 1530 // TIGER - 4422362 1531 BoundedRangeModel model = JSlider.this.getModel(); 1532 return Integer.valueOf(model.getMaximum() - model.getExtent()); 1533 } 1534 } // AccessibleJSlider 1535 }