|
We already mentioned how number and currency formatting is highly locale dependent. The Java programming language supplies a collection of formatter objects that can format and parse numeric values in the java.text class. You go through the following steps to format a number for a particular locale.
The factory methods are static methods of the NumberFormat class that take a Locale argument. There are three factory methods: getNumberInstance, getCurrencyInstance, and getPercentInstance. These methods return objects that can format and parse numbers, currency amounts, and percentages, respectively. For example, here is how you can format a currency value in German. Locale loc = new Locale("de", "DE"); NumberFormat currFmt = NumberFormat.getCurrencyInstance(loc); double amt = 123456.78; System.out.println(currFmt.format(amt)); This code prints 123.456,78 DM Note that the currency symbol is DM and that it is placed at the end of the string. Also, note the reversal of decimal points and decimal commas. Conversely, to read in a number that was entered or stored with the conventions of a certain locale, use the parse method. For example, the following code parses the value that the user typed into a text field. The parse method can deal with decimal points and commas, as well as digits in other languages. TextField inputField; . . . NumberFormat fmt = NumberFormat.getNumberInstance(); // get number formatter for default locale Number input = fmt.parse(inputField.getText().trim()); double x = input.doubleValue(); The return type of parse is the abstract type Number. The returned object is either a Double or a Long wrapper object, depending on whether the parsed number was a floating-point number. If you don't care about the distinction, you can simply use the doubleValue method of the Number class to retrieve the wrapped number. CAUTION
If the text for the number is not in the correct form, the method throws a ParseException. For example, leading whitespace in the string is not allowed. (Call trim to remove it.) However, any characters that follow the number in the string are simply ignored, so no exception is thrown. Note that the classes returned by the getXxxInstance factory methods are not actually of type NumberFormat. The NumberFormat type is an abstract class, and the actual formatters belong to one of its subclasses. The factory methods merely know how to locate the object that belongs to a particular locale. You can get a list of the currently supported locales with the static getAvailableLocales method. That method returns an array of the locales for which number formatter objects can be obtained. The sample program for this section lets you experiment with number formatters (see Figure 10-1). The combo box at the top of the figure contains all locales with number formatters. You can choose between number, currency, and percentage formatters. Each time you make another choice, the number in the text field is reformatted. If you go through a few locales, then you get a good impression of how many ways a number or currency value can be formatted. You can also type a different number and click the Parse button to call the parse method, which tries to parse what you entered. If your input is successfully parsed, then it is passed to format and the result is displayed. If parsing fails, then a "Parse error" message is displayed in the text field. Figure 10-1. The NumberFormatTest programThe code, shown in Example 10-1, is fairly straightforward. In the constructor, we call NumberFormat.getAvailableLocales. For each locale, we call geTDisplayName, and we fill a combo box with the strings that the geTDisplayName method returns. (The strings are not sorted; we tackle this issue with a custom combo box later in this chapter.) Whenever the user selects another locale or clicks on one of the radio buttons, we create a new formatter object and update the text field. When the user clicks on the Parse button, we call the parse method to do the actual parsing, based on the locale selected. Example 10-1. NumberFormatTest.java1. import java.awt.*; 2. import java.awt.event.*; 3. import java.text.*; 4. import java.util.*; 5. import javax.swing.*; 6. 7. /** 8. This program demonstrates formatting numbers under 9. various locales. 10. */ 11. public class NumberFormatTest 12. { 13. public static void main(String[] args) 14. { 15. JFrame frame = new NumberFormatFrame(); 16. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 17. frame.setVisible(true); 18. } 19. } 20. 21. /** 22. This frame contains radio buttons to select a number format, 23. a combo box to pick a locale, a text field to display 24. a formatted number, and a button to parse the text field 25. contents. 26. */ 27. class NumberFormatFrame extends JFrame 28. { 29. public NumberFormatFrame() 30. { 31. setTitle("NumberFormatTest"); 32. setLayout(new GridBagLayout()); 33. 34. ActionListener listener = new 35. ActionListener() 36. { 37. public void actionPerformed(ActionEvent event) { updateDisplay(); } 38. }; 39. 40. JPanel p = new JPanel(); 41. addRadioButton(p, numberRadioButton, rbGroup, listener); 42. addRadioButton(p, currencyRadioButton, rbGroup, listener); 43. addRadioButton(p, percentRadioButton, rbGroup, listener); 44. 45. add(new JLabel("Locale:"), new GBC(0, 0).setAnchor(GBC.EAST)); 46. add(p, new GBC(1, 1)); 47. add(parseButton, new GBC(0, 2).setInsets(2)); 48. add(localeCombo, new GBC(1, 0).setAnchor(GBC.WEST)); 49. add(numberText, new GBC(1, 2).setFill(GBC.HORIZONTAL)); 50. locales = NumberFormat.getAvailableLocales(); 51. for (Locale loc : locales) localeCombo.addItem(loc.getDisplayName()); 52. localeCombo.setSelectedItem(Locale.getDefault().getDisplayName()); 53. currentNumber = 123456.78; 54. updateDisplay(); 55. 56. localeCombo.addActionListener(listener); 57. 58. parseButton.addActionListener(new 59. ActionListener() 60. { 61. public void actionPerformed(ActionEvent event) 62. { 63. String s = numberText.getText().trim(); 64. try 65. { 66. Number n = currentNumberFormat.parse(s); 67. if (n != null) 68. { 69. currentNumber = n.doubleValue(); 70. updateDisplay(); 71. } 72. else 73. { 74. numberText.setText("Parse error: " + s); 75. } 76. } 77. catch (ParseException e) 78. { 79. numberText.setText("Parse error: " + s); 80. } 81. } 82. }); 83. pack(); 84. } 85. 86. /** 87. Adds a radio button to a container. 88. @param p the container into which to place the button 89. @param b the button 90. @param g the button group 91. @param listener the button listener 92. */ 93. public void addRadioButton(Container p, JRadioButton b, 94. ButtonGroup g, ActionListener listener) 95. { 96. b.setSelected(g.getButtonCount() == 0); 97. b.addActionListener(listener); 98. g.add(b); 99. p.add(b); 100. } 101. 102. /** 103. Updates the display and formats the number according 104. to the user settings. 105. */ 106. public void updateDisplay() 107. { 108. Locale currentLocale = locales[localeCombo.getSelectedIndex()]; 109. currentNumberFormat = null; 110. if (numberRadioButton.isSelected()) 111. currentNumberFormat = NumberFormat.getNumberInstance(currentLocale); 112. else if (currencyRadioButton.isSelected()) 113. currentNumberFormat = NumberFormat.getCurrencyInstance(currentLocale); 114. else if (percentRadioButton.isSelected()) 115. currentNumberFormat = NumberFormat.getPercentInstance(currentLocale); 116. String n = currentNumberFormat.format(currentNumber); 117. numberText.setText(n); 118. } 119. 120. private Locale[] locales; 121. private double currentNumber; 122. private JComboBox localeCombo = new JComboBox(); 123. private JButton parseButton = new JButton("Parse"); 124. private JTextField numberText = new JTextField(30); 125. private JRadioButton numberRadioButton = new JRadioButton("Number"); 126. private JRadioButton currencyRadioButton = new JRadioButton("Currency"); 127. private JRadioButton percentRadioButton = new JRadioButton("Percent"); 128. private ButtonGroup rbGroup = new ButtonGroup(); 129. private NumberFormat currentNumberFormat; 130. } java.text.NumberFormat 1.1
CurrenciesTo format a currency value, you can use the NumberFormat.getCurrencyInstance method. However, that method is not very flexibleit returns a formatter for a single currency. Suppose you prepare an invoice for an American customer in which some amounts are in dollars, and others in Euros. You can't just use two formatters NumberFormat dollarFormatter = NumberFormat.getCurrencyInstance(Locale.US); NumberFormat euroFormatter = NumberFormat.getCurrencyInstance(Locale.GERMANY); Your invoice would look very strange, with some values formatted like $100,000 and others like 100.000 . (Note that the Euro value uses a decimal point, not a comma.) Instead, use the Currency class to control the currency that is used by the formatters. You get a Currency object by passing a currency identifier to the static Currency.getInstance method. Then call the setCurrency method for each formatter. Here is how you would set up the Euro formatter for your American customer: NumberFormat euroFormatter = NumberFormat.getCurrencyInstance(Locale.US); euroFormatter.setCurrency(Currency.getInstance("EUR")); The currency identifiers are defined by ISO 4217see http://en.wikipedia.org/wiki/ISO_4217 for a list. Table 10-3 provides a partial list. (The official maintainer of the standard charges £70 for this informationsee http://www.bsi-global.com/Technical+Information/Publications/_Publications/tig90.xalter.) java.util.Currency 1.4
|
|