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