2011-05-27 68 views
2

一个问题,下面是代码,我希望这将增加,只有整数输入有效期为文本字段约束:有关的NumberFormatter

JFormattedTextField ftf = new JFormattedTextField(); 

NumberFormat format = NumberFormat.getNumberInstance(); 
format.setParseIntegerOnly(true); 
ftf.setFormatterFactory(new DefaultFormatterFactory(new NumberFormatter(format), new NumberFormatter(format), new NumberFormatter(format))); 

但我是什么惊讶的是,当我输入100aaa,它是有效的,100.111,也是有效的。 我该如何限制只有整数是有效的输入?

回答

3

您需要在NumberFormatter对象上使用setAllowsInvalid(false)

+0

这仍然不是我想要的,因为它是限制编辑人员而不是编辑人员提交的内容 – Leon 2011-05-27 06:01:45

+0

另请参见['DefaultFormatter'](http://download.oracle.com/javase/6/docs/api/javax/swing/text/DefaultFormatter.html)。 – trashgod 2011-05-27 06:05:17

+2

@Leon,同时添加'format.setMaximumFractionDigits(0);' – 2011-05-27 15:21:46

3

检查这个代码,有仅使用数字输入是允许的,(代码Old.Sun.Com.Tutorial和点点MVC规则修订)

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.text.NumberFormat; 

import javax.swing.BorderFactory; 
import javax.swing.BoundedRangeModel; 
import javax.swing.Box; 
import javax.swing.BoxLayout; 
import javax.swing.JComboBox; 
import javax.swing.JFormattedTextField; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JSlider; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 
import javax.swing.event.EventListenerList; 
import javax.swing.text.NumberFormatter; 

public class Converter { 

    private ConversionPanel metricPanel, usaPanel; 
    private Unit[] metricDistances = new Unit[3]; 
    private Unit[] usaDistances = new Unit[4]; 
    final static boolean MULTICOLORED = false; 
    // Specify the look and feel to use. Valid values: 
    // null (use the default), "Metal", "System", "Motif", "GTK+" 
    final static String LOOKANDFEEL = null; 
    private ConverterRangeModel dataModel = new ConverterRangeModel(); 
    private JPanel mainPane; 

    /** 
    * Create the ConversionPanels (one for metric, another for U.S.). I used 
    * "U.S." because although Imperial and U.S. distance measurements are the 
    * same, this program could be extended to include volume measurements, which 
    * aren't the same. 
    */ 
    public Converter() { 
     // Create Unit objects for metric distances, and then 
     // instantiate a ConversionPanel with these Units. 
     metricDistances[0] = new Unit("Centimeters", 0.01); 
     metricDistances[1] = new Unit("Meters", 1.0); 
     metricDistances[2] = new Unit("Kilometers", 1000.0); 
     metricPanel = new ConversionPanel(this, "Metric System", metricDistances, 
       dataModel); 

     // Create Unit objects for U.S. distances, and then 
     // instantiate a ConversionPanel with these Units. 
     usaDistances[0] = new Unit("Inches", 0.0254); 
     usaDistances[1] = new Unit("Feet", 0.305); 
     usaDistances[2] = new Unit("Yards", 0.914); 
     usaDistances[3] = new Unit("Miles", 1613.0); 
     usaPanel = new ConversionPanel(this, "U.S. System", usaDistances, 
       new FollowerRangeModel(dataModel)); 

     // Create a JPanel, and add the ConversionPanels to it. 
     mainPane = new JPanel(); 
     mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.PAGE_AXIS)); 
     if (MULTICOLORED) { 
      mainPane.setOpaque(true); 
      mainPane.setBackground(new Color(255, 0, 0)); 
     } 
     mainPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 
     mainPane.add(Box.createRigidArea(new Dimension(0, 5))); 
     mainPane.add(metricPanel); 
     mainPane.add(Box.createRigidArea(new Dimension(0, 5))); 
     mainPane.add(usaPanel); 
     mainPane.add(Box.createGlue()); 
     resetMaxValues(true); 
    } 

    public void resetMaxValues(boolean resetCurrentValues) { 
     double metricMultiplier = metricPanel.getMultiplier(); 
     double usaMultiplier = usaPanel.getMultiplier(); 
     int maximum = ConversionPanel.MAX; 
     if (metricMultiplier > usaMultiplier) { 
      maximum = (int) (ConversionPanel.MAX * (usaMultiplier/metricMultiplier)); 
     } 
     dataModel.setMaximum(maximum); 
     if (resetCurrentValues) { 
      dataModel.setDoubleValue(maximum); 
     } 
    } 

    private static void initLookAndFeel() { 
     String lookAndFeel = null; 
     if (LOOKANDFEEL != null) { 
      if (LOOKANDFEEL.equals("Metal")) { 
       lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName(); 
      } else if (LOOKANDFEEL.equals("System")) { 
       lookAndFeel = UIManager.getSystemLookAndFeelClassName(); 
      } else if (LOOKANDFEEL.equals("Motif")) { 
       lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; 
      } else if (LOOKANDFEEL.equals("GTK+")) { // new in 1.4.2 
       lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; 
      } else { 
       System.err.println("Unexpected value of LOOKANDFEEL specified: " + LOOKANDFEEL); 
       lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName(); 
      } 
      try { 
       UIManager.setLookAndFeel(lookAndFeel); 
      } catch (ClassNotFoundException e) { 
       System.err.println("Couldn't find class for specified look and feel:" + lookAndFeel); 
       System.err.println("Did you include the L&F library in the class path?"); 
       System.err.println("Using the default look and feel."); 
      } catch (UnsupportedLookAndFeelException e) { 
       System.err.println("Can't use the specified look and feel (" + lookAndFeel + ") on this platform."); 
       System.err.println("Using the default look and feel."); 
      } catch (Exception e) { 
       System.err.println("Couldn't get specified look and feel (" + lookAndFeel + "), for some reason."); 
       System.err.println("Using the default look and feel."); 
       e.printStackTrace(); 
      } 
     } 
    } 

    /** 
    * Create the GUI and show it. For thread safety, this method should be 
    * invoked from the event-dispatching thread. 
    */ 
    private static void createAndShowGUI() { 
     initLookAndFeel(); 
     JFrame frame = new JFrame("Converter"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     Converter converter = new Converter(); 
     converter.mainPane.setOpaque(true); 
     frame.setContentPane(converter.mainPane); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 

/** 
* Based on the source code for DefaultBoundedRangeModel, this class stores its 
* value as a double, rather than an int. The minimum value and extent are 
* always 0. 
*/ 
class ConverterRangeModel implements BoundedRangeModel { 

    protected ChangeEvent changeEvent = null; 
    protected EventListenerList listenerList = new EventListenerList(); 
    protected int maximum = 10000; 
    protected int minimum = 0; 
    protected int extent = 0; 
    protected double value = 0.0; 
    protected double multiplier = 1.0; 
    protected boolean isAdjusting = false; 

    public ConverterRangeModel() { 
    } 

    public double getMultiplier() { 
     return multiplier; 
    } 

    public void setMultiplier(double multiplier) { 
     this.multiplier = multiplier; 
     fireStateChanged(); 
    } 

    @Override 
    public int getMaximum() { 
     return maximum; 
    } 

    @Override 
    public void setMaximum(int newMaximum) { 
     setRangeProperties(value, extent, minimum, newMaximum, isAdjusting); 
    } 

    @Override 
    public int getMinimum() { 
     return (int) minimum; 
    } 

    @Override 
    public void setMinimum(int newMinimum) { 
     System.out.println("In ConverterRangeModel setMinimum"); 
     // Do nothing. 
    } 

    @Override 
    public int getValue() { 
     return (int) getDoubleValue(); 
    } 

    @Override 
    public void setValue(int newValue) { 
     setDoubleValue((double) newValue); 
    } 

    public double getDoubleValue() { 
     return value; 
    } 

    public void setDoubleValue(double newValue) { 
     setRangeProperties(newValue, extent, minimum, maximum, isAdjusting); 
    } 

    @Override 
    public int getExtent() { 
     return (int) extent; 
    } 

    @Override 
    public void setExtent(int newExtent) { 
     // Do nothing. 
    } 

    @Override 
    public boolean getValueIsAdjusting() { 
     return isAdjusting; 
    } 

    @Override 
    public void setValueIsAdjusting(boolean b) { 
     setRangeProperties(value, extent, minimum, maximum, b); 
    } 

    @Override 
    public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean newAdjusting) { 
     setRangeProperties((double) newValue, newExtent, newMin, newMax, newAdjusting); 
    } 

    public void setRangeProperties(double newValue, int unusedExtent, 
      int unusedMin, int newMax, boolean newAdjusting) { 
     if (newMax <= minimum) { 
      newMax = minimum + 1; 
     } 
     if (Math.round(newValue) > newMax) { // allow some rounding error 
      newValue = newMax; 
     } 
     boolean changeOccurred = false; 
     if (newValue != value) { 
      value = newValue; 
      changeOccurred = true; 
     } 
     if (newMax != maximum) { 
      maximum = newMax; 
      changeOccurred = true; 
     } 
     if (newAdjusting != isAdjusting) { 
      maximum = newMax; 
      isAdjusting = newAdjusting; 
      changeOccurred = true; 
     } 
     if (changeOccurred) { 
      fireStateChanged(); 
     } 
    } 

    /* 
    * The rest of this is event handling code copied from 
    * DefaultBoundedRangeModel. 
    */ 
    @Override 
    public void addChangeListener(ChangeListener l) { 
     listenerList.add(ChangeListener.class, l); 
    } 

    @Override 
    public void removeChangeListener(ChangeListener l) { 
     listenerList.remove(ChangeListener.class, l); 
    } 

    protected void fireStateChanged() { 
     Object[] listeners = listenerList.getListenerList(); 
     for (int i = listeners.length - 2; i >= 0; i -= 2) { 
      if (listeners[i] == ChangeListener.class) { 
       if (changeEvent == null) { 
        changeEvent = new ChangeEvent(this); 
       } 
       ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); 
      } 
     } 
    } 
} 


