1. /*
  2. * @(#)JSlider.java 1.105 04/05/12
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import javax.swing.border.*;
  9. import javax.swing.event.*;
  10. import javax.swing.plaf.*;
  11. import javax.accessibility.*;
  12. import java.io.Serializable;
  13. import java.io.ObjectOutputStream;
  14. import java.io.ObjectInputStream;
  15. import java.io.IOException;
  16. import java.util.*;
  17. import java.beans.*;
  18. /**
  19. * A component that lets the user graphically select a value by sliding
  20. * a knob within a bounded interval. The slider can show both
  21. * major tick marks and minor tick marks between them. The number of
  22. * values between the tick marks is controlled with
  23. * <code>setMajorTickSpacing</code> and <code>setMinorTickSpacing</code>.
  24. * <p>
  25. * For further information and examples see
  26. * <a
  27. href="http://java.sun.com/docs/books/tutorial/uiswing/components/slider.html">How to Use Sliders</a>,
  28. * a section in <em>The Java Tutorial.</em>
  29. * <p>
  30. * <strong>Warning:</strong>
  31. * Serialized objects of this class will not be compatible with
  32. * future Swing releases. The current serialization support is
  33. * appropriate for short term storage or RMI between applications running
  34. * the same version of Swing. As of 1.4, support for long term storage
  35. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  36. * has been added to the <code>java.beans</code> package.
  37. * Please see {@link java.beans.XMLEncoder}.
  38. *
  39. * @beaninfo
  40. * attribute: isContainer false
  41. * description: A component that supports selecting a integer value from a range.
  42. *
  43. * @version 1.105 05/12/04
  44. * @author David Kloba
  45. */
  46. public class JSlider extends JComponent implements SwingConstants, Accessible {
  47. /**
  48. * @see #getUIClassID
  49. * @see #readObject
  50. */
  51. private static final String uiClassID = "SliderUI";
  52. private boolean paintTicks = false;
  53. private boolean paintTrack = true;
  54. private boolean paintLabels = false;
  55. private boolean isInverted = false;
  56. /**
  57. * The data model that handles the numeric maximum value,
  58. * minimum value, and current-position value for the slider.
  59. */
  60. protected BoundedRangeModel sliderModel;
  61. /**
  62. * The number of values between the major tick marks -- the
  63. * larger marks that break up the minor tick marks.
  64. */
  65. protected int majorTickSpacing;
  66. /**
  67. * The number of values between the minor tick marks -- the
  68. * smaller marks that occur between the major tick marks.
  69. * @see #setMinorTickSpacing
  70. */
  71. protected int minorTickSpacing;
  72. /**
  73. * If true, the knob (and the data value it represents)
  74. * resolve to the closest tick mark next to where the user
  75. * positioned the knob. The default is false.
  76. * @see #setSnapToTicks
  77. */
  78. protected boolean snapToTicks = false;
  79. /**
  80. * If true, the knob (and the data value it represents)
  81. * resolve to the closest slider value next to where the user
  82. * positioned the knob.
  83. */
  84. boolean snapToValue = true;
  85. /**
  86. * @see #setOrientation
  87. */
  88. protected int orientation;
  89. /**
  90. */
  91. private Dictionary labelTable;
  92. /**
  93. * The changeListener (no suffix) is the listener we add to the
  94. * Sliders model. By default this listener just forwards events
  95. * to ChangeListeners (if any) added directly to the slider.
  96. *
  97. * @see #addChangeListener
  98. * @see #createChangeListener
  99. */
  100. protected ChangeListener changeListener = createChangeListener();
  101. /**
  102. * Only one <code>ChangeEvent</code> is needed per slider instance since the
  103. * event's only (read-only) state is the source property. The source
  104. * of events generated here is always "this". The event is lazily
  105. * created the first time that an event notification is fired.
  106. *
  107. * @see #fireStateChanged
  108. */
  109. protected transient ChangeEvent changeEvent = null;
  110. private void checkOrientation(int orientation) {
  111. switch (orientation) {
  112. case VERTICAL:
  113. case HORIZONTAL:
  114. break;
  115. default:
  116. throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
  117. }
  118. }
  119. /**
  120. * Creates a horizontal slider with the range 0 to 100 and
  121. * an initial value of 50.
  122. */
  123. public JSlider() {
  124. this(HORIZONTAL, 0, 100, 50);
  125. }
  126. /**
  127. * Creates a slider using the specified orientation with the
  128. * range 0 to 100 and an initial value of 50.
  129. */
  130. public JSlider(int orientation) {
  131. this(orientation, 0, 100, 50);
  132. }
  133. /**
  134. * Creates a horizontal slider using the specified min and max
  135. * with an initial value equal to the average of the min plus max.
  136. */
  137. public JSlider(int min, int max) {
  138. this(HORIZONTAL, min, max, (min + max) / 2);
  139. }
  140. /**
  141. * Creates a horizontal slider using the specified min, max and value.
  142. */
  143. public JSlider(int min, int max, int value) {
  144. this(HORIZONTAL, min, max, value);
  145. }
  146. /**
  147. * Creates a slider with the specified orientation and the
  148. * specified minimum, maximum, and initial values.
  149. *
  150. * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
  151. *
  152. * @see #setOrientation
  153. * @see #setMinimum
  154. * @see #setMaximum
  155. * @see #setValue
  156. */
  157. public JSlider(int orientation, int min, int max, int value)
  158. {
  159. checkOrientation(orientation);
  160. this.orientation = orientation;
  161. sliderModel = new DefaultBoundedRangeModel(value, 0, min, max);
  162. sliderModel.addChangeListener(changeListener);
  163. updateUI();
  164. }
  165. /**
  166. * Creates a horizontal slider using the specified
  167. * BoundedRangeModel.
  168. */
  169. public JSlider(BoundedRangeModel brm)
  170. {
  171. this.orientation = JSlider.HORIZONTAL;
  172. setModel(brm);
  173. sliderModel.addChangeListener(changeListener);
  174. updateUI();
  175. }
  176. /**
  177. * Gets the UI object which implements the L&F for this component.
  178. *
  179. * @return the SliderUI object that implements the Slider L&F
  180. */
  181. public SliderUI getUI() {
  182. return(SliderUI)ui;
  183. }
  184. /**
  185. * Sets the UI object which implements the L&F for this component.
  186. *
  187. * @param ui the SliderUI L&F object
  188. * @see UIDefaults#getUI
  189. * @beaninfo
  190. * bound: true
  191. * hidden: true
  192. * attribute: visualUpdate true
  193. * description: The UI object that implements the slider's LookAndFeel.
  194. */
  195. public void setUI(SliderUI ui) {
  196. super.setUI(ui);
  197. }
  198. /**
  199. * Resets the UI property to a value from the current look and feel.
  200. *
  201. * @see JComponent#updateUI
  202. */
  203. public void updateUI() {
  204. updateLabelUIs();
  205. setUI((SliderUI)UIManager.getUI(this));
  206. }
  207. /**
  208. * Returns the name of the L&F class that renders this component.
  209. *
  210. * @return "SliderUI"
  211. * @see JComponent#getUIClassID
  212. * @see UIDefaults#getUI
  213. */
  214. public String getUIClassID() {
  215. return uiClassID;
  216. }
  217. /**
  218. * We pass Change events along to the listeners with the
  219. * the slider (instead of the model itself) as the event source.
  220. */
  221. private class ModelListener implements ChangeListener, Serializable {
  222. public void stateChanged(ChangeEvent e) {
  223. fireStateChanged();
  224. }
  225. }
  226. /**
  227. * Subclasses that want to handle model ChangeEvents differently
  228. * can override this method to return their own ChangeListener
  229. * implementation. The default ChangeListener just forwards
  230. * ChangeEvents to the ChangeListeners added directly to the slider.
  231. *
  232. * @see #fireStateChanged
  233. */
  234. protected ChangeListener createChangeListener() {
  235. return new ModelListener();
  236. }
  237. /**
  238. * Adds a ChangeListener to the slider.
  239. *
  240. * @param l the ChangeListener to add
  241. * @see #fireStateChanged
  242. * @see #removeChangeListener
  243. */
  244. public void addChangeListener(ChangeListener l) {
  245. listenerList.add(ChangeListener.class, l);
  246. }
  247. /**
  248. * Removes a ChangeListener from the slider.
  249. *
  250. * @param l the ChangeListener to remove
  251. * @see #fireStateChanged
  252. * @see #addChangeListener
  253. */
  254. public void removeChangeListener(ChangeListener l) {
  255. listenerList.remove(ChangeListener.class, l);
  256. }
  257. /**
  258. * Returns an array of all the <code>ChangeListener</code>s added
  259. * to this JSlider with addChangeListener().
  260. *
  261. * @return all of the <code>ChangeListener</code>s added or an empty
  262. * array if no listeners have been added
  263. * @since 1.4
  264. */
  265. public ChangeListener[] getChangeListeners() {
  266. return (ChangeListener[])listenerList.getListeners(
  267. ChangeListener.class);
  268. }
  269. /**
  270. * Send a ChangeEvent, whose source is this Slider, to
  271. * each listener. This method method is called each time
  272. * a ChangeEvent is received from the model.
  273. *
  274. * @see #addChangeListener
  275. * @see EventListenerList
  276. */
  277. protected void fireStateChanged() {
  278. Object[] listeners = listenerList.getListenerList();
  279. for (int i = listeners.length - 2; i >= 0; i -= 2) {
  280. if (listeners[i]==ChangeListener.class) {
  281. if (changeEvent == null) {
  282. changeEvent = new ChangeEvent(this);
  283. }
  284. ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  285. }
  286. }
  287. }
  288. /**
  289. * Returns data model that handles the sliders three
  290. * fundamental properties: minimum, maximum, value.
  291. *
  292. * @see #setModel
  293. */
  294. public BoundedRangeModel getModel() {
  295. return sliderModel;
  296. }
  297. /**
  298. * Sets the model that handles the sliders three
  299. * fundamental properties: minimum, maximum, value.
  300. *
  301. * @see #getModel
  302. * @beaninfo
  303. * bound: true
  304. * description: The sliders BoundedRangeModel.
  305. */
  306. public void setModel(BoundedRangeModel newModel)
  307. {
  308. BoundedRangeModel oldModel = getModel();
  309. if (oldModel != null) {
  310. oldModel.removeChangeListener(changeListener);
  311. }
  312. sliderModel = newModel;
  313. if (newModel != null) {
  314. newModel.addChangeListener(changeListener);
  315. if (accessibleContext != null) {
  316. accessibleContext.firePropertyChange(
  317. AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
  318. (oldModel == null
  319. ? null : new Integer(oldModel.getValue())),
  320. (newModel == null
  321. ? null : new Integer(newModel.getValue())));
  322. }
  323. }
  324. firePropertyChange("model", oldModel, sliderModel);
  325. }
  326. /**
  327. * Returns the sliders value.
  328. * @return the models value property
  329. * @see #setValue
  330. */
  331. public int getValue() {
  332. return getModel().getValue();
  333. }
  334. /**
  335. * Sets the sliders current value. This method just forwards
  336. * the value to the model.
  337. *
  338. * @see #getValue
  339. * @beaninfo
  340. * preferred: true
  341. * description: The sliders current value.
  342. */
  343. public void setValue(int n) {
  344. BoundedRangeModel m = getModel();
  345. int oldValue = m.getValue();
  346. if (oldValue == n) {
  347. return;
  348. }
  349. m.setValue(n);
  350. if (accessibleContext != null) {
  351. accessibleContext.firePropertyChange(
  352. AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
  353. new Integer(oldValue),
  354. new Integer(m.getValue()));
  355. }
  356. }
  357. /**
  358. * Returns the minimum value supported by the slider.
  359. *
  360. * @return the value of the models minimum property
  361. * @see #setMinimum
  362. */
  363. public int getMinimum() {
  364. return getModel().getMinimum();
  365. }
  366. /**
  367. * Sets the models minimum property.
  368. *
  369. * @see #getMinimum
  370. * @see BoundedRangeModel#setMinimum
  371. * @beaninfo
  372. * bound: true
  373. * preferred: true
  374. * description: The sliders minimum value.
  375. */
  376. public void setMinimum(int minimum) {
  377. int oldMin = getModel().getMinimum();
  378. getModel().setMinimum(minimum);
  379. firePropertyChange( "minimum", new Integer( oldMin ), new Integer( minimum ) );
  380. }
  381. /**
  382. * Returns the maximum value supported by the slider.
  383. *
  384. * @return the value of the models maximum property
  385. * @see #setMaximum
  386. */
  387. public int getMaximum() {
  388. return getModel().getMaximum();
  389. }
  390. /**
  391. * Sets the models maximum property.
  392. *
  393. * @see #getMaximum
  394. * @see BoundedRangeModel#setMaximum
  395. * @beaninfo
  396. * bound: true
  397. * preferred: true
  398. * description: The sliders maximum value.
  399. */
  400. public void setMaximum(int maximum) {
  401. int oldMax = getModel().getMaximum();
  402. getModel().setMaximum(maximum);
  403. firePropertyChange( "maximum", new Integer( oldMax ), new Integer( maximum ) );
  404. }
  405. /**
  406. * True if the slider knob is being dragged.
  407. *
  408. * @return the value of the models valueIsAdjusting property
  409. * @see #setValueIsAdjusting
  410. */
  411. public boolean getValueIsAdjusting() {
  412. return getModel().getValueIsAdjusting();
  413. }
  414. /**
  415. * Sets the models valueIsAdjusting property. Slider look and
  416. * feel implementations should set this property to true when
  417. * a knob drag begins, and to false when the drag ends. The
  418. * slider model will not generate ChangeEvents while
  419. * valueIsAdjusting is true.
  420. *
  421. * @see #getValueIsAdjusting
  422. * @see BoundedRangeModel#setValueIsAdjusting
  423. * @beaninfo
  424. * expert: true
  425. * description: True if the slider knob is being dragged.
  426. */
  427. public void setValueIsAdjusting(boolean b) {
  428. BoundedRangeModel m = getModel();
  429. boolean oldValue = m.getValueIsAdjusting();
  430. m.setValueIsAdjusting(b);
  431. if ((oldValue != b) && (accessibleContext != null)) {
  432. accessibleContext.firePropertyChange(
  433. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  434. ((oldValue) ? AccessibleState.BUSY : null),
  435. ((b) ? AccessibleState.BUSY : null));
  436. }
  437. }
  438. /**
  439. * Returns the "extent" -- the range of values "covered" by the knob.
  440. * @return an int representing the extent
  441. * @see #setExtent
  442. * @see BoundedRangeModel#getExtent
  443. */
  444. public int getExtent() {
  445. return getModel().getExtent();
  446. }
  447. /**
  448. * Sets the size of the range "covered" by the knob. Most look
  449. * and feel implementations will change the value by this amount
  450. * if the user clicks on either side of the knob.
  451. *
  452. * @see #getExtent
  453. * @see BoundedRangeModel#setExtent
  454. * @beaninfo
  455. * expert: true
  456. * description: Size of the range covered by the knob.
  457. */
  458. public void setExtent(int extent) {
  459. getModel().setExtent(extent);
  460. }
  461. /**
  462. * Return this slider's vertical or horizontal orientation.
  463. * @return VERTICAL or HORIZONTAL
  464. * @see #setOrientation
  465. */
  466. public int getOrientation() {
  467. return orientation;
  468. }
  469. /**
  470. * Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
  471. *
  472. * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
  473. * @see #getOrientation
  474. * @beaninfo
  475. * preferred: true
  476. * bound: true
  477. * attribute: visualUpdate true
  478. * description: Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
  479. * enum: VERTICAL JSlider.VERTICAL
  480. * HORIZONTAL JSlider.HORIZONTAL
  481. *
  482. */
  483. public void setOrientation(int orientation)
  484. {
  485. checkOrientation(orientation);
  486. int oldValue = this.orientation;
  487. this.orientation = orientation;
  488. firePropertyChange("orientation", oldValue, orientation);
  489. if ((oldValue != orientation) && (accessibleContext != null)) {
  490. accessibleContext.firePropertyChange(
  491. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  492. ((oldValue == VERTICAL)
  493. ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
  494. ((orientation == VERTICAL)
  495. ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
  496. }
  497. if (orientation != oldValue) {
  498. revalidate();
  499. }
  500. }
  501. /**
  502. * Returns the dictionary of what labels to draw at which values.
  503. *
  504. * @return the <code>Dictionary</code> containing labels and
  505. * where to draw them
  506. */
  507. public Dictionary getLabelTable() {
  508. /*
  509. if ( labelTable == null && getMajorTickSpacing() > 0 ) {
  510. setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
  511. }
  512. */
  513. return labelTable;
  514. }
  515. /**
  516. * Used to specify what label will be drawn at any given value.
  517. * The key-value pairs are of this format:
  518. * <code>{ Integer value, java.swing.JComponent label }</code>.
  519. *
  520. * @see #createStandardLabels
  521. * @see #getLabelTable
  522. * @beaninfo
  523. * hidden: true
  524. * bound: true
  525. * attribute: visualUpdate true
  526. * description: Specifies what labels will be drawn for any given value.
  527. */
  528. public void setLabelTable( Dictionary labels ) {
  529. Dictionary oldTable = labelTable;
  530. labelTable = labels;
  531. updateLabelUIs();
  532. firePropertyChange("labelTable", oldTable, labelTable );
  533. if (labels != oldTable) {
  534. revalidate();
  535. repaint();
  536. }
  537. }
  538. /**
  539. * Resets the UI property to a value from the current look and feel.
  540. *
  541. * @see JComponent#updateUI
  542. */
  543. protected void updateLabelUIs() {
  544. if ( getLabelTable() == null ) {
  545. return;
  546. }
  547. Enumeration labels = getLabelTable().keys();
  548. while ( labels.hasMoreElements() ) {
  549. Object value = getLabelTable().get( labels.nextElement() );
  550. if ( value instanceof JComponent ) {
  551. JComponent component = (JComponent)value;
  552. component.updateUI();
  553. component.setSize( component.getPreferredSize() );
  554. }
  555. }
  556. }
  557. /**
  558. * Creates a hashtable that will draw text labels starting at the
  559. * slider minimum using the increment specified.
  560. * If you call <code>createStandardLabels( 10 )</code>
  561. * and the slider minimum is
  562. * zero, then it will make labels for the values 0, 10, 20, 30, and so on.
  563. * @see #setLabelTable
  564. */
  565. public Hashtable createStandardLabels( int increment ) {
  566. return createStandardLabels( increment, getMinimum() );
  567. }
  568. /**
  569. * Creates a hashtable that will draw text labels starting at the
  570. * start point
  571. * specified using the increment specified. If you call
  572. * <code>createStandardLabels( 10, 2 )</code>,
  573. * then it will make labels for the values 2, 12, 22, 32, and so on.
  574. * @see #setLabelTable
  575. * @exception IllegalArgumentException if slider label start point
  576. * out of range or if label increment is less than or equal
  577. * to zero
  578. */
  579. public Hashtable createStandardLabels( int increment, int start ) {
  580. if ( start > getMaximum() || start < getMinimum() ) {
  581. throw new IllegalArgumentException( "Slider label start point out of range." );
  582. }
  583. if ( increment <= 0 ) {
  584. throw new IllegalArgumentException( "Label incremement must be > 0" );
  585. }
  586. class SmartHashtable extends Hashtable implements PropertyChangeListener {
  587. int increment = 0;
  588. int start = 0;
  589. boolean startAtMin = false;
  590. class LabelUIResource extends JLabel implements UIResource {
  591. public LabelUIResource( String text, int alignment ) {
  592. super( text, alignment );
  593. setName("Slider.label");
  594. }
  595. }
  596. public SmartHashtable( int increment, int start ) {
  597. super();
  598. this.increment = increment;
  599. this.start = start;
  600. startAtMin = start == getMinimum();
  601. createLabels();
  602. }
  603. public void propertyChange( PropertyChangeEvent e ) {
  604. if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) {
  605. start = getMinimum();
  606. }
  607. if ( e.getPropertyName().equals( "minimum" ) ||
  608. e.getPropertyName().equals( "maximum" ) ) {
  609. Enumeration keys = getLabelTable().keys();
  610. Object key = null;
  611. Hashtable hashtable = new Hashtable();
  612. // Save the labels that were added by the developer
  613. while ( keys.hasMoreElements() ) {
  614. key = keys.nextElement();
  615. Object value = getLabelTable().get( key );
  616. if ( !(value instanceof LabelUIResource) ) {
  617. hashtable.put( key, value );
  618. }
  619. }
  620. clear();
  621. createLabels();
  622. // Add the saved labels
  623. keys = hashtable.keys();
  624. while ( keys.hasMoreElements() ) {
  625. key = keys.nextElement();
  626. put( key, hashtable.get( key ) );
  627. }
  628. ((JSlider)e.getSource()).setLabelTable( this );
  629. }
  630. }
  631. void createLabels() {
  632. for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
  633. put( new Integer( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) );
  634. }
  635. }
  636. }
  637. SmartHashtable table = new SmartHashtable( increment, start );
  638. if ( getLabelTable() != null && (getLabelTable() instanceof PropertyChangeListener) ) {
  639. removePropertyChangeListener( (PropertyChangeListener)getLabelTable() );
  640. }
  641. addPropertyChangeListener( table );
  642. return table;
  643. }
  644. /**
  645. * Returns true if the value-range shown for the slider is reversed,
  646. *
  647. * @return true if the slider values are reversed from their normal order
  648. * @see #setInverted
  649. */
  650. public boolean getInverted() {
  651. return isInverted;
  652. }
  653. /**
  654. * Specify true to reverse the value-range shown for the slider and false to
  655. * put the value range in the normal order. The order depends on the
  656. * slider's <code>ComponentOrientation</code> property. Normal (non-inverted)
  657. * horizontal sliders with a <code>ComponentOrientation</code> value of
  658. * <code>LEFT_TO_RIGHT</code> have their maximum on the right.
  659. * Normal horizontal sliders with a <code>ComponentOrientation</code> value of
  660. * <code>RIGHT_TO_LEFT</code> have their maximum on the left. Normal vertical
  661. * sliders have their maximum on the top. These labels are reversed when the
  662. * slider is inverted.
  663. *
  664. * @param b true to reverse the slider values from their normal order
  665. * @beaninfo
  666. * bound: true
  667. * attribute: visualUpdate true
  668. * description: If true reverses the slider values from their normal order
  669. *
  670. */
  671. public void setInverted( boolean b ) {
  672. boolean oldValue = isInverted;
  673. isInverted = b;
  674. firePropertyChange("inverted", oldValue, isInverted);
  675. if (b != oldValue) {
  676. repaint();
  677. }
  678. }
  679. /**
  680. * This method returns the major tick spacing. The number that is returned
  681. * represents the distance, measured in values, between each major tick mark.
  682. * If you have a slider with a range from 0 to 50 and the major tick spacing
  683. * is set to 10, you will get major ticks next to the following values:
  684. * 0, 10, 20, 30, 40, 50.
  685. *
  686. * @return the number of values between major ticks
  687. * @see #setMajorTickSpacing
  688. */
  689. public int getMajorTickSpacing() {
  690. return majorTickSpacing;
  691. }
  692. /**
  693. * This method sets the major tick spacing. The number that is passed-in
  694. * represents the distance, measured in values, between each major tick mark.
  695. * If you have a slider with a range from 0 to 50 and the major tick spacing
  696. * is set to 10, you will get major ticks next to the following values:
  697. * 0, 10, 20, 30, 40, 50.
  698. *
  699. * @see #getMajorTickSpacing
  700. * @beaninfo
  701. * bound: true
  702. * attribute: visualUpdate true
  703. * description: Sets the number of values between major tick marks.
  704. *
  705. */
  706. public void setMajorTickSpacing(int n) {
  707. int oldValue = majorTickSpacing;
  708. majorTickSpacing = n;
  709. if ( labelTable == null && getMajorTickSpacing() > 0 && getPaintLabels() ) {
  710. setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
  711. }
  712. firePropertyChange("majorTickSpacing", oldValue, majorTickSpacing);
  713. if (majorTickSpacing != oldValue && getPaintTicks()) {
  714. repaint();
  715. }
  716. }
  717. /**
  718. * This method returns the minor tick spacing. The number that is returned
  719. * represents the distance, measured in values, between each minor tick mark.
  720. * If you have a slider with a range from 0 to 50 and the minor tick spacing
  721. * is set to 10, you will get minor ticks next to the following values:
  722. * 0, 10, 20, 30, 40, 50.
  723. *
  724. * @return the number of values between minor ticks
  725. * @see #getMinorTickSpacing
  726. */
  727. public int getMinorTickSpacing() {
  728. return minorTickSpacing;
  729. }
  730. /**
  731. * This method sets the minor tick spacing. The number that is passed-in
  732. * represents the distance, measured in values, between each minor tick mark.
  733. * If you have a slider with a range from 0 to 50 and the minor tick spacing
  734. * is set to 10, you will get minor ticks next to the following values:
  735. * 0, 10, 20, 30, 40, 50.
  736. *
  737. * @see #getMinorTickSpacing
  738. * @beaninfo
  739. * bound: true
  740. * attribute: visualUpdate true
  741. * description: Sets the number of values between minor tick marks.
  742. */
  743. public void setMinorTickSpacing(int n) {
  744. int oldValue = minorTickSpacing;
  745. minorTickSpacing = n;
  746. firePropertyChange("minorTickSpacing", oldValue, minorTickSpacing);
  747. if (minorTickSpacing != oldValue && getPaintTicks()) {
  748. repaint();
  749. }
  750. }
  751. /**
  752. * Returns true if the knob (and the data value it represents)
  753. * resolve to the closest tick mark next to where the user
  754. * positioned the knob.
  755. *
  756. * @return true if the value snaps to the nearest tick mark, else false
  757. * @see #setSnapToTicks
  758. */
  759. public boolean getSnapToTicks() {
  760. return snapToTicks;
  761. }
  762. /**
  763. * Returns true if the knob (and the data value it represents)
  764. * resolve to the closest slider value next to where the user
  765. * positioned the knob.
  766. *
  767. * @return true if the value snaps to the nearest slider value, else false
  768. */
  769. boolean getSnapToValue() {
  770. return snapToValue;
  771. }
  772. /**
  773. * Specifying true makes the knob (and the data value it represents)
  774. * resolve to the closest tick mark next to where the user
  775. * positioned the knob.
  776. *
  777. * @param b true to snap the knob to the nearest tick mark
  778. * @see #getSnapToTicks
  779. * @beaninfo
  780. * bound: true
  781. * description: If true snap the knob to the nearest tick mark.
  782. */
  783. public void setSnapToTicks(boolean b) {
  784. boolean oldValue = snapToTicks;
  785. snapToTicks = b;
  786. firePropertyChange("snapToTicks", oldValue, snapToTicks);
  787. }
  788. /**
  789. * Specifying true makes the knob (and the data value it represents)
  790. * resolve to the closest slider value next to where the user
  791. * positioned the knob. If the snapToTicks property has been set to
  792. * true, the snap-to-ticks behavior will prevail.
  793. *
  794. * @param b true to snap the knob to the nearest slider value
  795. * @see #getSnapToValue
  796. * @see #setSnapToTicks
  797. * @beaninfo
  798. * bound: true
  799. * description: If true snap the knob to the nearest slider value.
  800. */
  801. void setSnapToValue(boolean b) {
  802. boolean oldValue = snapToValue;
  803. snapToValue = b;
  804. firePropertyChange("snapToValue", oldValue, snapToValue);
  805. }
  806. /**
  807. * Tells if tick marks are to be painted.
  808. * @return true if tick marks are painted, else false
  809. * @see #setPaintTicks
  810. */
  811. public boolean getPaintTicks() {
  812. return paintTicks;
  813. }
  814. /**
  815. * Determines whether tick marks are painted on the slider.
  816. * @see #getPaintTicks
  817. * @beaninfo
  818. * bound: true
  819. * attribute: visualUpdate true
  820. * description: If true tick marks are painted on the slider.
  821. */
  822. public void setPaintTicks(boolean b) {
  823. boolean oldValue = paintTicks;
  824. paintTicks = b;
  825. firePropertyChange("paintTicks", oldValue, paintTicks);
  826. if (paintTicks != oldValue) {
  827. revalidate();
  828. repaint();
  829. }
  830. }
  831. /**
  832. * Tells if the track (area the slider slides in) is to be painted.
  833. * @return true if track is painted, else false
  834. * @see #setPaintTrack
  835. */
  836. public boolean getPaintTrack() {
  837. return paintTrack;
  838. }
  839. /**
  840. * Determines whether the track is painted on the slider.
  841. * @see #getPaintTrack
  842. * @beaninfo
  843. * bound: true
  844. * attribute: visualUpdate true
  845. * description: If true, the track is painted on the slider.
  846. */
  847. public void setPaintTrack(boolean b) {
  848. boolean oldValue = paintTrack;
  849. paintTrack = b;
  850. firePropertyChange("paintTrack", oldValue, paintTrack);
  851. if (paintTrack != oldValue) {
  852. repaint();
  853. }
  854. }
  855. /**
  856. * Tells if labels are to be painted.
  857. * @return true if labels are painted, else false
  858. * @see #setPaintLabels
  859. */
  860. public boolean getPaintLabels() {
  861. return paintLabels;
  862. }
  863. /**
  864. * Determines whether labels are painted on the slider.
  865. * @see #getPaintLabels
  866. * @beaninfo
  867. * bound: true
  868. * attribute: visualUpdate true
  869. * description: If true labels are painted on the slider.
  870. */
  871. public void setPaintLabels(boolean b) {
  872. boolean oldValue = paintLabels;
  873. paintLabels = b;
  874. if ( labelTable == null && getMajorTickSpacing() > 0 ) {
  875. setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
  876. }
  877. firePropertyChange("paintLabels", oldValue, paintLabels);
  878. if (paintLabels != oldValue) {
  879. revalidate();
  880. repaint();
  881. }
  882. }
  883. /**
  884. * See readObject() and writeObject() in JComponent for more
  885. * information about serialization in Swing.
  886. */
  887. private void writeObject(ObjectOutputStream s) throws IOException {
  888. s.defaultWriteObject();
  889. if (getUIClassID().equals(uiClassID)) {
  890. byte count = JComponent.getWriteObjCounter(this);
  891. JComponent.setWriteObjCounter(this, --count);
  892. if (count == 0 && ui != null) {
  893. ui.installUI(this);
  894. }
  895. }
  896. }
  897. /**
  898. * Returns a string representation of this JSlider. This method
  899. * is intended to be used only for debugging purposes, and the
  900. * content and format of the returned string may vary between
  901. * implementations. The returned string may be empty but may not
  902. * be <code>null</code>.
  903. *
  904. * @return a string representation of this JSlider.
  905. */
  906. protected String paramString() {
  907. String paintTicksString = (paintTicks ?
  908. "true" : "false");
  909. String paintTrackString = (paintTrack ?
  910. "true" : "false");
  911. String paintLabelsString = (paintLabels ?
  912. "true" : "false");
  913. String isInvertedString = (isInverted ?
  914. "true" : "false");
  915. String snapToTicksString = (snapToTicks ?
  916. "true" : "false");
  917. String snapToValueString = (snapToValue ?
  918. "true" : "false");
  919. String orientationString = (orientation == HORIZONTAL ?
  920. "HORIZONTAL" : "VERTICAL");
  921. return super.paramString() +
  922. ",isInverted=" + isInvertedString +
  923. ",majorTickSpacing=" + majorTickSpacing +
  924. ",minorTickSpacing=" + minorTickSpacing +
  925. ",orientation=" + orientationString +
  926. ",paintLabels=" + paintLabelsString +
  927. ",paintTicks=" + paintTicksString +
  928. ",paintTrack=" + paintTrackString +
  929. ",snapToTicks=" + snapToTicksString +
  930. ",snapToValue=" + snapToValueString;
  931. }
  932. /////////////////
  933. // Accessibility support
  934. ////////////////
  935. /**
  936. * Gets the AccessibleContext associated with this JSlider.
  937. * For sliders, the AccessibleContext takes the form of an
  938. * AccessibleJSlider.
  939. * A new AccessibleJSlider instance is created if necessary.
  940. *
  941. * @return an AccessibleJSlider that serves as the
  942. * AccessibleContext of this JSlider
  943. */
  944. public AccessibleContext getAccessibleContext() {
  945. if (accessibleContext == null) {
  946. accessibleContext = new AccessibleJSlider();
  947. }
  948. return accessibleContext;
  949. }
  950. /**
  951. * This class implements accessibility support for the
  952. * <code>JSlider</code> class. It provides an implementation of the
  953. * Java Accessibility API appropriate to slider user-interface elements.
  954. * <p>
  955. * <strong>Warning:</strong>
  956. * Serialized objects of this class will not be compatible with
  957. * future Swing releases. The current serialization support is
  958. * appropriate for short term storage or RMI between applications running
  959. * the same version of Swing. As of 1.4, support for long term storage
  960. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  961. * has been added to the <code>java.beans</code> package.
  962. * Please see {@link java.beans.XMLEncoder}.
  963. */
  964. protected class AccessibleJSlider extends AccessibleJComponent
  965. implements AccessibleValue {
  966. /**
  967. * Get the state set of this object.
  968. *
  969. * @return an instance of AccessibleState containing the current state
  970. * of the object
  971. * @see AccessibleState
  972. */
  973. public AccessibleStateSet getAccessibleStateSet() {
  974. AccessibleStateSet states = super.getAccessibleStateSet();
  975. if (getValueIsAdjusting()) {
  976. states.add(AccessibleState.BUSY);
  977. }
  978. if (getOrientation() == VERTICAL) {
  979. states.add(AccessibleState.VERTICAL);
  980. }
  981. else {
  982. states.add(AccessibleState.HORIZONTAL);
  983. }
  984. return states;
  985. }
  986. /**
  987. * Get the role of this object.
  988. *
  989. * @return an instance of AccessibleRole describing the role of the object
  990. */
  991. public AccessibleRole getAccessibleRole() {
  992. return AccessibleRole.SLIDER;
  993. }
  994. /**
  995. * Get the AccessibleValue associated with this object. In the
  996. * implementation of the Java Accessibility API for this class,
  997. * return this object, which is responsible for implementing the
  998. * AccessibleValue interface on behalf of itself.
  999. *
  1000. * @return this object
  1001. */
  1002. public AccessibleValue getAccessibleValue() {
  1003. return this;
  1004. }
  1005. /**
  1006. * Get the accessible value of this object.
  1007. *
  1008. * @return The current value of this object.
  1009. */
  1010. public Number getCurrentAccessibleValue() {
  1011. return new Integer(getValue());
  1012. }
  1013. /**
  1014. * Set the value of this object as a Number.
  1015. *
  1016. * @return True if the value was set.
  1017. */
  1018. public boolean setCurrentAccessibleValue(Number n) {
  1019. // TIGER - 4422535
  1020. if (n == null) {
  1021. return false;
  1022. }
  1023. setValue(n.intValue());
  1024. return true;
  1025. }
  1026. /**
  1027. * Get the minimum accessible value of this object.
  1028. *
  1029. * @return The minimum value of this object.
  1030. */
  1031. public Number getMinimumAccessibleValue() {
  1032. return new Integer(getMinimum());
  1033. }
  1034. /**
  1035. * Get the maximum accessible value of this object.
  1036. *
  1037. * @return The maximum value of this object.
  1038. */
  1039. public Number getMaximumAccessibleValue() {
  1040. // TIGER - 4422362
  1041. BoundedRangeModel model = JSlider.this.getModel();
  1042. return new Integer(model.getMaximum() - model.getExtent());
  1043. }
  1044. } // AccessibleJSlider
  1045. }