java+jtextfield+取值,是否有任何方法只接受JTextField中的数值?

由于这个问题经常出现,我在这个问题上投入了更多的精力,而不是我通常会做的。

我投给JFormattedTextField..每个Swing开发人员都应该在他/她的工具箱中有一个改进的该类版本,因为它允许通过正确的选择来验证几乎所有您可以想到的东西。Format..我已经用过的例子:字符串输入,其中

String可能不是空的

坐标输入

日期输入

编辑

JSpinner

地图比例尺

数字

...

它还允许在输入无效时进行视觉反馈,例如,InputVerifier..它仍然允许用户输入任何内容,但是当该值无效时,该值就不会被接受,并且该值永远不会离开UI。我认为(但这也是我的观点),最好允许用户输入无效的输入,然后用例如DocumentFilter..当在文本字段中键入字符而不出现时,我会怀疑存在错误。

让我用一些代码(实际上是一些代码)来说明这一点。首先是小型演示应用程序。此应用程序仅显示JFormattedTextField为了数字。只需使用另一种格式,就可以重用该组件进行完全不同的验证。

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和一个JButton它只在输入有效时才启用(啊哈,请吃那个。)DocumentFilter解决办法)。它还显示了JTextArea其中,每次遇到新的有效值时都会打印该值。按下按钮显示值。

的代码ImprovedFormattedTextField可以在下面找到,以及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;/**

Extension of {@code JFormattedTextField} which solves some of the usability issues

*/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;/**

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.

*/public class ParseAllFormat extends Format {

private final Format fDelegate;

/**

* Decorate aDelegate 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() 

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都会尊重这一点。因此,为了获得视觉反馈,最好在字段旁边使用感叹号。缺点是,如果突然添加/移除图标,这可能会破坏布局。

反馈只表示输入有效/无效。没有任何东西表明预期格式是什么。的一个可能的解决方案是使用自创建的

Format,它包括一个有效输入的描述/示例,并将其作为工具提示放在

JFormattedTextField.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值