【问题标题】:Getting preview of final text from jTextField从 jTextField 获取最终文本的预览
【发布时间】:2020-12-15 16:27:03
【问题描述】:

我正在尝试创建JTextField,该检查只能接受双精度数(包括科学记数法):

abstract class DoubleKeyAdapter extends KeyAdapter
{
    @Override
    public void KeyTyped(KeyEvent e)
    {
        if (!(((JTextField) e.getSource()).getText() + e.getKeyChar()).matches(“[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d*)?”))
            e.consume();
    }

    @Override
    public abstract void KeyReleased(KeyEvent e);
}

问题是当我尝试将- 添加到例如文本字段的开头时。它不允许我这样做,因为它通过在文本末尾附加 - 来进行检查,换句话说,我不知道新字符添加到哪里。 所以我的问题是:

  1. 有没有办法在整个文本出现在文本字段之前预览整个文本?
  2. 有没有办法创建更好的JTextField(或它的扩展)?
  3. 有没有办法知道新角色的位置?

【问题讨论】:

    标签: java swing java-15


    【解决方案1】:

    您可以为此使用DocumentFilter

    它允许您在将文本插入文档之前进行编辑。

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class DoubleFilter extends DocumentFilter
    {
        @Override
        public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributes)
            throws BadLocationException
        {
            replace(fb, offset, 0, text, attributes);
        }
    
        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attributes)
            throws BadLocationException
        {
            //  In case someone tries to clear the Document by using setText(null)
    
            if (text == null)
                text = "";
    
            //  Build the text string assuming the replace of the text is successfull
    
            Document doc = fb.getDocument();
            StringBuilder sb = new StringBuilder();
            sb.append(doc.getText(0, doc.getLength()));
            sb.replace(offset, offset + length, text);
    
            if (validReplace(sb.toString()))
                super.replace(fb, offset, length, text, attributes);
            else
                Toolkit.getDefaultToolkit().beep();
        }
    
        private boolean validReplace(String text)
        {
            //  In case setText("") is used to clear the Document
    
            if (text.isEmpty())
                return true;
    
            //  Verify input is a Double
    
            try
            {
                Double.parseDouble( text );
                return true;
            }
            catch (NumberFormatException e)
            {
                return false;
            }
        }
    
        private static void createAndShowGUI()
        {
            JTextField textField = new JTextField(10);
            AbstractDocument doc = (AbstractDocument) textField.getDocument();
            doc.setDocumentFilter( new DoubleFilter() );
            textField.setText("123");
            textField.setText("123567");
            textField.setText(null);
    
            JFrame frame = new JFrame("Integer Filter");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout( new java.awt.GridBagLayout() );
            frame.add( textField );
            frame.setSize(220, 200);
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args) throws Exception
        {
            EventQueue.invokeLater( () -> createAndShowGUI() );
    /*
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowGUI();
                }
            });
    */
        }
    
    }
    

    它并不能满足您的所有需求,但它应该可以帮助您入门。

    【讨论】:

    • 它很有帮助,我从你的回答中得到了很多启发,我会在今天晚些时候发布我所做的。似乎insertString 方法没有做任何事情,如果有,请告诉我:-)
    • @RoyAsh,insertString 方法似乎没有任何作用, 请参阅:stackoverflow.com/questions/23525441/…。我总是实现这两种方法(如演示)以确保我处理所有情况。这允许更多可重用的代码。
    • 我的经验是这样的过滤器会导致不好的用户体验。有时,为了使编辑更简单,需要临时设置无效文本。一个例子是删除整个文本以写入一个全新的数字。不起作用,因为空字符串不是有效数字。或者粘贴我知道之后需要修复的文本。该过滤器不可能,因此我需要在粘贴之前打开第二个编辑器进行修复。除此之外,为什么要重新发明JFormattedTextField
    • @Holger,我仍在尝试各种可能性 :-),此外,我记得我看过它,我注意到有一个格式化程序,名为 NumberFormatter(我可能弄错了它的名字)这并没有给我想要的精度,我认为它可以是 twickable 但我去实现简单的String↔︎double 转换(有点“你看到你得到了什么”),我可能从长远来看,仍然采用JFormattedTextField 选项,这可能是更明智的举措,我需要考虑一下。
    • @Holger,我现在已经试过了,看来它并不能阻止用户插入无法继续有效数字的字符(作为用户类型,而不是在焦点更改时),有没有办法调整它的行为以强制它的行为每个键类型?
    【解决方案2】:

    受@camickr 启发,我对解决方案的看法, 并添加了 2 个方法:getDouble()setDouble()

    import javax.swing.*;
    import javax.swing.text.*;
    import java.util.regex.Pattern;
    
    public class JDoubleField extends JTextField
    {
        private static final DocumentFilter doubleFilter = new DocumentFilter()
        {
            private final Pattern pattern = Pattern.compile("[+-]?(NaN|Infinity|\\d*(\\.\\d*)?((?<=\\d\\.?)[eE][+-]?\\d*)?)");
    
            @Override
            public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException
            {
                replace(fb, offset, 0, string, attr);
            }
    
            @Override
            public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException
            {
                if (text == null || pattern.matcher(new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()))
                        .replace(offset, offset + length, text))
                        .matches())
                    super.replace(fb, offset, length, text, attrs);
            }
        };
    
        public double getDouble()
        {
            try
            {
                return Double.parseDouble(getText());
            } catch (NumberFormatException ignored)
            {
                return Double.NaN;
            }
        }
    
        public void setDouble(double num)
        {
            setText(String.valueOf(num));
        }
    
        public JDoubleField()
        {
            this(0);
        }
    
        public JDoubleField(double num)
        {
            this(String.valueOf(num));
        }
    
        public JDoubleField(double num, int columns)
        {
            this(String.valueOf(num), columns);
        }
    
        public JDoubleField(Document doc, double num, int columns)
        {
            this(doc, String.valueOf(num), columns);
        }
    
        public JDoubleField(int columns)
        {
            this(null, columns);
        }
    
        public JDoubleField(String text)
        {
            this(text, 0);
        }
    
        public JDoubleField(String text, int columns)
        {
            this(null, text, columns);
        }
    
        public JDoubleField(Document doc, String text, int columns)
        {
            super(doc, null, columns);
            ((AbstractDocument) getDocument()).setDocumentFilter(doubleFilter);
            if (text != null)
                setText(text);
        }
    }
    

    【讨论】:

    • 不要扩展 JTextField。仅在向类添加功能时才扩展类。设置 DocumentFilter 不是添加功能。
    • 我想制作一种新类型的文本字段,它具有不同的行为,并且可重复使用,我没有添加功能,我已经更改了它。如果我有很多文本字段并且我不想手动更改它们的行为,我认为扩展 JTextField 更可取
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 2020-07-01
    • 1970-01-01
    • 2019-11-25
    相关资源
    最近更新 更多