我为我们公司写了一个小程序,负责饮料的销售,每个用户都有自己的帐户。为了给他的帐户充值,有一个 JSpinner,如下所示:
一名员工问我是否可以将货币添加到此旋转器中。所以我实现了它,但现在你只能用货币符号存款,而不能用货币符号存款,这打扰了其他工作人员,所以让我们来回答我的问题,我如何才能同时接受带货币和不带货币的条目?
基本微调器(如我上面发布的图片所示):
final SpinnerNumberModel spinnerModel = new SpinnerNumberModel( 1, 1, 1000, 1 );
final JSpinner valueSpinner = new JSpinner( spinnerModel );
为了添加货币,我使用了这个代码片段,效果很好
String pattern = "0€";
JSpinner.NumberEditor editor = new JSpinner.NumberEditor( valueSpinner, pattern );
valueSpinner.setEditor( editor );
我已经尝试编写一个自定义 JSpinner,但我无法实现 Spinner 接受两个条目。
最佳答案
已关注 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
即可处理此类字符串。
尽管您可以简单地通过放置两个 JSpinner
来完成此操作,一个用于金额,另一个用于货币。
编辑 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
documentation和 corresponding Java Tutorial ,但找不到有关指定可选货币符号的任何内容,因此我认为您必须使用自定义 Pattern
(如本答案中的前面的示例代码),我还在此处发布了这些链接,位于如果其他人在其中找到了解决方案。
关于java - 在 JSpinner 中显示货币,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59947168/