简体   繁体   English

Java:语言环境是否会影响JFormattedTextField的格式化程序

[英]Java : Does Locale affect the Formatter for JFormattedTextField

I have created a custom component (NumberFormattedTextField) of JFormattedTextField. 我创建了JFormattedTextField的自定义组件(NumberFormattedTextField)。 This is the Formatter I use : 这是我使用的格式化程序:

    public static InternationalFormatter getDecimalIFormatter92() {
    // For Buy & Sale Price
    DecimalFormat numberFormat = (DecimalFormat) DecimalFormat.getNumberInstance();
    numberFormat.setMaximumFractionDigits(2);
    numberFormat.setMinimumFractionDigits(2);
    numberFormat.setRoundingMode(RoundingMode.HALF_UP);
    numberFormat.setGroupingUsed(false);

    final InternationalFormatter formatter = new InternationalFormatter(numberFormat);
    formatter.setAllowsInvalid(false);
    formatter.setMinimum(0.00);
    formatter.setMaximum(999999999.99);

    return formatter;
}

When I create an instance of NumberFormattedTextField : 当我创建NumberFormattedTextField的实例时:

 public RelationsPanel(CashParent parent) {
    try {
    initComponents();   // startBalTxt = new NumberFormattedTextField();
    Utility.logInfo("initComponents OVER");
    myParent = parent;
    nameTxt.setSizeLimit(20);
    System.out.println("startBalTxt.setFormatter GOING FOR IT"); 
    this.startBalTxt.setFormatter(Utility.getDecimalIFormatter82());  // Must be throwing here
    System.out.println("startBalTxt.setFormatter DONE"); 
    this.currentBalTxt.setFormatter(Utility.getDecimalIFormatter82());
    } catch (Exception e) {
        Utility.logInfo("Failed to Initialize : " + e.getMessage());
        e.printStackTrace();
    }
}

NumberFormattedTextField CLASS Code : NumberFormattedTextField CLASS代码:

public class NumberFormattedTextField extends JFormattedTextField implements java.io.Serializable, DocumentListener, FocusListener {
private DecimalFormat numberFormat;
private InternationalFormatter formatter;
private double MAX_VALUE = 999999.99;
private final Map attributes = (Utility.getTextFont()).getAttributes();

/**
 * Creates a NumberFormattedTextField with 6 Integer & 2 Fractional digits.
 * Minimum is set to 0.00 and Max to 999999.99 without any grouping used.
 */
public NumberFormattedTextField() {
    super();
    createFormatter();  // Creates a default formatter, used if formatter is not set
    this.setValue(0.00);
    init();
}


private void createFormatter() {
    // Create standard DecimalFormat
    numberFormat = (DecimalFormat) DecimalFormat.getNumberInstance();
    numberFormat.setMaximumFractionDigits(2);
    numberFormat.setMinimumFractionDigits(2);
    numberFormat.setRoundingMode(RoundingMode.HALF_UP);
    numberFormat.setGroupingUsed(false);

    formatter = new InternationalFormatter(numberFormat);
    formatter.setAllowsInvalid(false);
    formatter.setMinimum(0.00);
    formatter.setMaximum(999999.99);

    this.setFormatterFactory(new AbstractFormatterFactoryImpl());
}

private void init() {
    setFont(Utility.getTextFont());
    this.getDocument().addDocumentListener(this);
    this.addFocusListener(this);
    attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
    setFocusLostBehavior(PERSIST);
}

public void setFormatter(InternationalFormatter format) {
    super.setFormatter(format);
    System.out.println("Class of Format = " + format.getFormat().getClass());
    if (format.getFormat() instanceof java.text.DecimalFormat)
        numberFormat = (DecimalFormat)format.getFormat();
    else
        numberFormat = (DecimalFormat)(NumberFormat) format.getFormat();

    formatter = format;
    // AbstractFormatterFactoryImpl returns formatter straight away    
    this.setFormatterFactory(new AbstractFormatterFactoryImpl());
    calculateMaxValue();
}

private void calculateMaxValue() {
    try {
        if (formatter.getMaximum() != null) {
            //System.out.println(" MAX ALlowed = " + formatter.getMaximum());
            String no = formatter.valueToString(formatter.getMaximum());
            char seperator = java.text.DecimalFormatSymbols.getInstance().getGroupingSeparator();
            no = no.replace(String.valueOf(seperator), "");
            System.out.println("MAX Number to PArse = " + no);
            MAX_VALUE = Double.parseDouble(no);  // HERE ITS THROWING EXCEPTION
        }
    } catch (ParseException ex) {
        Logger.getLogger(NumberFormattedTextField.class.getName()).log(Level.SEVERE, null, ex);
    }
}

The above code on my PC works perfectly well. 我的PC上的上述代码运行良好。 But on client's PC it gives error : Failed to Initialize : For input string: "99999999,99" ERROR/Logs that I GET : 但是在客户端的PC上,它给出错误:无法初始化:对于输入字符串:“ 99999999,99”错误/我得到的日志:

