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