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, ? extends 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. 162 * 756 /** 757 * {@inheritDoc} 758 * 759 * @since 1.6 760 */ 761 public void setFont(Font font) { 762 super.setFont(font); 763 updateLabelSizes(); 764 } 765 766 /** 767 * {@inheritDoc} 768 * @since 1.7 769 */ 770 public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { 771 if (!isShowing()) { 772 return false; 773 } 774 775 // Check that there is a label with such image 776 Enumeration<? extends JComponent> elements = labelTable.elements(); 777 778 while (elements.hasMoreElements()) { 779 JComponent component = elements.nextElement(); 780 781 if (component instanceof JLabel) { 782 JLabel label = (JLabel) component; 783 784 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) || 785 SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) { 786 return super.imageUpdate(img, infoflags, x, y, w, h); 787 } 788 } 789 } 790 791 return false; 792 } 793 794 /** 795 * Returns the dictionary of what labels to draw at which values. 796 * 797 * @return the <code>Dictionary</code> containing labels and 798 * where to draw them 799 */ 800 public Dictionary<Integer, ? extends JComponent> getLabelTable() { 801 /* 802 if ( labelTable == null && getMajorTickSpacing() > 0 ) { 803 setLabelTable( createStandardLabels( getMajorTickSpacing() ) ); 804 } 805 */ 806 return labelTable; 807 } 808 809 810 /** 811 * Used to specify what label will be drawn at any given value. 812 * The key-value pairs are of this format: 813 * <code>{ Integer value, java.swing.JComponent label }</code>. 814 * <p> 815 * An easy way to generate a standard table of value labels is by using the 816 * {@code createStandardLabels} method. 817 * <p> 818 * Once the labels have been set, this method calls {@link #updateLabelUIs}. 819 * Note that the labels are only painted if the {@code paintLabels} 820 * property is {@code true}. 821 * 822 * @param labels new {@code Dictionary} of labels, or {@code null} to 823 * remove all labels 824 * @see #createStandardLabels(int) 825 * @see #getLabelTable 826 * @see #setPaintLabels 827 * @beaninfo 828 * hidden: true 829 * bound: true 830 * attribute: visualUpdate true 831 * description: Specifies what labels will be drawn for any given value. 832 */ 833 public void setLabelTable( Dictionary<Integer, ? extends JComponent> labels ) { 834 Dictionary<Integer, ? extends JComponent> oldTable = labelTable; 835 labelTable = labels; 836 updateLabelUIs(); 837 firePropertyChange("labelTable", oldTable, labelTable ); 838 if (labels != oldTable) { 839 revalidate(); 840 repaint(); 841 } 842 } 843 844 845 /** 846 * Updates the UIs for the labels in the label table by calling 847 * {@code updateUI} on each label. The UIs are updated from 848 * the current look and feel. The labels are also set to their 849 * preferred size. 850 * 851 * @see #setLabelTable 852 * @see JComponent#updateUI 853 */ 854 protected void updateLabelUIs() { 855 Dictionary<Integer, ? extends JComponent> labelTable = getLabelTable(); 856 857 if (labelTable == null) { 858 return; 859 } 860 Enumeration<Integer> labels = labelTable.keys(); 861 while ( labels.hasMoreElements() ) { 862 JComponent component = labelTable.get(labels.nextElement()); 863 component.updateUI(); 864 component.setSize(component.getPreferredSize()); 865 } 866 } 867 868 private void updateLabelSizes() { 869 Dictionary<Integer, ? extends JComponent> labelTable = getLabelTable(); 870 if (labelTable != null) { 871 Enumeration<? extends JComponent> labels = labelTable.elements(); 872 while (labels.hasMoreElements()) { 873 JComponent component = labels.nextElement(); 874 component.setSize(component.getPreferredSize()); 875 } 876 } 877 } 878 879 880 /** 881 * Creates a {@code Hashtable} of numerical text labels, starting at the 882 * slider minimum, and using the increment specified. 883 * For example, if you call <code>createStandardLabels( 10 )</code> 884 * and the slider minimum is zero, 885 * then labels will be created for the values 0, 10, 20, 30, and so on. 886 * <p> 887 * For the labels to be drawn on the slider, the returned {@code Hashtable} 888 * must be passed into {@code setLabelTable}, and {@code setPaintLabels} 889 * must be set to {@code true}. 890 * <p> 891 * For further details on the makeup of the returned {@code Hashtable}, see 892 * the {@code setLabelTable} documentation. 893 * 965 return fg; 966 } 967 } 968 969 public SmartHashtable( int increment, int start ) { 970 super(); 971 this.increment = increment; 972 this.start = start; 973 startAtMin = start == getMinimum(); 974 createLabels(); 975 } 976 977 public void propertyChange( PropertyChangeEvent e ) { 978 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) { 979 start = getMinimum(); 980 } 981 982 if ( e.getPropertyName().equals( "minimum" ) || 983 e.getPropertyName().equals( "maximum" ) ) { 984 985 Enumeration<Integer> keys = getLabelTable().keys(); 986 Hashtable<Integer, JComponent> hashtable = new Hashtable<>(); 987 988 // Save the labels that were added by the developer 989 while ( keys.hasMoreElements() ) { 990 Integer key = keys.nextElement(); 991 JComponent value = labelTable.get(key); 992 if ( !(value instanceof LabelUIResource) ) { 993 hashtable.put( key, value ); 994 } 995 } 996 997 clear(); 998 createLabels(); 999 1000 // Add the saved labels 1001 keys = hashtable.keys(); 1002 while ( keys.hasMoreElements() ) { 1003 Integer key = keys.nextElement(); 1004 put( key, hashtable.get( key ) ); 1005 } 1006 1007 ((JSlider)e.getSource()).setLabelTable( this ); 1008 } 1009 } 1010 1011 void createLabels() { 1012 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) { 1013 put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) ); 1014 } 1015 } 1016 } 1017 1018 SmartHashtable table = new SmartHashtable( increment, start ); 1019 1020 Dictionary<Integer, ? extends JComponent> labelTable = getLabelTable(); 1021 1022 if (labelTable != null && (labelTable instanceof PropertyChangeListener)) { 1023 removePropertyChangeListener((PropertyChangeListener) labelTable); 1024 } 1025 1026 addPropertyChangeListener( table ); 1027 1028 return table; 1029 } 1030 1031 1032 /** 1033 * Returns true if the value-range shown for the slider is reversed, 1034 * 1035 * @return true if the slider values are reversed from their normal order 1036 * @see #setInverted 1037 */ 1038 public boolean getInverted() { 1039 return isInverted; 1040 } | 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 @SuppressWarnings("rawtypes") 142 private Dictionary labelTable; 143 // For better source compatibility, the labelTable field and 144 // associated getter and setter methods are being left as raw 145 // types. 146 147 /** 148 * The changeListener (no suffix) is the listener we add to the 149 * slider's model. This listener is initialized to the 150 * {@code ChangeListener} returned from {@code createChangeListener}, 151 * which by default just forwards events 152 * to {@code ChangeListener}s (if any) added directly to the slider. 153 * 154 * @see #addChangeListener 155 * @see #createChangeListener 156 */ 157 protected ChangeListener changeListener = createChangeListener(); 158 159 160 /** 161 * Only one <code>ChangeEvent</code> is needed per slider instance since the 162 * event's only (read-only) state is the source property. The source 163 * of events generated here is always "this". The event is lazily 164 * created the first time that an event notification is fired. 165 * 759 /** 760 * {@inheritDoc} 761 * 762 * @since 1.6 763 */ 764 public void setFont(Font font) { 765 super.setFont(font); 766 updateLabelSizes(); 767 } 768 769 /** 770 * {@inheritDoc} 771 * @since 1.7 772 */ 773 public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { 774 if (!isShowing()) { 775 return false; 776 } 777 778 // Check that there is a label with such image 779 Enumeration<?> elements = labelTable.elements(); 780 781 while (elements.hasMoreElements()) { 782 Component component = (Component) elements.nextElement(); 783 784 if (component instanceof JLabel) { 785 JLabel label = (JLabel) component; 786 787 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) || 788 SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) { 789 return super.imageUpdate(img, infoflags, x, y, w, h); 790 } 791 } 792 } 793 794 return false; 795 } 796 797 /** 798 * Returns the dictionary of what labels to draw at which values. 799 * 800 * @return the <code>Dictionary</code> containing labels and 801 * where to draw them 802 */ 803 @SuppressWarnings("rawtypes") 804 public Dictionary getLabelTable() { 805 /* 806 if ( labelTable == null && getMajorTickSpacing() > 0 ) { 807 setLabelTable( createStandardLabels( getMajorTickSpacing() ) ); 808 } 809 */ 810 return labelTable; 811 } 812 813 814 /** 815 * Used to specify what label will be drawn at any given value. 816 * The key-value pairs are of this format: 817 * <code>{ Integer value, java.swing.JComponent label }</code>. 818 * <p> 819 * An easy way to generate a standard table of value labels is by using the 820 * {@code createStandardLabels} method. 821 * <p> 822 * Once the labels have been set, this method calls {@link #updateLabelUIs}. 823 * Note that the labels are only painted if the {@code paintLabels} 824 * property is {@code true}. 825 * 826 * @param labels new {@code Dictionary} of labels, or {@code null} to 827 * remove all labels 828 * @see #createStandardLabels(int) 829 * @see #getLabelTable 830 * @see #setPaintLabels 831 * @beaninfo 832 * hidden: true 833 * bound: true 834 * attribute: visualUpdate true 835 * description: Specifies what labels will be drawn for any given value. 836 */ 837 @SuppressWarnings("rawtypes") 838 public void setLabelTable( Dictionary labels ) { 839 Dictionary oldTable = labelTable; 840 labelTable = labels; 841 updateLabelUIs(); 842 firePropertyChange("labelTable", oldTable, labelTable ); 843 if (labels != oldTable) { 844 revalidate(); 845 repaint(); 846 } 847 } 848 849 850 /** 851 * Updates the UIs for the labels in the label table by calling 852 * {@code updateUI} on each label. The UIs are updated from 853 * the current look and feel. The labels are also set to their 854 * preferred size. 855 * 856 * @see #setLabelTable 857 * @see JComponent#updateUI 858 */ 859 protected void updateLabelUIs() { 860 @SuppressWarnings("rawtypes") 861 Dictionary labelTable = getLabelTable(); 862 863 if (labelTable == null) { 864 return; 865 } 866 Enumeration<?> labels = labelTable.keys(); 867 while ( labels.hasMoreElements() ) { 868 JComponent component = (JComponent) labelTable.get(labels.nextElement()); 869 component.updateUI(); 870 component.setSize(component.getPreferredSize()); 871 } 872 } 873 874 private void updateLabelSizes() { 875 @SuppressWarnings("rawtypes") 876 Dictionary labelTable = getLabelTable(); 877 if (labelTable != null) { 878 Enumeration<?> labels = labelTable.elements(); 879 while (labels.hasMoreElements()) { 880 JComponent component = (JComponent) labels.nextElement(); 881 component.setSize(component.getPreferredSize()); 882 } 883 } 884 } 885 886 887 /** 888 * Creates a {@code Hashtable} of numerical text labels, starting at the 889 * slider minimum, and using the increment specified. 890 * For example, if you call <code>createStandardLabels( 10 )</code> 891 * and the slider minimum is zero, 892 * then labels will be created for the values 0, 10, 20, 30, and so on. 893 * <p> 894 * For the labels to be drawn on the slider, the returned {@code Hashtable} 895 * must be passed into {@code setLabelTable}, and {@code setPaintLabels} 896 * must be set to {@code true}. 897 * <p> 898 * For further details on the makeup of the returned {@code Hashtable}, see 899 * the {@code setLabelTable} documentation. 900 * 972 return fg; 973 } 974 } 975 976 public SmartHashtable( int increment, int start ) { 977 super(); 978 this.increment = increment; 979 this.start = start; 980 startAtMin = start == getMinimum(); 981 createLabels(); 982 } 983 984 public void propertyChange( PropertyChangeEvent e ) { 985 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) { 986 start = getMinimum(); 987 } 988 989 if ( e.getPropertyName().equals( "minimum" ) || 990 e.getPropertyName().equals( "maximum" ) ) { 991 992 Enumeration<?> keys = getLabelTable().keys(); 993 Hashtable<Integer, JComponent> hashtable = new Hashtable<>(); 994 995 // Save the labels that were added by the developer 996 while ( keys.hasMoreElements() ) { 997 Integer key = (Integer) keys.nextElement(); 998 JComponent value = (JComponent) labelTable.get(key); 999 if ( !(value instanceof LabelUIResource) ) { 1000 hashtable.put( key, value ); 1001 } 1002 } 1003 1004 clear(); 1005 createLabels(); 1006 1007 // Add the saved labels 1008 keys = hashtable.keys(); 1009 while ( keys.hasMoreElements() ) { 1010 Integer key = (Integer) keys.nextElement(); 1011 put( key, hashtable.get( key ) ); 1012 } 1013 1014 ((JSlider)e.getSource()).setLabelTable( this ); 1015 } 1016 } 1017 1018 void createLabels() { 1019 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) { 1020 put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) ); 1021 } 1022 } 1023 } 1024 1025 SmartHashtable table = new SmartHashtable( increment, start ); 1026 1027 @SuppressWarnings("rawtypes") 1028 Dictionary labelTable = getLabelTable(); 1029 1030 if (labelTable != null && (labelTable instanceof PropertyChangeListener)) { 1031 removePropertyChangeListener((PropertyChangeListener) labelTable); 1032 } 1033 1034 addPropertyChangeListener( table ); 1035 1036 return table; 1037 } 1038 1039 1040 /** 1041 * Returns true if the value-range shown for the slider is reversed, 1042 * 1043 * @return true if the slider values are reversed from their normal order 1044 * @see #setInverted 1045 */ 1046 public boolean getInverted() { 1047 return isInverted; 1048 } |