/* 
* Works in 1.1+Swing, 1.4, and all releases in between. Used by the Converter 
* example. 
*/ 
/** 
* Implements a model whose data is actually in another model (the "source 
* model"). The follower model adjusts the values obtained from the source model 
* (or set in the follower model) to be in a different unit of measure. 
* 
*/ 
class FollowerRangeModel extends ConverterRangeModel implements ChangeListener { 

    private ConverterRangeModel sourceModel; // the real model 

    /** Creates a FollowerRangeModel that gets its state from sourceModel. */ 
    public FollowerRangeModel(ConverterRangeModel sourceModel) { 
     this.sourceModel = sourceModel; 
     sourceModel.addChangeListener(this); 
    } 

    @Override // The only method in the ChangeListener interface. 
    public void stateChanged(ChangeEvent e) { 
     fireStateChanged(); 
    } 

    @Override 
    public int getMaximum() { 
     int modelMax = sourceModel.getMaximum(); 
     double multiplyBy = sourceModel.getMultiplier()/this.getMultiplier(); 
     return (int) (modelMax * multiplyBy); 
    } 

    @Override 
    public void setMaximum(int newMaximum) { 
     sourceModel.setMaximum((int) (newMaximum * (this.getMultiplier()/sourceModel.getMultiplier()))); 
    } 

