使JFormattedTextField的行为类似于ATM输入

时间:2013-06-12 20:29:58

标签: java swing jformattedtextfield number-formatting

我想知道是否有任何方式使JformattedTextField或jtextField表现得像atm money输入。我的意思是你从右到左输入,比如你输入10你需要再按2个0,这样它就是10.00。程序从右到左自动输入小数点?如果未输入2 0,则仅为.10。这可能吗?如果我想使用该字符串进行计算,那将如何返回给我?我尝试了抽象格式化程序,但这并不能很好地工作。我想用它来输入客户收到的金额。但要做到白痴证明。

3 个答案:

答案 0 :(得分:4)

这会强制用户始终从右侧输入文本,无论插入符号位于何处。插入新字符时,所有先前的字符都向左移动。格式化将根据您的格式化程序应用:

import java.awt.*;
import java.text.*;
import javax.swing.*;
import javax.swing.text.*;

public class ABMTextField extends JTextField
{
    private DecimalFormat format;
    private String decimal;

    public ABMTextField(DecimalFormat format)
    {
        this.format = format;

        decimal = Character.toString( format.getDecimalFormatSymbols().getDecimalSeparator() );

        setColumns( format.toPattern().length() );
        setHorizontalAlignment(JFormattedTextField.TRAILING);

        setText( format.format(0.0) );

        AbstractDocument doc = (AbstractDocument)getDocument();
        doc.setDocumentFilter( new ABMFilter() );
    }

    @Override
    public void setText(String text)
    {
        Number number = format.parse(text, new ParsePosition(0));

        if (number != null)
            super.setText( text );
    }

    public class ABMFilter extends DocumentFilter
    {
        public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
            throws BadLocationException
        {
            replace(fb, offs, 0, str, a);
        }

        public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
            throws BadLocationException
        {
            if ("0123456789".contains(str))
            {
                Document doc = fb.getDocument();
                StringBuilder sb = new StringBuilder( doc.getText(0, doc.getLength()) );

                int decimalOffset = sb.indexOf( decimal );

                if (decimalOffset != -1)
                {
                    sb.deleteCharAt(decimalOffset);
                    sb.insert(decimalOffset + 1, decimal);
                }

                sb.append(str);

                try
                {
                    String text = format.format( format.parse( sb.toString() ) );
                    super.replace(fb, 0, doc.getLength(), text, a);
                }
                catch(ParseException e) {}
            }
            else
                Toolkit.getDefaultToolkit().beep();
        }

        public void remove(DocumentFilter.FilterBypass fb, int offset, int length)
            throws BadLocationException
        {
            Document doc = fb.getDocument();
            StringBuilder sb = new StringBuilder( doc.getText(0, doc.getLength()) );

            int decimalOffset = sb.indexOf( decimal );

            if (decimalOffset != -1)
            {
                sb.deleteCharAt(decimalOffset);
                sb.insert(decimalOffset - 1, decimal);
            }

            sb.deleteCharAt( sb.length() - 1) ;

            try
            {
                String text = format.format( format.parse( sb.toString() ) );
                super.replace(fb, 0, doc.getLength(), text, null);
            }
            catch(ParseException e) {}
        }
    }

    private static void createAndShowUI()
    {
        DecimalFormat format = new DecimalFormat("###,##0.00");
        ABMTextField abm = new ABMTextField( format );

        JPanel panel = new JPanel();
        panel.add( abm );

        JFrame frame = new JFrame("ABMTextField");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( panel );
        frame.setSize(200, 200);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}
  

如果我想使用该字符串进行计算,那将如何返回给我?

您需要创建一个方法,可能是getValue(),它将使用format.parse(...)方法返回实际数字。

答案 1 :(得分:2)

请查看How to use Formatted Text Fields,特别是Using MaskFormatter

像...一样的东西。

MaskFormatter formatter = new MaskFormatter("##.##");
JFormattedTextField field = JFormattedTextField(formatter);
例如,

可能有帮助。

简单示例

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.MaskFormatter;

public class TestFormattedTextField {

    public static void main(String[] args) {
        new TestFormattedTextField();
    }

    public TestFormattedTextField() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                try {
                    JFormattedTextField field = new JFormattedTextField();
                    MaskFormatter formatter = new MaskFormatter("##.##");
                    formatter.setPlaceholderCharacter('0');
                    field.setFormatterFactory(new DefaultFormatterFactory(formatter));

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new GridBagLayout());
                    frame.add(field);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (ParseException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }        
}

附加示例

现在,我意识到上一个示例不符合您的确切需求(正如您所描述的那样),这是一个简单的解决方案,我还添加了一个DocumentFilter示例......

enter image description here

将输出...

Value = 0.1
Value = $0.10

enter image description here

将输出

Value = 10.0
Value = $10.00

...代码

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.MaskFormatter;

public class TestFormattedTextField {

    public static void main(String[] args) {
        new TestFormattedTextField();
    }

    public TestFormattedTextField() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                MoneyField field = new MoneyField();
                field.addActionListener(new ActionListener() {
                    @Override
                    @SuppressWarnings("empty-statement")
                    public void actionPerformed(ActionEvent e) {
                        MoneyField field = (MoneyField) e.getSource();
                        double value = field.getValue();
                        System.out.println("Value = " + value);
                        System.out.println("Value = " + NumberFormat.getCurrencyInstance().format(value));
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                frame.add(field);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MoneyField extends JTextField {

        public MoneyField() {
            setColumns(5);
            setHorizontalAlignment(RIGHT);
            ((AbstractDocument) getDocument()).setDocumentFilter(new Filter());
        }

        public double getValue() {

            String text = getText();
            if (!text.contains(".")) {
                text = "0." + text;
            }

            return Double.parseDouble(text);

        }

        protected class Filter extends DocumentFilter {

            protected String getNumbers(String text) {
                StringBuilder sb = new StringBuilder(text.length());
                for (char c : text.toCharArray()) {
                    if (Character.isDigit(c)) {
                        sb.append(c);
                    }
                }
                return sb.toString();
            }

            @Override
            public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
                if (length > 0) {
                    fb.remove(offset, length);
                }
                insertString(fb, offset, text, attrs);
            }

            @Override
            public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
                text = getNumbers(text);
                if (text.length() > 0) {
                    int docLength = fb.getDocument().getLength();
                    if (docLength == 2) {
                        text = "." + text;
                    }
                    if (docLength + text.length() < 6) {
                        super.insertString(fb, offset, text, attr);
                    }
                }
            }

            @Override
            public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
                if (offset == 3) {
                    offset = 2;
                    length = 2;
                }
                super.remove(fb, offset, length);
            }
        }
    }
}

查看DocumentFilter examples了解详情

答案 2 :(得分:1)

对JTextField使用DocumentFilter并覆盖适当的方法来处理数字格式。如果你能发布你所尝试过的并且“不起作用”,那也很好。