После этого ответа на вопрос об измерении единиц длины, вы можете сделать это аналогичным образом для валют:
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 ammountStr = matcher.group(2),
currencyStr = matcher.group(6);
final double ammount = Double.parseDouble(ammountStr);
if (currencyStr.trim().isEmpty()) {
lastCurrency = defaultCurrency;
verbose = false;
}
else {
lastCurrency = Currency.valueOf(currencyStr);
verbose = true;
}
return ammount;
}
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 ammount = String.format("%.2f", value).replace(',', '.');
return verbose ? (ammount + ' ' + lastCurrency.name()) : ammount;
}
}
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
s, один для суммы, а другой для валюты.
Редактировать 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 ammountStr = matcher.group(2).trim(),
currencyStr = matcher.group(6).trim();
final double ammount = Double.parseDouble(ammountStr);
if (currencyStr.isEmpty()) {
lastCurrency = defaultCurrency;
verbose = false;
}
else {
if (!supportedCurrencies.contains(currencyStr))
throw new ParseException("Unsupported currency.", 0);
lastCurrency = currencyStr;
verbose = true;
}
return ammount;
}
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 ammount = String.format("%.2f", value).replace(',', '.');
return verbose ? (ammount + ' ' + lastCurrency) : ammount;
}
}
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
документацию и соответствующий Java Tutorial , но не могу найти что-либо об указании необязательных символов валюты, поэтому я думаю, что вам придется работать с пользовательским Pattern
, как в предыдущих примерах кодов в этом ответе, и я также публикую эти ссылки здесь, на случай, если кто-то еще найдет S решение в них.