121
122 /**
123 * If true, the knob (and the data value it represents)
124 * resolve to the closest slider value next to where the user
125 * positioned the knob.
126 */
127 boolean snapToValue = true;
128
129 /**
130 * Whether the slider is horizontal or vertical
131 * The default is horizontal.
132 *
133 * @see #setOrientation
134 */
135 protected int orientation;
136
137
138 /**
139 * {@code Dictionary} of what labels to draw at which values
140 */
141 private Dictionary labelTable;
142
143
144 /**
145 * The changeListener (no suffix) is the listener we add to the
146 * slider's model. This listener is initialized to the
147 * {@code ChangeListener} returned from {@code createChangeListener},
148 * which by default just forwards events
149 * to {@code ChangeListener}s (if any) added directly to the slider.
150 *
151 * @see #addChangeListener
152 * @see #createChangeListener
153 */
154 protected ChangeListener changeListener = createChangeListener();
155
156
157 /**
158 * Only one <code>ChangeEvent</code> is needed per slider instance since the
159 * event's only (read-only) state is the source property. The source
160 * of events generated here is always "this". The event is lazily
161 * created the first time that an event notification is fired.
752 /**
753 * {@inheritDoc}
754 *
755 * @since 1.6
756 */
757 public void setFont(Font font) {
758 super.setFont(font);
759 updateLabelSizes();
760 }
761
762 /**
763 * {@inheritDoc}
764 * @since 1.7
765 */
766 public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
767 if (!isShowing()) {
768 return false;
769 }
770
771 // Check that there is a label with such image
772 Enumeration elements = labelTable.elements();
773
774 while (elements.hasMoreElements()) {
775 Component component = (Component) elements.nextElement();
776
777 if (component instanceof JLabel) {
778 JLabel label = (JLabel) component;
779
780 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) ||
781 SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) {
782 return super.imageUpdate(img, infoflags, x, y, w, h);
783 }
784 }
785 }
786
787 return false;
788 }
789
790 /**
791 * Returns the dictionary of what labels to draw at which values.
792 *
793 * @return the <code>Dictionary</code> containing labels and
794 * where to draw them
795 */
796 public Dictionary getLabelTable() {
797 /*
798 if ( labelTable == null && getMajorTickSpacing() > 0 ) {
799 setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
800 }
801 */
802 return labelTable;
803 }
804
805
806 /**
807 * Used to specify what label will be drawn at any given value.
808 * The key-value pairs are of this format:
809 * <code>{ Integer value, java.swing.JComponent label }</code>.
810 * <p>
811 * An easy way to generate a standard table of value labels is by using the
812 * {@code createStandardLabels} method.
813 * <p>
814 * Once the labels have been set, this method calls {@link #updateLabelUIs}.
815 * Note that the labels are only painted if the {@code paintLabels}
816 * property is {@code true}.
817 *
818 * @param labels new {@code Dictionary} of labels, or {@code null} to
819 * remove all labels
820 * @see #createStandardLabels(int)
821 * @see #getLabelTable
822 * @see #setPaintLabels
823 * @beaninfo
824 * hidden: true
825 * bound: true
826 * attribute: visualUpdate true
827 * description: Specifies what labels will be drawn for any given value.
828 */
829 public void setLabelTable( Dictionary labels ) {
830 Dictionary oldTable = labelTable;
831 labelTable = labels;
832 updateLabelUIs();
833 firePropertyChange("labelTable", oldTable, labelTable );
834 if (labels != oldTable) {
835 revalidate();
836 repaint();
837 }
838 }
839
840
841 /**
842 * Updates the UIs for the labels in the label table by calling
843 * {@code updateUI} on each label. The UIs are updated from
844 * the current look and feel. The labels are also set to their
845 * preferred size.
846 *
847 * @see #setLabelTable
848 * @see JComponent#updateUI
849 */
850 protected void updateLabelUIs() {
851 Dictionary labelTable = getLabelTable();
852
853 if (labelTable == null) {
854 return;
855 }
856 Enumeration labels = labelTable.keys();
857 while ( labels.hasMoreElements() ) {
858 JComponent component = (JComponent) labelTable.get(labels.nextElement());
859 component.updateUI();
860 component.setSize(component.getPreferredSize());
861 }
862 }
863
864 private void updateLabelSizes() {
865 Dictionary labelTable = getLabelTable();
866 if (labelTable != null) {
867 Enumeration labels = labelTable.elements();
868 while (labels.hasMoreElements()) {
869 JComponent component = (JComponent) labels.nextElement();
870 component.setSize(component.getPreferredSize());
871 }
872 }
873 }
874
875
876 /**
877 * Creates a {@code Hashtable} of numerical text labels, starting at the
878 * slider minimum, and using the increment specified.
879 * For example, if you call <code>createStandardLabels( 10 )</code>
880 * and the slider minimum is zero,
881 * then labels will be created for the values 0, 10, 20, 30, and so on.
882 * <p>
883 * For the labels to be drawn on the slider, the returned {@code Hashtable}
884 * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
885 * must be set to {@code true}.
886 * <p>
887 * For further details on the makeup of the returned {@code Hashtable}, see
888 * the {@code setLabelTable} documentation.
889 *
890 * @param increment distance between labels in the generated hashtable
891 * @return a new {@code Hashtable} of labels
892 * @see #setLabelTable
893 * @see #setPaintLabels
894 * @throws IllegalArgumentException if {@code increment} is less than or
895 * equal to zero
896 */
897 public Hashtable createStandardLabels( int increment ) {
898 return createStandardLabels( increment, getMinimum() );
899 }
900
901
902 /**
903 * Creates a {@code Hashtable} of numerical text labels, starting at the
904 * starting point specified, and using the increment specified.
905 * For example, if you call
906 * <code>createStandardLabels( 10, 2 )</code>,
907 * then labels will be created for the values 2, 12, 22, 32, and so on.
908 * <p>
909 * For the labels to be drawn on the slider, the returned {@code Hashtable}
910 * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
911 * must be set to {@code true}.
912 * <p>
913 * For further details on the makeup of the returned {@code Hashtable}, see
914 * the {@code setLabelTable} documentation.
915 *
916 * @param increment distance between labels in the generated hashtable
917 * @param start value at which the labels will begin
918 * @return a new {@code Hashtable} of labels
919 * @see #setLabelTable
920 * @see #setPaintLabels
921 * @exception IllegalArgumentException if {@code start} is
922 * out of range, or if {@code increment} is less than or equal
923 * to zero
924 */
925 public Hashtable createStandardLabels( int increment, int start ) {
926 if ( start > getMaximum() || start < getMinimum() ) {
927 throw new IllegalArgumentException( "Slider label start point out of range." );
928 }
929
930 if ( increment <= 0 ) {
931 throw new IllegalArgumentException( "Label incremement must be > 0" );
932 }
933
934 class SmartHashtable extends Hashtable<Object, Object> implements PropertyChangeListener {
935 int increment = 0;
936 int start = 0;
937 boolean startAtMin = false;
938
939 class LabelUIResource extends JLabel implements UIResource {
940 public LabelUIResource( String text, int alignment ) {
941 super( text, alignment );
942 setName("Slider.label");
943 }
944
945 public Font getFont() {
946 Font font = super.getFont();
947 if (font != null && !(font instanceof UIResource)) {
948 return font;
949 }
950 return JSlider.this.getFont();
951 }
952
953 public Color getForeground() {
954 Color fg = super.getForeground();
961 return fg;
962 }
963 }
964
965 public SmartHashtable( int increment, int start ) {
966 super();
967 this.increment = increment;
968 this.start = start;
969 startAtMin = start == getMinimum();
970 createLabels();
971 }
972
973 public void propertyChange( PropertyChangeEvent e ) {
974 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) {
975 start = getMinimum();
976 }
977
978 if ( e.getPropertyName().equals( "minimum" ) ||
979 e.getPropertyName().equals( "maximum" ) ) {
980
981 Enumeration keys = getLabelTable().keys();
982 Hashtable<Object, Object> hashtable = new Hashtable<Object, Object>();
983
984 // Save the labels that were added by the developer
985 while ( keys.hasMoreElements() ) {
986 Object key = keys.nextElement();
987 Object value = labelTable.get(key);
988 if ( !(value instanceof LabelUIResource) ) {
989 hashtable.put( key, value );
990 }
991 }
992
993 clear();
994 createLabels();
995
996 // Add the saved labels
997 keys = hashtable.keys();
998 while ( keys.hasMoreElements() ) {
999 Object key = keys.nextElement();
1000 put( key, hashtable.get( key ) );
1001 }
1002
1003 ((JSlider)e.getSource()).setLabelTable( this );
1004 }
1005 }
1006
1007 void createLabels() {
1008 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
1009 put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) );
1010 }
1011 }
1012 }
1013
1014 SmartHashtable table = new SmartHashtable( increment, start );
1015
1016 Dictionary labelTable = getLabelTable();
1017
1018 if (labelTable != null && (labelTable instanceof PropertyChangeListener)) {
1019 removePropertyChangeListener((PropertyChangeListener) labelTable);
1020 }
1021
1022 addPropertyChangeListener( table );
1023
1024 return table;
1025 }
1026
1027
1028 /**
1029 * Returns true if the value-range shown for the slider is reversed,
1030 *
1031 * @return true if the slider values are reversed from their normal order
1032 * @see #setInverted
1033 */
1034 public boolean getInverted() {
1035 return isInverted;
1036 }
|
121
122 /**
123 * If true, the knob (and the data value it represents)
124 * resolve to the closest slider value next to where the user
125 * positioned the knob.
126 */
127 boolean snapToValue = true;
128
129 /**
130 * Whether the slider is horizontal or vertical
131 * The default is horizontal.
132 *
133 * @see #setOrientation
134 */
135 protected int orientation;
136
137
138 /**
139 * {@code Dictionary} of what labels to draw at which values
140 */
141 private Dictionary<Integer, JComponent> labelTable;
142
143
144 /**
145 * The changeListener (no suffix) is the listener we add to the
146 * slider's model. This listener is initialized to the
147 * {@code ChangeListener} returned from {@code createChangeListener},
148 * which by default just forwards events
149 * to {@code ChangeListener}s (if any) added directly to the slider.
150 *
151 * @see #addChangeListener
152 * @see #createChangeListener
153 */
154 protected ChangeListener changeListener = createChangeListener();
155
156
157 /**
158 * Only one <code>ChangeEvent</code> is needed per slider instance since the
159 * event's only (read-only) state is the source property. The source
160 * of events generated here is always "this". The event is lazily
161 * created the first time that an event notification is fired.
752 /**
753 * {@inheritDoc}
754 *
755 * @since 1.6
756 */
757 public void setFont(Font font) {
758 super.setFont(font);
759 updateLabelSizes();
760 }
761
762 /**
763 * {@inheritDoc}
764 * @since 1.7
765 */
766 public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
767 if (!isShowing()) {
768 return false;
769 }
770
771 // Check that there is a label with such image
772 Enumeration<JComponent> elements = labelTable.elements();
773
774 while (elements.hasMoreElements()) {
775 JComponent component = elements.nextElement();
776
777 if (component instanceof JLabel) {
778 JLabel label = (JLabel) component;
779
780 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) ||
781 SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) {
782 return super.imageUpdate(img, infoflags, x, y, w, h);
783 }
784 }
785 }
786
787 return false;
788 }
789
790 /**
791 * Returns the dictionary of what labels to draw at which values.
792 *
793 * @return the <code>Dictionary</code> containing labels and
794 * where to draw them
795 */
796 public Dictionary<Integer, JComponent> getLabelTable() {
797 /*
798 if ( labelTable == null && getMajorTickSpacing() > 0 ) {
799 setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
800 }
801 */
802 return labelTable;
803 }
804
805
806 /**
807 * Used to specify what label will be drawn at any given value.
808 * The key-value pairs are of this format:
809 * <code>{ Integer value, java.swing.JComponent label }</code>.
810 * <p>
811 * An easy way to generate a standard table of value labels is by using the
812 * {@code createStandardLabels} method.
813 * <p>
814 * Once the labels have been set, this method calls {@link #updateLabelUIs}.
815 * Note that the labels are only painted if the {@code paintLabels}
816 * property is {@code true}.
817 *
818 * @param labels new {@code Dictionary} of labels, or {@code null} to
819 * remove all labels
820 * @see #createStandardLabels(int)
821 * @see #getLabelTable
822 * @see #setPaintLabels
823 * @beaninfo
824 * hidden: true
825 * bound: true
826 * attribute: visualUpdate true
827 * description: Specifies what labels will be drawn for any given value.
828 */
829 public void setLabelTable( Dictionary<Integer, JComponent> labels ) {
830 Dictionary<Integer, JComponent> oldTable = labelTable;
831 labelTable = labels;
832 updateLabelUIs();
833 firePropertyChange("labelTable", oldTable, labelTable );
834 if (labels != oldTable) {
835 revalidate();
836 repaint();
837 }
838 }
839
840
841 /**
842 * Updates the UIs for the labels in the label table by calling
843 * {@code updateUI} on each label. The UIs are updated from
844 * the current look and feel. The labels are also set to their
845 * preferred size.
846 *
847 * @see #setLabelTable
848 * @see JComponent#updateUI
849 */
850 protected void updateLabelUIs() {
851 Dictionary<Integer, JComponent> labelTable = getLabelTable();
852
853 if (labelTable == null) {
854 return;
855 }
856 Enumeration<Integer> labels = labelTable.keys();
857 while ( labels.hasMoreElements() ) {
858 JComponent component = labelTable.get(labels.nextElement());
859 component.updateUI();
860 component.setSize(component.getPreferredSize());
861 }
862 }
863
864 private void updateLabelSizes() {
865 Dictionary<Integer, JComponent> labelTable = getLabelTable();
866 if (labelTable != null) {
867 Enumeration<JComponent> labels = labelTable.elements();
868 while (labels.hasMoreElements()) {
869 JComponent component = labels.nextElement();
870 component.setSize(component.getPreferredSize());
871 }
872 }
873 }
874
875
876 /**
877 * Creates a {@code Hashtable} of numerical text labels, starting at the
878 * slider minimum, and using the increment specified.
879 * For example, if you call <code>createStandardLabels( 10 )</code>
880 * and the slider minimum is zero,
881 * then labels will be created for the values 0, 10, 20, 30, and so on.
882 * <p>
883 * For the labels to be drawn on the slider, the returned {@code Hashtable}
884 * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
885 * must be set to {@code true}.
886 * <p>
887 * For further details on the makeup of the returned {@code Hashtable}, see
888 * the {@code setLabelTable} documentation.
889 *
890 * @param increment distance between labels in the generated hashtable
891 * @return a new {@code Hashtable} of labels
892 * @see #setLabelTable
893 * @see #setPaintLabels
894 * @throws IllegalArgumentException if {@code increment} is less than or
895 * equal to zero
896 */
897 public Hashtable<Integer, JComponent> createStandardLabels( int increment ) {
898 return createStandardLabels( increment, getMinimum() );
899 }
900
901
902 /**
903 * Creates a {@code Hashtable} of numerical text labels, starting at the
904 * starting point specified, and using the increment specified.
905 * For example, if you call
906 * <code>createStandardLabels( 10, 2 )</code>,
907 * then labels will be created for the values 2, 12, 22, 32, and so on.
908 * <p>
909 * For the labels to be drawn on the slider, the returned {@code Hashtable}
910 * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
911 * must be set to {@code true}.
912 * <p>
913 * For further details on the makeup of the returned {@code Hashtable}, see
914 * the {@code setLabelTable} documentation.
915 *
916 * @param increment distance between labels in the generated hashtable
917 * @param start value at which the labels will begin
918 * @return a new {@code Hashtable} of labels
919 * @see #setLabelTable
920 * @see #setPaintLabels
921 * @exception IllegalArgumentException if {@code start} is
922 * out of range, or if {@code increment} is less than or equal
923 * to zero
924 */
925 public Hashtable<Integer, JComponent> createStandardLabels( int increment, int start ) {
926 if ( start > getMaximum() || start < getMinimum() ) {
927 throw new IllegalArgumentException( "Slider label start point out of range." );
928 }
929
930 if ( increment <= 0 ) {
931 throw new IllegalArgumentException( "Label incremement must be > 0" );
932 }
933
934 class SmartHashtable extends Hashtable<Integer, JComponent> implements PropertyChangeListener {
935 int increment = 0;
936 int start = 0;
937 boolean startAtMin = false;
938
939 class LabelUIResource extends JLabel implements UIResource {
940 public LabelUIResource( String text, int alignment ) {
941 super( text, alignment );
942 setName("Slider.label");
943 }
944
945 public Font getFont() {
946 Font font = super.getFont();
947 if (font != null && !(font instanceof UIResource)) {
948 return font;
949 }
950 return JSlider.this.getFont();
951 }
952
953 public Color getForeground() {
954 Color fg = super.getForeground();
961 return fg;
962 }
963 }
964
965 public SmartHashtable( int increment, int start ) {
966 super();
967 this.increment = increment;
968 this.start = start;
969 startAtMin = start == getMinimum();
970 createLabels();
971 }
972
973 public void propertyChange( PropertyChangeEvent e ) {
974 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) {
975 start = getMinimum();
976 }
977
978 if ( e.getPropertyName().equals( "minimum" ) ||
979 e.getPropertyName().equals( "maximum" ) ) {
980
981 Enumeration<Integer> keys = getLabelTable().keys();
982 Hashtable<Integer, JComponent> hashtable = new Hashtable<>();
983
984 // Save the labels that were added by the developer
985 while ( keys.hasMoreElements() ) {
986 Integer key = keys.nextElement();
987 JComponent value = labelTable.get(key);
988 if ( !(value instanceof LabelUIResource) ) {
989 hashtable.put( key, value );
990 }
991 }
992
993 clear();
994 createLabels();
995
996 // Add the saved labels
997 keys = hashtable.keys();
998 while ( keys.hasMoreElements() ) {
999 Integer key = keys.nextElement();
1000 put( key, hashtable.get( key ) );
1001 }
1002
1003 ((JSlider)e.getSource()).setLabelTable( this );
1004 }
1005 }
1006
1007 void createLabels() {
1008 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
1009 put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) );
1010 }
1011 }
1012 }
1013
1014 SmartHashtable table = new SmartHashtable( increment, start );
1015
1016 Dictionary<Integer, JComponent> labelTable = getLabelTable();
1017
1018 if (labelTable != null && (labelTable instanceof PropertyChangeListener)) {
1019 removePropertyChangeListener((PropertyChangeListener) labelTable);
1020 }
1021
1022 addPropertyChangeListener( table );
1023
1024 return table;
1025 }
1026
1027
1028 /**
1029 * Returns true if the value-range shown for the slider is reversed,
1030 *
1031 * @return true if the slider values are reversed from their normal order
1032 * @see #setInverted
1033 */
1034 public boolean getInverted() {
1035 return isInverted;
1036 }
|