try - validar solo letras en un jtextfield java
¿Hay alguna forma de aceptar solo valores numéricos en un JTextField? (19)
Además, considere usar un InputVerifier
.
¿Hay alguna forma de aceptar solo valores numéricos en un JTextField
? ¿Hay algún método especial para esto?
Aunque existe el malvado JFormattedTextField
no hay una manera trivial de hacerlo utilizando solo la biblioteca Swing. La mejor manera de implementar este tipo de característica es con un DocumentFilter
.
Como esta pregunta reaparece bastante a menudo, puse un poco más de esfuerzo en esta respuesta que normalmente solía hacer.
Mi voto va al JFormattedTextField
. OMI cada desarrollador de Swing debe tener una versión mejorada de esa clase en su conjunto de herramientas, ya que permite validar casi cualquier cosa que se le ocurra mediante la opción correcta de Format
. Ejemplos para los cuales ya lo usé:
- Entrada de cadena donde la
String
no puede estar vacía - Entrada coordinada
- Entrada de fecha
- Editor en un
JSpinner
- Escalas del mapa
- Números
- ...
También permite comentarios visuales cuando la entrada no es válida, que no es el caso con el InputVerifier
. Todavía permite al usuario ingresar cualquier cosa, pero ese valor simplemente no se acepta cuando no es válido y ese valor nunca abandona la UI. Creo (pero, nuevamente, esa es mi opinión) que es mejor permitir que el usuario escriba una entrada no válida que simplemente eliminarla automáticamente, por ejemplo, con un DocumentFilter
. Sospecho que hay un error al escribir un carácter en un campo de texto y no aparece.
Permítanme ilustrar esto con algún código (bastante código en realidad). Primero, la pequeña aplicación de demostración. Esta aplicación solo muestra un JFormattedTextField
para números. El solo uso de otro formato permite reutilizar ese componente para validaciones completamente diferentes.
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://.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;
}
}
que solo muestra un ImprovedFormattedTextField
y un JButton
que solo se habilita cuando la entrada es válida (aha, come esa solución de DocumentFilter
). También muestra un JTextArea
en el que el valor se imprime cada vez que se encuentra un nuevo valor válido. Al presionar el botón, se muestra el valor.
El código para ImprovedFormattedTextField
se puede encontrar a continuación, junto con ParseAllFormat
del que depende
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 );
}
}
} );
}
}
}
}
La clase 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 );
}
}
Posibles mejoras:
- el
setBackground
no es respetado por todos los Look-and-Feels. A veces puede usarsetForeground
ensetForeground
lugar, pero incluso eso no está garantizado para ser respetado por todos los L & F. Entonces, para comentarios visuales, sería mejor usar un signo de exclamación colocado al lado del campo. El inconveniente es que esto podría arruinar un diseño si de repente agrega / elimina un icono - la retroalimentación solo indica que la entrada es válida / inválida. No hay nada que indique cuál es el formato esperado. Una posible solución es usar una extensión de
Format
creada por elJFormattedTextField
que incluya una descripción / ejemplo de entrada válida, y poner eso como información sobre herramientas enJFormattedTextField
.
Concluyendo la cantidad de vistas que está recibiendo esta pregunta, no encontré ninguna de las soluciones anteriores adecuadas para mi problema. Decidí hacer un PlainDocument personalizado para satisfacer mis necesidades. Esta solución también emite un pitido cuando se alcanza el número máximo de caracteres utilizados, o el texto insertado no es un número entero.
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);
}
}
implementado de la siguiente manera:
JTextField textfield = new JTextField();
textfield.setDocument(new FixedSizeNumberDocument(textfield,5));
Creo que es la mejor solución:
JTextField textField = new JFormattedTextField(new MaskFormatter("###")); //
Esta pregunta fue citada como un "duplicado exacto" de otra pregunta que se ha cerrado desde entonces. Las respuestas a esta pregunta fueron tan pobres que me inspiré para ayudar a cualquiera que pudiera encontrarlo más tarde, al vincular una respuesta mucho mejor para este caso de uso.
Es una respuesta a la pregunta cerrada y se puede resumir como ...
Use un JSpinner
en JSpinner
lugar.
Mire JFormattedTextField .
Pruébelo en el evento de tecla presionada para el JTextField relacionado.
private void JTextField(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
char enter = evt.getKeyChar();
if(!(Character.isDigit(enter))){
evt.consume();
}
}
Puede crear un hermoso campo de texto en Java que acepte o permita solo valores numéricos. Incluso puede establecer la precisión de los valores flotantes ... verifique el code en zybocodes
Te gustaría echar un vistazo a JFormattedTextField
Los campos de texto formateados proporcionan una forma para que los desarrolladores especifiquen el conjunto válido de caracteres que pueden escribirse en un campo de texto
Esta es una subclase de JTextField, por lo que puedes usarla así:
JTextField textField = new JFormattedTextField(NumberFormat.getInstance());
Un enfoque simple es subclasificar JTextField y anular createDefaultModel () devolviendo la subclase PlainDocument personalizada. Ejemplo: un campo de texto solo para enteros:
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);
}
}
Ingrese la entrada en insertString () de cualquier manera.
Una solución muy fácil es usar un oyente de acción.
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));
}
}
Puedes usarlo también para el doble:
Double.parseDouble(TextField.getText());
Una solución rápida:
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);
}
}
};
El problema con la solución anterior es que el usuario no puede usar las teclas Eliminar, Flecha izquierda, Flecha derecha o Retroceso en el campo de texto, por lo que sugiero usar esta solución:
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.
}
}
};
Use el formatter
para formatear el campo de texto.
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);
escribe este código en la clave escrita
char c=evt.getKeyChar();
if(!(Character.isDigit(c) || (c==KeyEvent.VK_BACK_SPACE || c==KeyEvent.VK_DELETE)))
{
getToolkit().beep();
evt.consume();
}
numberField = new JFormattedTextField (NumberFormat.getInstance ());
DataTF.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent eve) {
String AllowedData="0123456789.";
char enter = eve.getKeyChar();
if (!AllowedData.contains(String.valueOf(enter))) {
eve.consume();
}
}
});
if (JTextField.getText().equals("") || !(Pattern.matches("^[0-9]+$", JTextField.getText()))) {
JOptionPane.showMessageDialog(null, " JTextField Invalide !!!!! ");
}
- if JTextField.getText (). equals ("") == -> si JTextField está vacío
- if (! (Pattern.matches ("^ [0-9] + $", JTextField.getText ()))) == -> si TextField contiene otros caracteres distintos a los
- JOptionPane.showMessageDialog (null, "JTextField Invalide !!!!!"); == -> entonces este mensaje aparecerá
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 );
}
}
}