【问题标题】:Displaying Currency in JSpinner在 JSpinner 中显示货币
【发布时间】:2020-05-13 18:36:05
【问题描述】:

我为我们公司写了一个小程序,负责饮料的销售,每个用户都有自己的帐户。为了给他的帐户充值,有一个 JSpinner,看起来像这样https://i.imgur.com/qJpPfqR.png。一位员工问我是否可以将货币添加到此微调器中。所以我实现了它,但是现在你只能用货币符号存款而不能没有它,这打扰了其他工作人员,所以让我们来回答我的问题,我如何设法接受有货币和没有货币的条目?

基本微调器(如我在上面发布的图片中):

final SpinnerNumberModel spinnerModel = new SpinnerNumberModel( 1, 1, 1000, 1 );
final JSpinner valueSpinner = new JSpinner( spinnerModel );

为了添加货币,我使用了这个代码 sn-p,效果很好

    String pattern = "0€";
    JSpinner.NumberEditor editor = new JSpinner.NumberEditor( valueSpinner, pattern );
    valueSpinner.setEditor( editor );

我已经尝试编写一个自定义 JSpinner,但我无法实现 Spinner 将同时接受两个条目。

【问题讨论】:

    标签: java swing spinner currency jspinner


    【解决方案1】:

    this 回答有关长度单位的问题后,您可以以类似的方式处理货币:

    import java.text.ParseException;
    import java.util.Objects;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import javax.swing.JButton;
    import javax.swing.JFormattedTextField;
    import javax.swing.JFormattedTextField.AbstractFormatter;
    import javax.swing.JFormattedTextField.AbstractFormatterFactory;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JSpinner;
    import javax.swing.JSpinner.DefaultEditor;
    import javax.swing.SpinnerNumberModel;
    
    public class MainWithFormatter {
    
        //For more currencies and their ISO codes, visit https://en.wikipedia.org/wiki/List_of_circulating_currencies
        public static enum Currency {
            EUR, //Euro
            USD, //United States Dollar
            GBP, //British Pound
            JPY //Japanese Yen
        }
    
        public static class CurrencyFormatter extends AbstractFormatter {
    
            private static final Pattern PATTERN;
    
            static {
                //Building the Pattern is not too tricky. It just needs some attention.
    
                final String blank = "\\p{Blank}"; //Match any whitespace character.
                final String blankGroupAny = "(" + blank + "*)"; //Match any whitespace character, zero or more times and group them.
    
                final String digits = "\\d"; //Match any digit.
                final String digitsGroup = "(" + digits + "+)"; //Match any digit, at least once and group them.
                final String digitsSuperGroup = "(\\-?" + digitsGroup + "\\.?" + digitsGroup + "?)"; //Matches for example "-2.4" or "2.4" or "2" or "-2" in the same group!
    
                //Create the pattern part which matches any of the available currencies...
                final Currency[] currencies = Currency.values();
                final StringBuilder currenciesBuilder = new StringBuilder(Pattern.quote("")); //Empty currency value is valid.
                for (int i = 0; i < currencies.length; ++i)
                    currenciesBuilder.append('|').append(Pattern.quote(currencies[i].name()));
                final String currenciessGroup = "(" + currenciesBuilder + ")";
    
                final String full = "^" + blankGroupAny + digitsSuperGroup + blankGroupAny + currenciessGroup + blankGroupAny + "$"; //Compose full pattern.
    
                PATTERN = Pattern.compile(full);
            }
    
            private final Currency defaultCurrency;
            private Currency lastCurrency;
            private boolean verbose; //Show the default currency while spinning or not?
    
            public CurrencyFormatter(final Currency defaultCurrency) {
                this.defaultCurrency = Objects.requireNonNull(defaultCurrency);
                lastCurrency = defaultCurrency;
                verbose = true;
            }
    
            @Override
            public Object stringToValue(final String text) throws ParseException {
                if (text == null || text.trim().isEmpty())
                    throw new ParseException("Null or empty text.", 0);
                try {
                    final Matcher matcher = PATTERN.matcher(text.toUpperCase());
                    if (!matcher.matches())
                        throw new ParseException("Invalid input.", 0);
                    final String amountStr = matcher.group(2),
                                 currencyStr = matcher.group(6);
                    final double amount = Double.parseDouble(amountStr);
                    if (currencyStr.trim().isEmpty()) {
                        lastCurrency = defaultCurrency;
                        verbose = false;
                    }
                    else {
                        lastCurrency = Currency.valueOf(currencyStr);
                        verbose = true;
                    }
                    return amount;
                }
                catch (final IllegalArgumentException iax) {
                    throw new ParseException("Failed to parse input \"" + text + "\".", 0);
                }
            }
    
            public Currency getLastCurrency() {
                return lastCurrency;
            }
    
            @Override
            public String valueToString(final Object value) throws ParseException {
                final String amount = String.format("%.2f", value).replace(',', '.');
                return verbose ? (amount + ' ' + lastCurrency.name()) : amount;
            }
        }
    
        public static class CurrencyFormatterFactory extends AbstractFormatterFactory {
            @Override
            public AbstractFormatter getFormatter(final JFormattedTextField tf) {
                if (!(tf.getFormatter() instanceof CurrencyFormatter))
                    return new CurrencyFormatter(Currency.USD);
                return tf.getFormatter();
            }
        }
    
        public static void main(final String[] args) {
            final JSpinner spin = new JSpinner(new SpinnerNumberModel(0d, -1000000d, 1000000d, 0.01d));
    
            final JFormattedTextField jftf = ((DefaultEditor) spin.getEditor()).getTextField();
            jftf.setFormatterFactory(new CurrencyFormatterFactory());
    
            //Added a button to demonstrate how to obtain the value the user has selected:
            final JButton check = new JButton("Check!");
            check.addActionListener(e -> {
                final CurrencyFormatter cf = (CurrencyFormatter) jftf.getFormatter();
                JOptionPane.showMessageDialog(check, Objects.toString(spin.getValue()) + ' ' + cf.getLastCurrency().name() + '!');
            });
    
            final JPanel contents = new JPanel(); //FlowLayout.
            contents.add(spin);
            contents.add(check);
    
            final JFrame frame = new JFrame("JSpinner currencies.");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(contents);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    

    您只需为将处理此类字符串的微调器的默认编辑器的格式化文本字段创建一个自定义AbstractFormatter

    虽然您可以简单地通过输入两个JSpinners 来做到这一点,一个用于金额,另一个用于货币。

    编辑 1:或者,您可以使用内置的 java.util.Currency 类:

    import java.text.ParseException;
    import java.util.Currency;
    import java.util.Objects;
    import java.util.Set;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.stream.Collectors;
    import javax.swing.JButton;
    import javax.swing.JFormattedTextField;
    import javax.swing.JFormattedTextField.AbstractFormatter;
    import javax.swing.JFormattedTextField.AbstractFormatterFactory;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JSpinner;
    import javax.swing.JSpinner.DefaultEditor;
    import javax.swing.SpinnerNumberModel;
    
    public class MainWithCurrency {
    
        public static class CurrencyFormatter extends AbstractFormatter {
    
            private static final Pattern PATTERN;
    
            static {
                //Building the Pattern is not too tricky. It just needs some attention.
    
                final String blank = "\\p{Blank}"; //Match any whitespace character.
                final String blankGroupAny = "(" + blank + "*)"; //Match any whitespace character, zero or more times and group them.
    
                final String digits = "\\d"; //Match any digit.
                final String digitsGroup = "(" + digits + "+)"; //Match any digit, at least once and group them.
                final String digitsSuperGroup = "(\\-?" + digitsGroup + "\\.?" + digitsGroup + "?)"; //Matches for example "-2.4" or "2.4" or "2" or "-2" in the same group!
    
                //Create the pattern part which matches any of the available currencies...
                final String currencyCodes = "[A-Z]{3}|" + Pattern.quote(""); //Currency code consists of 3 letters, or is empty for default value.
                final String currenciessGroup = "(" + currencyCodes + ")";
    
                final String full = "^" + blankGroupAny + digitsSuperGroup + blankGroupAny + currenciessGroup + blankGroupAny + "$"; //Compose full pattern.
    
                PATTERN = Pattern.compile(full);
            }
    
            private final Set<String> supportedCurrencies;
            private final String defaultCurrency;
            private String lastCurrency;
            private boolean verbose; //Show the default currency while spinning or not?
    
            public CurrencyFormatter(final Set<Currency> supportedCurrencies,
                                     final Currency defaultCurrency) {
                if (!supportedCurrencies.contains(defaultCurrency))
                    throw new IllegalArgumentException("Default currency is not supported.");
                this.supportedCurrencies = supportedCurrencies.stream().map(currency -> currency.getCurrencyCode()).collect(Collectors.toSet());
                this.defaultCurrency = defaultCurrency.getCurrencyCode();
                lastCurrency = this.defaultCurrency;
                verbose = true;
            }
    
            @Override
            public Object stringToValue(final String text) throws ParseException {
                if (text == null || text.trim().isEmpty())
                    throw new ParseException("Null or empty text.", 0);
                try {
                    final Matcher matcher = PATTERN.matcher(text.toUpperCase());
                    if (!matcher.matches())
                        throw new ParseException("Invalid input.", 0);
                    final String amountStr = matcher.group(2).trim(),
                                 currencyStr = matcher.group(6).trim();
                    final double amount = Double.parseDouble(amountStr);
                    if (currencyStr.isEmpty()) {
                        lastCurrency = defaultCurrency;
                        verbose = false;
                    }
                    else {
                        if (!supportedCurrencies.contains(currencyStr))
                            throw new ParseException("Unsupported currency.", 0);
                        lastCurrency = currencyStr;
                        verbose = true;
                    }
                    return amount;
                }
                catch (final IllegalArgumentException iax) {
                    throw new ParseException("Failed to parse input \"" + text + "\".", 0);
                }
            }
    
            public Currency getLastCurrency() {
                return Currency.getInstance(lastCurrency);
            }
    
            @Override
            public String valueToString(final Object value) throws ParseException {
                final String amount = String.format("%.2f", value).replace(',', '.');
                return verbose ? (amount + ' ' + lastCurrency) : amount;
            }
        }
    
        public static class CurrencyFormatterFactory extends AbstractFormatterFactory {
            @Override
            public AbstractFormatter getFormatter(final JFormattedTextField tf) {
                if (!(tf.getFormatter() instanceof CurrencyFormatter))
                    return new CurrencyFormatter(Currency.getAvailableCurrencies(), Currency.getInstance("USD"));
                return tf.getFormatter();
            }
        }
    
        public static void main(final String[] args) {
            final JSpinner spin = new JSpinner(new SpinnerNumberModel(0d, -1000000d, 1000000d, 0.01d));
    
            final JFormattedTextField jftf = ((DefaultEditor) spin.getEditor()).getTextField();
            jftf.setFormatterFactory(new CurrencyFormatterFactory());
    
            //Added a button to demonstrate how to obtain the value the user has selected:
            final JButton check = new JButton("Check!");
            check.addActionListener(e -> {
                final CurrencyFormatter cf = (CurrencyFormatter) jftf.getFormatter();
                JOptionPane.showMessageDialog(check, Objects.toString(spin.getValue()) + ' ' + cf.getLastCurrency().getCurrencyCode() + '!');
            });
    
            final JPanel contents = new JPanel(); //FlowLayout.
            contents.add(spin);
            contents.add(check);
    
            final JFrame frame = new JFrame("JSpinner currencies.");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(contents);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    

    在此代码(第一次编辑)中,我正在解析货币 ISO 代码,并根据支持货币的 Set 对其进行检查。

    注意:我已阅读 DecimalFormat documentationcorresponding Java Tutorial,但找不到任何有关指定可选货币符号的信息,因此我认为您必须使用自定义 Pattern就像这个答案中前面的示例代码一样,我也在此处发布这些链接,以防其他人在其中找到解决方案。

    【讨论】:

      猜你喜欢
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      相关资源
      最近更新 更多