有没有办法只接受一个JTextField中的数值?

有没有办法只接受一个JTextField数值? 有没有特别的方法呢?

由于这个问题经常再次出现,我通常会做更多的努力来解决这个问题。

我的投票转到JFormattedTextField 。 国际海事组织的每个Swing开发者都应该在他/她的工具包中有一个改进版本的类,因为它允许通过Format的正确select来validation几乎任何你能想到的东西。 我已经使用它的例子:

  • stringinput,其中的String不能为空
  • 协调input
  • dateinput
  • 编辑JSpinner
  • 地图比例
  • 数字

它还允许在input无效的情况下进行视觉反馈,这与InputVerifier 。 它仍然允许用户input任何内容,但是这个值在无效时不被接受,并且该值永远不会离开UI。 我认为(但同样,这是我的意见),让用户键入无效的input,只是将它自动删除,如DocumentFilter更好。 我会怀疑当在文本字段中键入一个字符,并且它不会出现一个错误。

让我用一些代码(实际上相当一些代码)来说明这一点。 首先是小演示应用程序。 这个应用程序只显示一个数字的JFormattedTextField 。 只要使用其他格式,就可以重复使用该组件进行完全不同的validation。

在这里输入图像描述

 import be.pcl.swing.ImprovedFormattedTextField; import javax.swing.*; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.NumberFormat; /** * See http://stackoverflow.com/q/1313390/1076463 */ public class FormattedTextFieldDemo { public static void main( String[] args ) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame testFrame = new JFrame( "FormattedTextFieldDemo" ); NumberFormat integerNumberInstance = NumberFormat.getIntegerInstance(); ImprovedFormattedTextField integerFormattedTextField = new ImprovedFormattedTextField( integerNumberInstance, 100 ); integerFormattedTextField.setColumns( 20 ); testFrame.add( createButtonPanel( integerFormattedTextField ), BorderLayout.NORTH ); final JTextArea textArea = new JTextArea(50, 50); PropertyChangeListener updateTextAreaListener = new PropertyChangeListener() { @Override public void propertyChange( PropertyChangeEvent evt ) { textArea.append( "New value: " + evt.getNewValue() + "\n" ); } }; integerFormattedTextField.addPropertyChangeListener( "value", updateTextAreaListener ); testFrame.add( new JScrollPane( textArea ), BorderLayout.CENTER ); testFrame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE ); testFrame.pack(); testFrame.setVisible( true ); } } ); } private static JPanel createButtonPanel( final JFormattedTextField aTextField ){ JPanel panel = new JPanel( new BorderLayout( ) ); panel.add( aTextField, BorderLayout.WEST ); Action action = new AbstractAction() { { aTextField.addPropertyChangeListener( "editValid", new PropertyChangeListener() { @Override public void propertyChange( PropertyChangeEvent evt ) { setEnabled( ( ( Boolean ) evt.getNewValue() ) ); } } ); putValue( Action.NAME, "Show current value" ); } @Override public void actionPerformed( ActionEvent e ) { JOptionPane.showMessageDialog( null, "The current value is [" + aTextField.getValue() + "] of class [" + aTextField.getValue().getClass() + "]" ); } }; panel.add( new JButton( action ), BorderLayout.EAST ); return panel; } } 

它只显示了一个ImprovedFormattedTextField和一个只在input有效的情况下启用的JButton (aha,吃掉DocumentFilter解决scheme)。 它还显示了一个JTextArea ,每当遇到一个新的有效值时,将在其中打印值。 按下button显示值。