      startBalTxt.setFormatter GOING FOR IT
  INFO: initComponents OVER
  Class of Format = class java.text.DecimalFormat
  MAX Number to PArse = 99999999,99
  INFO: Failed to Initialize : For input string: "99999999,99"
  java.lang.NumberFormatException: For input string: "99999999,99"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
    at java.lang.Double.parseDouble(Double.java:540)
    at cashaccountingapp.components.NumberFormattedTextField.calculateMaxValue(NumberFormattedTextField.java:184)
 Class of Format = class java.text.DecimalFormat
    at cashaccountingapp.components.NumberFormattedTextField.setFormatter(NumberFormattedTextField.java:173)
    at cashaccountingapp.data.RelationsPanel.<init>(RelationsPanel.java:35)

The locale of both of us are different. 我们俩的语言环境不同。

What can be the reason for this error ? 发生此错误的原因可能是什么? Different Locale or something else that I need to take care in my NumberFormattedTextField class. 我的NumberFormattedTextField类中有其他语言环境或其他需要注意的地方。 I want app to adapt the system settings and show accordingly. 我希望应用程序适应系统设置并相应显示。

How to handle out the problem ?? 如何解决这个问题?

most probably (can't be entirely sure, as you don't show the intial setting and crippled the error to its message only ;-) different Locales are the reason: one has the period as decimal point, the other has the comma. 很有可能是(不能完全确定,因为您没有显示初始设置并将错误仅破坏其消息;-)不同的语言环境是原因:一个以句点为小数点,另一个以逗号表示。 So if you initialize the one with a String representing the number in the other, it will clash: the comma is not interpreted as a decimal separator, so the max is too big to fit the limits 因此,如果用一个表示另一个数字的String初始化一个,则会发生冲突:逗号不解释为小数点分隔符,因此最大值太大而无法满足限制

Got the solution : 得到了解决方案:

I get the DecimalFormatSymbols instance of Locale.US specifically. 我专门得到Locale.US的DecimalFormatSymbols实例。 This helps me get the string in standard format with proper decimal seperator. 这有助于我使用适当的十进制分隔符以标准格式获取字符串。 And thus am able to parse the valid string to Double. 从而能够将有效字符串解析为Double。 Here is the code I changed, if at all it may help any body : 这是我更改的代码,如果有帮助的话:

    private void calculateMaxValue() {
    try {
        if (formatter.getMaximum() != null) {
            String no = formatter.valueToString(formatter.getMaximum());
            // Get DecimalFormatSymbols instance of Locale.US
            char seperator = java.text.DecimalFormatSymbols.getInstance(java.util.Locale.US).getGroupingSeparator();
            no = no.replace(String.valueOf(seperator), "");
            MAX_VALUE = Double.parseDouble(no);
        }
    } catch (ParseException ex) {
        Utility.logs.log(Level.SEVERE, null, ex);
    }
}

That's it, no other changes were required. 就是这样,不需要其他更改。

Thanks. 谢谢。

After two hours of googling and making some changes, I get a simpler solution, to accept only dot(.) as decimal separator in a JFormattedTextField : 经过两个小时的谷歌搜索并进行了一些更改之后,我得到了一个更简单的解决方案,只接受点(。)作为JFormattedTextField小数点分隔符:

JFormattedTextField txtTax = new javax.swing.JFormattedTextField();
txtTax.setFormatterFactory(new DefaultFormatterFactory(new NumberFormatter(new DecimalFormat("#,##0.00", new DecimalFormatSymbols(new Locale("us", "EN"))))));

This solution ignores System locale(ec,ES) and sets the component a specific locale (us,EN) 此解决方案忽略系统locale(ec,ES)并将组件设置为特定区域设置(us,EN)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM