制作自定义 JTextField (JCurrencyField)

发布于 2024-11-18 02:01:48 字数 4557 浏览 5 评论 0原文

我制作了一个 JCurrencyField 以在我的程序中使用它,我几乎完成了它的创建,但我遇到了一个问题。

JCurrencyField 是一个普通的 JTextField,但它不能接受任何不是数字或小数点 . 的字符,并且我为此 JCurrencyField 做了一些规范:

  • 用户不能插入超过一个小数点 .< /代码>。
  • 用户不能在小数点后插入超过两位的数字。

我遇到的问题是,如果小数点后有两位数字,则无法在小数点前插入任何数字。

这是我的代码:

import javax.swing.*;
import javax.swing.text.*;
public class JCurrencyField extends JTextField
{
    public JCurrencyField()
    {
        ((AbstractDocument)getDocument()).setDocumentFilter(new NumberOnlyFilter());
    }

    private class NumberOnlyFilter extends DocumentFilter
    {
        public void insertString(DocumentFilter.FilterBypass fb, int offset,   
        String text, AttributeSet attr) throws BadLocationException
        {
            if(!containsOnlyNumbers(text)) return;
            fb.insertString(offset, text, attr);   
        }    

        public void replace(DocumentFilter.FilterBypass fb, int offset, int length,   
        String text, AttributeSet attr) throws BadLocationException
        {
            if(!containsOnlyNumbers(text)) return;
            fb.replace(offset, length, text, attr);
        }

        /**
        * This method checks if a String contains only numbers
        */
        public boolean containsOnlyNumbers(String str)
        {

            //It can't contain only numbers if it's null or empty...
            if (str == null || str.length() == 0) return false;


            int counter = 0;
            for(int i = 0; i < getText().length(); i++)
            {
                if(counter > 1) return false;
                if(getText().charAt(i) == '.')
                {
                    counter++;
                }
            }

            int fp_counter = 0;
            int fp_index = -1;
            for(int i = 0; i < str.length(); i++)
            {
                if(counter >= 1) break;
                if(str.charAt(i) == '.')
                {
                    fp_counter++;
                    fp_index = i;
                }
            }

            if(fp_counter > 1) return false;

            if(str.length() > fp_index + 3) return false;

            if(counter >= 1)
            {
                for(int i = 0; i < getText().length(); i++)
                {
                    if(getText().charAt(i) == '.') counter++;
                }
            }

            for (int j = 0; j < str.length(); j++)
            {
                if(counter >= 1 && (str.charAt(j) == '.')) return false;
            }

            int index = 0;
            boolean fp_Flag = false;
            int sp_count = 0;
            for(int k = 0; k < getText().length(); k++)
            {
                if(getText().charAt(k) == '.')
                {
                    index = k;
                    fp_Flag = true;
                }
                if(fp_Flag) sp_count++;
                if(sp_count > 2) return false;
            }

            //if(fp_Flag && str.length() > 2) return false;
            if(fp_Flag && index + 1 < getText().length() && str.length() > 1) return false;
            //if(index + 2 < getText().length() && fp_Flag) return false;


            for (int l = 0; l < str.length(); l++)
            {

                //If we find a non-digit character we return false.
                if(str.charAt(l) == '.') continue;
                if(!Character.isDigit(str.charAt(l)))
                return false;
            }

            return true;
        }
    }
}

测试程序:

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JFrame

{
    private JCurrencyField txt = new JCurrencyField();
    public Test()
    {
        super("Test...");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        try{ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
        catch(Exception e){ System.out.println("Unable to load Windows look and feel");}
        setPreferredSize(new Dimension(300, 100));
        ((JPanel) getContentPane()).setBorder(new EmptyBorder(13, 13, 13, 13) );
        setLayout(new FlowLayout());
        txt.setPreferredSize(new Dimension(100,30));
        add(txt);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        setResizable(false);
    }
    public static void main(String[] args)
    {
        new Test();
    }
}

你能帮我解决这个问题吗?

I making a JCurrencyField to use it in my program, I almost finished creating it but I've faced an issue.

JCurrencyField is a normal JTextField but it cannot accept any character that is not a number or decimal point . and I made some specifications for this JCurrencyField:

  • The user cannot insert more than one decimal point ..
  • The user cannot insert more than two digits after the decimal point.

The issue I've faced was not being able to insert any digits before the decimal point if there are two digits after the decimal point.

Here is my code:

import javax.swing.*;
import javax.swing.text.*;
public class JCurrencyField extends JTextField
{
    public JCurrencyField()
    {
        ((AbstractDocument)getDocument()).setDocumentFilter(new NumberOnlyFilter());
    }

    private class NumberOnlyFilter extends DocumentFilter
    {
        public void insertString(DocumentFilter.FilterBypass fb, int offset,   
        String text, AttributeSet attr) throws BadLocationException
        {
            if(!containsOnlyNumbers(text)) return;
            fb.insertString(offset, text, attr);   
        }    

        public void replace(DocumentFilter.FilterBypass fb, int offset, int length,   
        String text, AttributeSet attr) throws BadLocationException
        {
            if(!containsOnlyNumbers(text)) return;
            fb.replace(offset, length, text, attr);
        }

        /**
        * This method checks if a String contains only numbers
        */
        public boolean containsOnlyNumbers(String str)
        {

            //It can't contain only numbers if it's null or empty...
            if (str == null || str.length() == 0) return false;


            int counter = 0;
            for(int i = 0; i < getText().length(); i++)
            {
                if(counter > 1) return false;
                if(getText().charAt(i) == '.')
                {
                    counter++;
                }
            }

            int fp_counter = 0;
            int fp_index = -1;
            for(int i = 0; i < str.length(); i++)
            {
                if(counter >= 1) break;
                if(str.charAt(i) == '.')
                {
                    fp_counter++;
                    fp_index = i;
                }
            }

            if(fp_counter > 1) return false;

            if(str.length() > fp_index + 3) return false;

            if(counter >= 1)
            {
                for(int i = 0; i < getText().length(); i++)
                {
                    if(getText().charAt(i) == '.') counter++;
                }
            }

            for (int j = 0; j < str.length(); j++)
            {
                if(counter >= 1 && (str.charAt(j) == '.')) return false;
            }

            int index = 0;
            boolean fp_Flag = false;
            int sp_count = 0;
            for(int k = 0; k < getText().length(); k++)
            {
                if(getText().charAt(k) == '.')
                {
                    index = k;
                    fp_Flag = true;
                }
                if(fp_Flag) sp_count++;
                if(sp_count > 2) return false;
            }

            //if(fp_Flag && str.length() > 2) return false;
            if(fp_Flag && index + 1 < getText().length() && str.length() > 1) return false;
            //if(index + 2 < getText().length() && fp_Flag) return false;


            for (int l = 0; l < str.length(); l++)
            {

                //If we find a non-digit character we return false.
                if(str.charAt(l) == '.') continue;
                if(!Character.isDigit(str.charAt(l)))
                return false;
            }

            return true;
        }
    }
}

Test Program:

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JFrame

{
    private JCurrencyField txt = new JCurrencyField();
    public Test()
    {
        super("Test...");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        try{ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
        catch(Exception e){ System.out.println("Unable to load Windows look and feel");}
        setPreferredSize(new Dimension(300, 100));
        ((JPanel) getContentPane()).setBorder(new EmptyBorder(13, 13, 13, 13) );
        setLayout(new FlowLayout());
        txt.setPreferredSize(new Dimension(100,30));
        add(txt);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        setResizable(false);
    }
    public static void main(String[] args)
    {
        new Test();
    }
}

could you please help me to solve this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

顾忌 2024-11-25 02:01:48

最好将 JFormattedTextFieldNumberFormat 一起使用
java.text.NumberFormat#getCurrencyInstance()

it's better to use JFormattedTextField with NumberFormat
java.text.NumberFormat#getCurrencyInstance()

千柳 2024-11-25 02:01:48

您在 DocumentFilter 中测试了错误的字符串。

您不应该测试文本字符串,而应该测试从 FilterBypass 参数获取的文本和文档构建的字符串,因为这是您想要查看它是否满足条件的字符串。例如,不是这个:

    public void insertString(DocumentFilter.FilterBypass fb, int offset,   
    String text, AttributeSet attr) throws BadLocationException
    {
        if(!containsOnlyNumbers(text)) return;
        fb.insertString(offset, text, attr);   
    }    

    public void replace(DocumentFilter.FilterBypass fb, int offset, int length,   
    String text, AttributeSet attr) throws BadLocationException
    {
        if(!containsOnlyNumbers(text)) return;
        fb.replace(offset, length, text, attr);
    }

而是这个:

   private class NumberOnlyFilter extends DocumentFilter {
      public void insertString(DocumentFilter.FilterBypass fb, int offset,
               String text, AttributeSet attr) throws BadLocationException {
         StringBuilder sb = new StringBuilder();
         sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
         sb.insert(offset, text);
         if (!containsOnlyNumbers(sb.toString()))
            return;
         fb.insertString(offset, text, attr);
      }

      public void replace(DocumentFilter.FilterBypass fb, int offset,
               int length, String text, AttributeSet attr)
               throws BadLocationException {
         StringBuilder sb = new StringBuilder();
         sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
         sb.replace(offset, offset + length, text);
         if (!containsOnlyNumbers(sb.toString()))
            return;
         fb.replace(offset, length, text, attr);
      }

您将需要对 containsOnlyNumbers 方法进行更改以适应这些更改。

编辑 1
这可以使用 toto 的正则表达式轻松完成:

  private boolean containsOnlyNumbers(String text) {
     Pattern pattern = Pattern.compile("\\d*(\\.\\d{0,2})?");
     Matcher matcher = pattern.matcher(text);
     boolean isMatch = matcher.matches();
     return isMatch;
  }

You're testing the wrong string in your DocumentFilter.

You shouldn't be testing the text String but rather the String built from text and Document obtained from the FilterBypass parameter since this is the String that you want to see if it fulfills the criteria. For instance, not this:

    public void insertString(DocumentFilter.FilterBypass fb, int offset,   
    String text, AttributeSet attr) throws BadLocationException
    {
        if(!containsOnlyNumbers(text)) return;
        fb.insertString(offset, text, attr);   
    }    

    public void replace(DocumentFilter.FilterBypass fb, int offset, int length,   
    String text, AttributeSet attr) throws BadLocationException
    {
        if(!containsOnlyNumbers(text)) return;
        fb.replace(offset, length, text, attr);
    }

But rather this:

   private class NumberOnlyFilter extends DocumentFilter {
      public void insertString(DocumentFilter.FilterBypass fb, int offset,
               String text, AttributeSet attr) throws BadLocationException {
         StringBuilder sb = new StringBuilder();
         sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
         sb.insert(offset, text);
         if (!containsOnlyNumbers(sb.toString()))
            return;
         fb.insertString(offset, text, attr);
      }

      public void replace(DocumentFilter.FilterBypass fb, int offset,
               int length, String text, AttributeSet attr)
               throws BadLocationException {
         StringBuilder sb = new StringBuilder();
         sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
         sb.replace(offset, offset + length, text);
         if (!containsOnlyNumbers(sb.toString()))
            return;
         fb.replace(offset, length, text, attr);
      }

You will need to make changes to your containsOnlyNumbers method to account for these changes.

Edit 1
And this can be easily done using toto's regex:

  private boolean containsOnlyNumbers(String text) {
     Pattern pattern = Pattern.compile("\\d*(\\.\\d{0,2})?");
     Matcher matcher = pattern.matcher(text);
     boolean isMatch = matcher.matches();
     return isMatch;
  }
夏尔 2024-11-25 02:01:48

以下 正则表达式 应该有效:

Pattern pattern = Pattern.compile("\\d*(\\.\\d{0,2})?");
Matcher matcher = pattern.matcher(text);
boolean isMatch = matcher.matches();
if (isMatch) 
  value = Double.parseDouble(text);

但是它还会匹配空字符串,因此如果不匹配,则必须单独检查。 (我不知道 parseDouble 是否为空字符串返回 0。)

编辑:@mkorbel 关于使用 java.swing.text.NumberFormatter< 的评论/code> 和 java.text.NumberFormat 是比我更好的解决方案。您可能会将代码缩小约 100 倍……这就是当您了解库时会发生的情况。

The following regex should work:

Pattern pattern = Pattern.compile("\\d*(\\.\\d{0,2})?");
Matcher matcher = pattern.matcher(text);
boolean isMatch = matcher.matches();
if (isMatch) 
  value = Double.parseDouble(text);

However it would also match the empty string, so you have to check for that separately, if you don't it. (I don't know if parseDouble returns 0 for an empty string.)

EDIT: the comment of @mkorbel about using java.swing.text.NumberFormatter with java.text.NumberFormat is a better solution than mine. You'll probably shrink your code by a factor ~100... that's what happens when you know your libraries.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文