ImprovedFormattedTextField的代码可以在下面find,连同它所依赖的ParseAllFormat

 package be.pcl.swing; import javax.swing.JFormattedTextField; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.Color; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.text.Format; import java.text.ParseException; /** * <p>Extension of {@code JFormattedTextField} which solves some of the usability issues</p> */ public class ImprovedFormattedTextField extends JFormattedTextField { private static final Color ERROR_BACKGROUND_COLOR = new Color( 255, 215, 215 ); private static final Color ERROR_FOREGROUND_COLOR = null; private Color fBackground, fForeground; /** * Create a new {@code ImprovedFormattedTextField} instance which will use {@code aFormat} for the * validation of the user input. * * @param aFormat The format. May not be {@code null} */ public ImprovedFormattedTextField( Format aFormat ) { //use a ParseAllFormat as we do not want to accept user input which is partially valid super( new ParseAllFormat( aFormat ) ); setFocusLostBehavior( JFormattedTextField.COMMIT_OR_REVERT ); updateBackgroundOnEachUpdate(); //improve the caret behavior //see also http://tips4java.wordpress.com/2010/02/21/formatted-text-field-tips/ addFocusListener( new MousePositionCorrectorListener() ); } /** * Create a new {@code ImprovedFormattedTextField} instance which will use {@code aFormat} for the * validation of the user input. The field will be initialized with {@code aValue}. * * @param aFormat The format. May not be {@code null} * @param aValue The initial value */ public ImprovedFormattedTextField( Format aFormat, Object aValue ) { this( aFormat ); setValue( aValue ); } private void updateBackgroundOnEachUpdate() { getDocument().addDocumentListener( new DocumentListener() { @Override public void insertUpdate( DocumentEvent e ) { updateBackground(); } @Override public void removeUpdate( DocumentEvent e ) { updateBackground(); } @Override public void changedUpdate( DocumentEvent e ) { updateBackground(); } } ); } /** * Update the background color depending on the valid state of the current input. This provides * visual feedback to the user */ private void updateBackground() { boolean valid = validContent(); if ( ERROR_BACKGROUND_COLOR != null ) { setBackground( valid ? fBackground : ERROR_BACKGROUND_COLOR ); } if ( ERROR_FOREGROUND_COLOR != null ) { setForeground( valid ? fForeground : ERROR_FOREGROUND_COLOR ); } } @Override public void updateUI() { super.updateUI(); fBackground = getBackground(); fForeground = getForeground(); } private boolean validContent() { AbstractFormatter formatter = getFormatter(); if ( formatter != null ) { try { formatter.stringToValue( getText() ); return true; } catch ( ParseException e ) { return false; } } return true; } @Override public void setValue( Object value ) { boolean validValue = true; //before setting the value, parse it by using the format try { AbstractFormatter formatter = getFormatter(); if ( formatter != null ) { formatter.valueToString( value ); } } catch ( ParseException e ) { validValue = false; updateBackground(); } //only set the value when valid if ( validValue ) { int old_caret_position = getCaretPosition(); super.setValue( value ); setCaretPosition( Math.min( old_caret_position, getText().length() ) ); } } @Override protected boolean processKeyBinding( KeyStroke ks, KeyEvent e, int condition, boolean pressed ) { //do not let the formatted text field consume the enters. This allows to trigger an OK button by //pressing enter from within the formatted text field if ( validContent() ) { return super.processKeyBinding( ks, e, condition, pressed ) && ks != KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ); } else { return super.processKeyBinding( ks, e, condition, pressed ); } } private static class MousePositionCorrectorListener extends FocusAdapter { @Override public void focusGained( FocusEvent e ) { /* After a formatted text field gains focus, it replaces its text with its * current value, formatted appropriately of course. It does this after * any focus listeners are notified. We want to make sure that the caret * is placed in the correct position rather than the dumb default that is * before the 1st character ! */ final JTextField field = ( JTextField ) e.getSource(); final int dot = field.getCaret().getDot(); final int mark = field.getCaret().getMark(); if ( field.isEnabled() && field.isEditable() ) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { // Only set the caret if the textfield hasn't got a selection on it if ( dot == mark ) { field.getCaret().setDot( dot ); } } } ); } } } } 

ParseAllFormat类:

 package be.pcl.swing; import java.text.AttributedCharacterIterator; import java.text.FieldPosition; import java.text.Format; import java.text.ParseException; import java.text.ParsePosition; /** * <p>Decorator for a {@link Format Format} which only accepts values which can be completely parsed * by the delegate format. If the value can only be partially parsed, the decorator will refuse to * parse the value.</p> */ public class ParseAllFormat extends Format { private final Format fDelegate; /** * Decorate <code>aDelegate</code> to make sure if parser everything or nothing * * @param aDelegate The delegate format */ public ParseAllFormat( Format aDelegate ) { fDelegate = aDelegate; } @Override public StringBuffer format( Object obj, StringBuffer toAppendTo, FieldPosition pos ) { return fDelegate.format( obj, toAppendTo, pos ); } @Override public AttributedCharacterIterator formatToCharacterIterator( Object obj ) { return fDelegate.formatToCharacterIterator( obj ); } @Override public Object parseObject( String source, ParsePosition pos ) { int initialIndex = pos.getIndex(); Object result = fDelegate.parseObject( source, pos ); if ( result != null && pos.getIndex() < source.length() ) { int errorIndex = pos.getIndex(); pos.setIndex( initialIndex ); pos.setErrorIndex( errorIndex ); return null; } return result; } @Override public Object parseObject( String source ) throws ParseException { //no need to delegate the call, super will call the parseObject( source, pos ) method return super.parseObject( source ); } } 

可能的改进:

  • setBackground不受所有外观的影响。 有时你可以使用setForeground ,但即使这样也不能保证所有的L&F都能遵守。 因此,对于视觉反馈,最好在场地旁边使用感叹号。 缺点是,如果你突然添加/删除图标,这可能会弄乱布局
  • 反馈仅表示input有效/无效。 没有任何东西表明预期的格式是什么。 一个可能的解决scheme是使用Format自我创build的扩展,其中包括有效input的描述/示例,并将其作为工具提示放在JFormattedTextField

这个问题被引用为另一个自从被closures的问题的“重复”。 这个问题的答案是如此之差,以至于我被启发去帮助任何可能在后来find它的人,通过链接到这个用例的更好的答案。

这是closures的问题的答案,可以概括为..

改用JSpinner

 import javax.swing.*; import javax.swing.text.*; public class JNumberTextField extends JTextField { private static final char DOT = '.'; private static final char NEGATIVE = '-'; private static final String BLANK = ""; private static final int DEF_PRECISION = 2; public static final int NUMERIC = 2; public static final int DECIMAL = 3; public static final String FM_NUMERIC = "0123456789"; public static final String FM_DECIMAL = FM_NUMERIC + DOT; private int maxLength = 0; private int format = NUMERIC; private String negativeChars = BLANK; private String allowedChars = null; private boolean allowNegative = false; private int precision = 0; protected PlainDocument numberFieldFilter; public JNumberTextField() { this( 10, NUMERIC ); } public JNumberTextField( int maxLen ) { this( maxLen, NUMERIC ); } public JNumberTextField( int maxLen, int format ) { setAllowNegative( true ); setMaxLength( maxLen ); setFormat( format ); numberFieldFilter = new JNumberFieldFilter(); super.setDocument( numberFieldFilter ); } public void setMaxLength( int maxLen ) { if (maxLen > 0) maxLength = maxLen; else maxLength = 0; } public int getMaxLength() { return maxLength; } public void setPrecision( int precision ) { if ( format == NUMERIC ) return; if ( precision >= 0 ) this.precision = precision; else this.precision = DEF_PRECISION; } public int getPrecision() { return precision; } public Number getNumber() { Number number = null; if ( format == NUMERIC ) number = new Integer(getText()); else number = new Double(getText()); return number; } public void setNumber( Number value ) { setText(String.valueOf(value)); } public int getInt() { return Integer.parseInt( getText() ); } public void setInt( int value ) { setText( String.valueOf( value ) ); } public float getFloat() { return ( new Float( getText() ) ).floatValue(); } public void setFloat(float value) { setText( String.valueOf( value ) ); } public double getDouble() { return ( new Double( getText() ) ).doubleValue(); } public void setDouble(double value) { setText( String.valueOf(value) ); } public int getFormat() { return format; } public void setFormat(int format) { switch ( format ) { case NUMERIC: default: this.format = NUMERIC; this.precision = 0; this.allowedChars = FM_NUMERIC; break; case DECIMAL: this.format = DECIMAL; this.precision = DEF_PRECISION; this.allowedChars = FM_DECIMAL; break; } } public void setAllowNegative( boolean value ) { allowNegative = value; if ( value ) negativeChars = "" + NEGATIVE; else negativeChars = BLANK; } public boolean isAllowNegative() { return allowNegative; } public void setDocument( Document document ) { } class JNumberFieldFilter extends PlainDocument { public JNumberFieldFilter() { super(); } public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException { String text = getText(0,offset) + str + getText(offset,(getLength() - offset)); if ( str == null || text == null ) return; for ( int i=0; i<str.length(); i++ ) { if ( ( allowedChars + negativeChars ).indexOf( str.charAt(i) ) == -1) return; } int precisionLength = 0, dotLength = 0, minusLength = 0; int textLength = text.length(); try { if ( format == NUMERIC ) { if ( ! ( ( text.equals( negativeChars ) ) && ( text.length() == 1) ) ) new Long(text); } else if ( format == DECIMAL ) { if ( ! ( ( text.equals( negativeChars ) ) && ( text.length() == 1) ) ) new Double(text); int dotIndex = text.indexOf(DOT); if( dotIndex != -1 ) { dotLength = 1; precisionLength = textLength - dotIndex - dotLength; if( precisionLength > precision ) return; } } } catch(Exception ex) { return; } if ( text.startsWith( "" + NEGATIVE ) ) { if ( !allowNegative ) return; else minusLength = 1; } if ( maxLength < ( textLength - dotLength - precisionLength - minusLength ) ) return; super.insertString( offset, str, attr ); } } } 

虽然存在纯粹的恶意JFormattedTextField但仅使用Swing库并不是一件简单的方法。 实现这种function的最好方法是使用DocumentFilter

我之前准备的一些代码。 一点描述。

快速解决scheme:

 JTextField textField = new JTextField() { public void processKeyEvent(KeyEvent ev) { char c = ev.getKeyChar(); if (c >= 48 && c <= 57) { // c = '0' ... c = '9' super.processKeyEvent(ev); } } }; 

上述解决scheme的问题是,用户不能使用文本字段中的删除,左箭头,右箭头或退格键,所以我build议使用此解决scheme:

 this.portTextField = new JTextField() { public void processKeyEvent(KeyEvent ev) { char c = ev.getKeyChar(); try { // Ignore all non-printable characters. Just check the printable ones. if (c > 31 && c < 127) { Integer.parseInt(c + ""); } super.processKeyEvent(ev); } catch (NumberFormatException nfe) { // Do nothing. Character inputted is not a number, so ignore it. } } }; 

一个简单的方法是通过返回定制的PlainDocument子类来inheritanceJTextField并覆盖createDefaultModel()。 示例 – 仅用于整数的文本字段:

 public class NumberField extends JTextField { @Override protected Document createDefaultModel() { return new Numberdocument(); } class Numberdocument extends PlainDocument { String numbers="1234567890-"; @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if(!numbers.contains(str)); else super.insertString(offs, str, a); } } 

以任何方式在insertString()中处理input。

另外,请考虑使用InputVerifier

同意这个问题越来越多的意见,我没有发现上述解决scheme适合我的问题。 我决定做一个自定义的PlainDocument来适应我的需求。 当达到所使用的最大字符数时,此解决scheme也会发出嘟嘟声,或插入的文本不是整数。

 private class FixedSizeNumberDocument extends PlainDocument { private JTextComponent owner; private int fixedSize; public FixedSizeNumberDocument(JTextComponent owner, int fixedSize) { this.owner = owner; this.fixedSize = fixedSize; } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (getLength() + str.length() > fixedSize) { str = str.substring(0, fixedSize - getLength()); this.owner.getToolkit().beep(); } try { Integer.parseInt(str); } catch (NumberFormatException e) { // inserted text is not a number this.owner.getToolkit().beep(); return; } super.insertString(offs, str, a); } } 

执行如下:

  JTextField textfield = new JTextField(); textfield.setDocument(new FixedSizeNumberDocument(textfield,5)); 

一个非常简单的解决scheme是使用一个动作监听器。

 TextFieldActionPerformed(java.awt.event.ActionEvent evt) { try{ Integer.parseInteger(TextField.getText()); } catch(Exception e){ JOptionPane.showMessageDialog(null, "Please insert Valid Number Only"); TextField.setText(TextField.getText().substring(0,TextField.getText().length()-1)); } } 

您也可以将它用于Double:

 Double.parseDouble(TextField.getText()); 

看看JFormattedTextField 。

把这个代码写入键入的键入

 char c=evt.getKeyChar(); if(!(Character.isDigit(c) || (c==KeyEvent.VK_BACK_SPACE || c==KeyEvent.VK_DELETE))) { getToolkit().beep(); evt.consume(); } 
 if (JTextField.getText().equals("") || !(Pattern.matches("^[0-9]+$", JTextField.getText()))) { JOptionPane.showMessageDialog(null, " JTextField Invalide !!!!! "); } 
  • 如果JTextField.getText()。equals(“”)== – >如果JTextField为空
  • if(!(Pattern.matches(“^ [0-9] + $”,JTextField.getText())))== – >如果TextField包含其他字符
  • JOptionPane.showMessageDialog(null,“JTextField Invalide !!!!!”); == – >所以这个消息将分开

在相关的JTextField的按键事件中试试这个。

 private void JTextField(java.awt.event.KeyEvent evt) { // TODO add your handling code here: char enter = evt.getKeyChar(); if(!(Character.isDigit(enter))){ evt.consume(); } } 

使用formatter来格式化文本字段。

 NumberFormat format = NumberFormat.getInstance(); format.setGroupingUsed(false); NumberFormatter formatter = new NumberFormatter(format); formatter.setValueClass(Integer.class); formatter.setMaximum(65535); formatter.setAllowsInvalid(false); formatter.setCommitsOnValidEdit(true); myTextField = new JFormattedTextField(formatter); 

numberField = new JFormattedTextField(NumberFormat.getInstance());

格式化文本字段教程

你想看看JFormattedTextField

带格式的文本字段为开发人员提供了一种指定可在文本字段中键入的有效字符集的方法

这是JTextField的一个子类,所以你可以像这样使用它:

 JTextField textField = new JFormattedTextField(NumberFormat.getInstance()); 

我认为这是最好的解决scheme:

 JTextField textField = new JFormattedTextField(new MaskFormatter("###")); // 

你可以在java中创build一个漂亮的文本字段,它接受或只允许数字值。你甚至可以设置浮点值的精度…检查代码在zybocodes

 textfield.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent ke) { char c = ke.getKeyChar(); if((!(Character.isDigit(c))) && // Only digits (c ! '\b') ) // For backspace { ke.consume(); } } public void keyReleased(KeyEvent e){} public void keyPressed(KeyEvent e){} });