    @Override 
    public int getValue() { 
     return (int) getDoubleValue(); 
    } 

    @Override 
    public void setValue(int newValue) { 
     setDoubleValue((double) newValue); 
    } 

    @Override 
    public double getDoubleValue() { 
     return sourceModel.getDoubleValue() * sourceModel.getMultiplier() 
       /this.getMultiplier(); 
    } 

    @Override 
    public void setDoubleValue(double newValue) { 
     sourceModel.setDoubleValue(newValue * this.getMultiplier() 
       /sourceModel.getMultiplier()); 
    } 

    @Override 
    public int getExtent() { 
     return super.getExtent(); 
    } 

    @Override 
    public void setExtent(int newExtent) { 
     super.setExtent(newExtent); 
    } 

    @Override 
    public void setRangeProperties(int value, int extent, int min, int max, 
      boolean adjusting) { 
     double multiplyBy = this.getMultiplier()/sourceModel.getMultiplier(); 
     sourceModel.setRangeProperties(value * multiplyBy, extent, min, (int) (max * multiplyBy), adjusting); 
    } 
} 


/* 
* Works in 1.1+Swing, 1.4, and all releases in between. Used by the Converter 
* example. 
*/ 
class Unit { 

    public String description; 
    public double multiplier; 

    Unit(String description, double multiplier) { 
     super(); 
     this.description = description; 
     this.multiplier = multiplier; 
    } 

    @Override 
    public String toString() { 
     String s = "Meters/" + description + " = " + multiplier; 
     return s; 
    } 
} 

/* 
* A 1.4 class used by the Converter example. 
*/ 
class ConversionPanel extends JPanel implements ActionListener, ChangeListener, PropertyChangeListener { 

    private static final long serialVersionUID = 1L; 
    private JFormattedTextField textField; 
    private JComboBox unitChooser; 
    private JSlider slider; 
    private ConverterRangeModel sliderModel; 
    private Converter controller; 
    private Unit[] units; 
    private String title; 
    private NumberFormat numberFormat; 
    final static boolean MULTICOLORED = false; 
    final static int MAX = 10000; 

