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