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