    ConversionPanel(Converter myController, String myTitle, Unit[] myUnits, ConverterRangeModel myModel) { 
     if (MULTICOLORED) { 
      setOpaque(true); 
      setBackground(new Color(0, 255, 255)); 
     } 
     setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(myTitle), BorderFactory.createEmptyBorder(5, 5, 5, 5))); 
     controller = myController;// Save arguments in instance variables. 
     units = myUnits; 
     title = myTitle; 
     sliderModel = myModel; 
     numberFormat = NumberFormat.getNumberInstance();// Create the text field format, and then the text field. 
     numberFormat.setMaximumFractionDigits(2); 
     NumberFormatter formatter = new NumberFormatter(numberFormat); 
     formatter.setAllowsInvalid(false); 
     formatter.setCommitsOnValidEdit(true);// seems to be a no-op -- aha -- it changes the value property but doesn't cause the result to 
     // be parsed (that happens on focus loss/return, I think). 
     textField = new JFormattedTextField(formatter); 
     textField.setColumns(10); 
     textField.setValue(new Double(sliderModel.getDoubleValue())); 
     textField.addPropertyChangeListener(this);  
     unitChooser = new JComboBox(); // Add the combo box. 
     for (int i = 0; i < units.length; i++) { // Populate it. 
      unitChooser.addItem(units[i].description); 
     } 
     unitChooser.setSelectedIndex(0); 
     sliderModel.setMultiplier(units[0].multiplier); 
     unitChooser.addActionListener(this); 
     slider = new JSlider(sliderModel); // Add the slider. 
     sliderModel.addChangeListener(this); 
     // Make the text field/slider group a fixed size 
     // to make stacked ConversionPanels nicely aligned. 
     JPanel unitGroup = new JPanel() { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public Dimension getMinimumSize() { 
       return getPreferredSize(); 
      } 

      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(150, super.getPreferredSize().height); 
      } 

      @Override 
      public Dimension getMaximumSize() { 
       return getPreferredSize(); 
      } 
     }; 
     unitGroup.setLayout(new BoxLayout(unitGroup, BoxLayout.PAGE_AXIS)); 
     if (MULTICOLORED) { 
      unitGroup.setOpaque(true); 
      unitGroup.setBackground(new Color(0, 0, 255)); 
     } 
     unitGroup.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); 
     unitGroup.add(textField); 
     unitGroup.add(slider); 
     JPanel chooserPanel = new JPanel();// Create a subpanel so the combo box isn't too tall and is sufficiently wide. 
     chooserPanel.setLayout(new BoxLayout(chooserPanel, BoxLayout.PAGE_AXIS)); 
     if (MULTICOLORED) { 
      chooserPanel.setOpaque(true); 
      chooserPanel.setBackground(new Color(255, 0, 255)); 
     } 
     chooserPanel.add(unitChooser); 
     chooserPanel.add(Box.createHorizontalStrut(100)); 
     setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));// Put everything together. 
     add(unitGroup); 
     add(chooserPanel); 
     unitGroup.setAlignmentY(TOP_ALIGNMENT); 
     chooserPanel.setAlignmentY(TOP_ALIGNMENT); 
    } 

    // Don't allow this panel to get taller than its preferred size. 
    // BoxLayout pays attention to maximum size, though most layout 
    // managers don't. 
    @Override 
    public Dimension getMaximumSize() { 
     return new Dimension(Integer.MAX_VALUE, getPreferredSize().height); 
    } 

    /** 
    * Returns the multiplier (units/meter) for the currently selected unit of 
    * measurement. 
    */ 
    public double getMultiplier() { 
     return sliderModel.getMultiplier(); 
    } 

    public double getValue() { 
     return sliderModel.getDoubleValue(); 
    } 

    /** Updates the text field when the main data model is updated. */ 
    @Override 
    public void stateChanged(ChangeEvent e) { 
     int min = sliderModel.getMinimum(); 
     int max = sliderModel.getMaximum(); 
     double value = sliderModel.getDoubleValue(); 
     NumberFormatter formatter = (NumberFormatter) textField.getFormatter(); 
     formatter.setMinimum(new Double(min)); 
     formatter.setMaximum(new Double(max)); 
     textField.setValue(new Double(value)); 
    } 

    /** 
    * Responds to the user choosing a new unit from the combo box. 
    */ 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     int i = unitChooser.getSelectedIndex(); // Combo box event. Set new maximums for the sliders. 
     sliderModel.setMultiplier(units[i].multiplier); 
     controller.resetMaxValues(false); 
    } 

    /** 
    * Detects when the value of the text field (not necessarily the same number 
    * as you'd get from getText) changes. 
    */ 
    @Override 
    public void propertyChange(PropertyChangeEvent e) { 
     if ("value".equals(e.getPropertyName())) { 
      Number value = (Number) e.getNewValue(); 
      sliderModel.setDoubleValue(value.doubleValue()); 
     } 
    } 
} 
+0

+1我喜欢代码示例。这应该解决OP的问题。 – Boro 2011-05-28 10:39:16