Then pass the resulting RowSorter to JTable’s public void setRowSorterRowSorter... If you explicitly attach a Comparatorto a column via public void setComparatorint column, Comparator co
Trang 1• Its abstract javax.swing.DefaultRowSorter<M, I>subclass, which supports sortingand filtering around a grid-based data model
• The DefaultRowSorter<M, I>’s javax.swing.table.TableRowSorter<M extends TableModel>subclass, which provides table component sorting and filtering via a javax.swing.table.TableModel
It is easy to introduce sorting to a table component After creating the table’s model and initializing the table component with this model, pass the model to
TableRowSorter<M extends TableModel>’s constructor Then pass the resulting RowSorter<M>
to JTable’s public void setRowSorter(RowSorter<? extends TableModel> sorter)method:TableModel model =
JTable table = new JTable (model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel> (model);
table.setRowSorter (sorter);
To demonstrate how easy it is to add sorting to your tables, I have designed a simpleapplication that itemizes some grocery items and their prices in a two-column table.Listing 4-3 presents the source code
{ "Bag of potatoes", 10.98 },{ "Magazine", 7.99 },
Trang 2{ "Can of soup", 0.89 },{ "DVD movie", 39.99 }};
TableModel model = new DefaultTableModel (rows, columns);
JTable table = new JTable (model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel> (model);
new PriceList1 ("Price List #1");
}};
java.awt.EventQueue.invokeLater (r);
}}
Run this application, and you will see output similar to the table shown in Figure 4-3
Figure 4-3.Unsorted table
Click the Item column’s header, and the rows will sort in ascending order of this column’s values A small up triangle will appear beside the column name to identify
the current sort direction, as shown in Figure 4-4
Trang 3Figure 4-4.Sorted table based on the Item column
Suppose that you decide to sort the items in ascending order of price (smallest priceitem first) After clicking the Price column’s header, a small up triangle appears beside the column name However, as Figure 4-5 indicates, the sort result is unexpected
Figure 4-5.Prices are sorted based on string comparisons.
The prices are not sorted based on their numerical values If they were, the row taining DVD movie and 39.99 would be the last row in the table Instead, rows have beensorted based on the string representations of the price values
con-According to the JDK documentation for the TableRowSorter<M extends TableModel>class, java.util.Comparator<T>comparators are used to compare objects during a sort.The Comparator<T>comparator that is chosen is based on five rules, which I have
excerpted (with minor additions) from the documentation (in the top-down order inwhich the decision is made):
• If a Comparator<T>has been specified for the column by the setComparatormethod,use it
• If the column class as returned by getColumnClassis String, use the Comparator<T>returned by Collator.getInstance()
• If the column class implements Comparable<T>, use a Comparator<T>that invokes thecompareTomethod
Trang 4• If a javax.swing.table.TableStringConverterhas been specified, use it to convert thevalues to Strings and then use the Comparator<T>returned by Collator.getInstance().
• Otherwise, use the Comparator<T>returned by Collator.getInstance()on the results from calling toStringon the objects
If you explicitly attach a Comparator<T>to a column via public void setComparator(int column, Comparator<?> comparator), this Comparator<T>will
be used during the sort (as indicated by the first rule) In contrast, it is easier to
subclass javax.swing.table.DefaultTableModeland override the public Class
getColumnClass(int column)method, which is what Listing 4-4 accomplishes
{ "Bag of potatoes", 10.98 },{ "Magazine", 7.99 },
{ "Can of soup", 0.89 },{ "DVD movie", 39.99 }};
TableModel model = new DefaultTableModel (rows, columns)
{
public Class getColumnClass (int column) {
if (column >= 0 &&
Trang 5column <= getColumnCount ()) return getValueAt (0, column).getClass (); else
return Object.class;
}
};
JTable table = new JTable (model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel> (model);table.setRowSorter (sorter);
getContentPane ().add (new JScrollPane (table));
setSize (200, 150);
setVisible (true);
}public static void main (String [] args){
Runnable r = new Runnable ()
{public void run (){
new PriceList2 ("Price List #2");
}};
java.awt.EventQueue.invokeLater (r);
}}
DefaultTableModelalways returns Object.classfrom its getColumnClass()method.According to the fifth rule, this results in the toString()method being called during sorting (and the result shown previously in Figure 4-5) By overriding getColumnClass()and having the overridden method return the appropriate type, sorting takes advantage
of the returned Classobject’s Comparable<T>(if there is one), according to the third rule.Figure 4-6 shows the properly sorted price list
Trang 6Figure 4-6.The DVD movie item is now displayed in the last row, where it should be based
on its price.
■ Tip JTable’s public void setAutoCreateRowSorter(boolean autoCreateRowSorter)method
offers the simplest way to attach a row sorter to a table component For more information about this
method, check out “Mustang (Java SE 6) Gallops into Town” (http://www.informit.com/articles/
article.asp?p=661371&rl=1)
Filtering the Table’s Rows
The DefaultRowSorter<M, I>class provides a public void setRowFilter(RowFilter<? super
M,? super I> filter)method for installing a filter that lets you determine which rows are
displayed and which rows are hidden You can pass to filteran instance of one of the
filters returned from the static methods in the abstract javax.swing.RowFilter<M, I>class,
or pass nullto remove any installed filter and allow all rows to be displayed Table 4-2
shows RowFilter’s filter factory methods
Table 4-2.RowFilter Filter Factory Methods
public static <M,I> RowFilter<M,I> Returns a row filter that includes a row if all
andFilter(Iterable<? extends RowFilter<? of the specified row filters include the row.
super M,? super I>> filters)
public static <M,I> RowFilter<M,I> Returns a row filter that includes only those rows
dateFilter(RowFilter.ComparisonType that have at least one java.util.Date value in
type, Date date, int indices) the indices columns that meets the criteria
specified by type If the indices argument is not specified, all columns are checked.
public static <M,I> RowFilter<M,I> Returns a row filter that includes a row if the
notFilter(RowFilter<M,I> filter) specified row filter does not include the row.
public static <M,I> RowFilter<M,I> Returns a row filter that includes only those rows
numberFilter(RowFilter.ComparisonType type, that have at least one Number value in the
Number number, int indices) indices columns that meets the criteria
specified by type If the indices argument is not specified, all columns are checked.
Continued
Trang 7public static <M,I> RowFilter<M,I> Returns a row filter that includes a row if any of orFilter(Iterable<? extends the specified row filters include the row RowFilter<? super M,? super I>> filters)
public static <M,I> RowFilter<M,I> Returns a row filter that uses a regular expression regexFilter(String regex, int indices) to determine which rows to include Each
column identified by indices is checked The row is returned if one of the column values matches the regex If the indices argument is not specified, all columns are checked.
Row filtering is useful in the context of a database application Rather than submit
a potentially expensive SQL SELECTstatement to the database management system toretrieve a subset of a table’s rows based on some criteria, filtering rows via a table compo-nent and its row filter is bound to be much faster For example, suppose your table
component presents a log of bugs (bug identifier, description, date filed, and dated fixed)found while testing software Furthermore, suppose that you want to present only thoserows whose description matches some entered regular expression Listing 4-5 presents anapplication that accomplishes this task
private static DateFormat df;
public BugLog (String title) throws ParseException
Table 4-2.Continued
Trang 8{super (title);
{ 1000, "Crash during file read", df.parse ("2/10/07 10:12 am"),df.parse ("2/11/07 11:15 pm") },
{ 1020, "GUI not repainted", df.parse ("3/5/07 6:00 pm"),df.parse ("3/8/07 3:00 am") },
{ 1025, "File not found exception", df.parse ("1/18/07 9:30 am"),df.parse ("1/22/07 4:13 pm") }
};
TableModel model = new DefaultTableModel (rows, columns);
JTable table = new JTable (model);
final TableRowSorter<TableModel> sorter;
sorter = new TableRowSorter<TableModel> (model);
table.setRowSorter (sorter);
getContentPane ().add (new JScrollPane (table));
JPanel pnl = new JPanel ();
pnl.add (new JLabel ("Filter expression:"));
final JTextField txtFE = new JTextField (25);
pnl.add (txtFE);
JButton btnSetFE = new JButton ("Set Filter Expression");
ActionListener al;
al = new ActionListener (){
public void actionPerformed (ActionEvent e){
String expr = txtFE.getText ();
sorter.setRowFilter (RowFilter.regexFilter (expr));
sorter.setSortKeys (null);
}};
Trang 9Runnable r = new Runnable ()
{public void run (){
try{new BugLog ("Bug Log");
}catch (ParseException pe){
JOptionPane.showMessageDialog (null,
pe.getMessage ());System.exit (1);
}}};
EventQueue.invokeLater (r);
}}
Run this application, specify [F|f]ileas a regular expression, and click the Set FilterExpression button In response, only the first and third rows will be displayed To restoreall rows, simply leave the text field blank and click the button
■ Note The sorter.setSortKeys (null);method call unsorts the view of the underlying model afterchanging the row filter In other words, if you have performed a sort by clicking some column header, thesorted view will revert to the unsorted view following this method call
Trang 10Look and Feel Enhancements
Unlike other Java-based GUI toolkits, Swing decouples its API from the underlying
plat-form’s windowing system toolkit This decoupling has resulted in trade-offs between
platform independence and the faithful reproduction of a native windowing system’s
look and feel Because of user demand for the best possible fidelity of system look and
feels, Java SE 6 improves the Windows look and feel and the GTK look and feel by
allow-ing them to use the native widget rasterizer to render Swallow-ing’s widgets (components, if
you prefer)
Starting with Java SE 6, Sun engineers have reimplemented the Windows look andfeel to use UxTheme, a Windows API hammered out between Microsoft and the author
of the popular WindowBlinds (http://www.stardock.com/products/windowblinds/) theming
engine This API exposes the manner in which Windows controls are rendered As a
result, a Swing application running under Windows XP should look like XP; when this
application runs under Windows Vista, it should look like Vista For completeness, the
original Windows look and feel is still available as the Windows Classic look and feel
(com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel)
Sun engineers have also reimplemented the GTK look and feel to employ native calls to GIMP Toolkit (GTK) engines, which makes it possible to reuse any installed GTK
engine to render Swing components If you are running Linux or Solaris, you can now
use all of your favorite GTK themes to render Swing applications and make these
applications integrate (visually) nicely with the desktop
New SwingWorker
Multithreaded Swing programs can include long-running tasks, such as a task that
per-forms an exhaustive database search across a network If these tasks are run on the
event-dispatching thread (the thread that dispatches events to GUI listeners), the
application will become unresponsive For this reason, a task must run on a worker
thread, which is also known as a background thread When the task completes and the
GUI needs to be updated, the worker thread must make sure that the GUI is updated
on the event-dispatching thread, because most Swing methods are not thread-safe
Although the javax.swing.SwingUtilities public static void invokeLater(Runnable doRun)
and public static void invokeAndWait(Runnable doRun)methods (or their java.awt
EventQueuecounterparts) could be used for this purpose, it is easier to work with Java SE
6’s new javax.swing.SwingWorker<T, V>class, because this class takes care of interthread
communication
Trang 11■ Note Although the new SwingWorker<T, V>class shares the same name as an older SwingWorkerclass, which was widely used for some of the same purposes (but never officially part of Swing), the twoclasses are very different For example, methods that perform the same functions have different names.Also, a separate instance of the new SwingWorker<T, V>class is required for each new background task,whereas old SwingWorkerinstances were reusable.
SwingWorker<T, V>is an abstract class that implements the java.util.concurrent.RunnableFuture<T, V>interface A subclass must implement the protected abstract TdoInBackground()method, which runs on a worker thread, to perform a long-runningtask When this method finishes, the protected void done()method is invoked on theevent-dispatching thread By default, this method does nothing However, you can override done()to safely update the GUI
Type parameter Tspecifies doInBackground()’s return type, and is also the return type of the SwingWorker<T, V>class’s public final T get()and public final T get(longtimeout, TimeUnit unit)methods These methods, which normally wait indefinitely orfor a specific period of time for a task to complete, return immediately with the task’sresult when invoked from within the done()method
Type parameter Vspecifies the type for interim results calculated by the workerthread Specifically, this type parameter is used by the protected final void
publish(V chunks)method, which is designed to be called from within
doInBackground(), to send intermediate results for processing to the
event-dispatching thread These results are retrieved by an overridden protected void
process(List<V> chunks)method whose code runs on the event-dispatching thread
If there are no intermediate results to process, you can specify Voidfor V(and avoid using the publish()and process()methods)
Image loading is one example where SwingWorker<T, V>comes in handy Without thisclass, you might consider loading all images before displaying the GUI, or loading themfrom the event-dispatching thread If you load the images prior to displaying the GUI,there might be a significant delay before the GUI appears Of course, the new splash-screen feature (see Chapter 3) obviates this concern If you attempt to load the imagesfrom the event-dispatching thread, the GUI will be unresponsive for the amount of time
it takes to finish loading all of the images For an example of using SwingWorker<T, V>
to load images, check out the “Simple Background Tasks” lesson in The Java Tutorial
(http://java.sun.com/docs/books/tutorial/uiswing/concurrency/simple.html)
To demonstrate SwingWorker<T, V>, I’ve created a simple application that lets youenter an integer and click a button to find out if this integer is prime This application’sGUI consists of a labeled text field for entering a number, a button for checking if thenumber is prime, and another label that shows the result Listing 4-6 presents the application’s source code
Trang 12super ("Prime Check");
setDefaultCloseOperation (EXIT_ON_CLOSE);
final JLabel lblResult = new JLabel (" ");
JPanel pnl = new JPanel ();
pnl.add (new JLabel ("Enter integer:"));
final JTextField txtNumber = new JTextField (10);
pnl.add (txtNumber);
JButton btnCheck = new JButton ("Check");
ActionListener al;
al = new ActionListener (){
public void actionPerformed (ActionEvent ae){
try{BigInteger bi = new BigInteger (txtNumber.getText ());
lblResult.setText ("One moment ");
new PrimeCheckTask (bi, lblResult).execute ();
}catch (NumberFormatException nfe){
lblResult.setText ("Invalid input");
}
Trang 13Runnable r = new Runnable ()
{public void run (){
new PrimeCheck ();
}};
EventQueue.invokeLater (r);
}}
class PrimeCheckTask extends SwingWorker<Boolean, Void>
{
private BigInteger bi;
private JLabel lblResult;
PrimeCheckTask (BigInteger bi, JLabel lblResult){
Trang 14if (isPrime) lblResult.setText ("Integer is prime");
else lblResult.setText ("Integer is not prime");
} catch (InterruptedException ie) {
lblResult.setText ("Interrupted");
} } catch (ExecutionException ee) {
String reason = null;
Throwable cause = ee.getCause ();
if (cause == null) reason = ee.getMessage ();
else reason = cause.getMessage ();
lblResult.setText ("Unable to determine primeness");
} }
}
When the user clicks the button, its action listener invokes new PrimeCheckTask (bi, lblResult).execute ()to instantiate and execute an instance of PrimeCheckTask,
a SwingWorker<T, V>subclass The biparameter references a java.math.BigInteger
argument that contains the integer to check The lblResultparameter references a
javax.swing.Jlabel, which shows the prime/not prime result (or an error message)
Execution results in a new worker thread starting and invoking the overridden doInBackground()method When this method completes, it returns a value that is stored
Trang 15in a future (A future is an object that stores the result of an asynchronous computation,
as discussed in Chapter 2.) Furthermore, method completion results in a call to the ridden done()method on the event-dispatching thread Within this method, the call toget()returns the value stored within the future, which is then used to set the label’s text.The doInBackground()method invokes bi.isProbablePrime (1000)to determine if theinteger stored in biis a prime number It returns true if the probability that the integer isprime exceeds 1-1/21000(which is practically 100% certainty that the integer is prime).Because it takes longer to determine whether an integer with a lot of digits is a prime, the
over-“One moment ” message will be displayed for longer periods when such a number isentered As long as this message is displayed, the GUI remains responsive You can easilyclose the application, or even click the Check button (although you should not click thisbutton until you see the message stating whether or not the integer is prime)
Text Component Printing
Java 5 integrated printing support into JTablevia several new print()methods and a new getPrintable()method Java SE 6 does the same thing for javax.swing.JTextField,javax.swing.JTextArea, and javax.swing.JEditorPaneby integrating new methods intotheir common JTextComponentsuperclass
One new method is public Printable getPrintable(MessageFormat headerFormat,MessageFormat footerFormat) It returns a java.awt.print.Printablethat prints the con-tents of this JTextComponentas it looks on the screen, but reformatted so that it fits on theprinted page You can wrap this Printableinside another Printableto create complexreports and other kinds of complex documents Because Printableshares the documentwith the JTextComponent, this document must not be changed while the document isbeing printed Otherwise, the printing behavior is undefined
Another new method is public boolean print(MessageFormat headerFormat, MessageFormat footerFormat, boolean showPrintDialog, PrintService service,
PrintRequestAttributeSet attributes, boolean interactive) This method prints thisJTextComponent’s content Specify its parameters as follows:
• Specify page header and footer text via headerFormatand footerFormat.Eachjava.text.MessageFormatidentifies a format pattern, which can contain only a single format item—an Integerthat identifies the current page number—in addition to literal text Pass nullto headerFormatif there is no header; pass null
to footerFormatif there is no footer
• If you would like to display a print dialog (unless headless mode is in effect) that lets the user change printing attributes or cancel printing, pass trueto showPrintDialog
Trang 16• Specify the initial javax.print.PrintServicefor the print dialog via service Pass nullto use the default print service.
• Specify a javax.print.attribute.PrintRequestAttributeSetcontaining an initial set
of attributes for the print dialog via attributes These attributes might be a number
of copies to print or supply needed values when the dialog is not shown Pass null
if there are no print attributes
• Determine if printing is performed in interactivemode If headless mode is not
in effect, passing trueto interactivecauses a modal (when called on the dispatching thread; otherwise, nonmodal) progress dialog with an abort option
to be displayed for the duration of printing If you call this method on the dispatching thread with interactiveset to false, all events (including repaints) are blocked until printing completes As a result, you should do this only if there
event-is no vevent-isible GUI
A java.awt.print.PrinterExceptionis thrown if the print job is aborted because of aprint system error If the current thread is not allowed to initiate a print job request by
an installed security manager, the print()method throws a SecurityException
Two convenience methods are also provided public boolean print(MessageFormatheaderFormat, MessageFormat footerFormat)invokes the more general print()method via
print(headerFormat, footerFormat, true, null, null, true) The public boolean print()
method invokes the more general print()method via print(null, null, true, null,
Trang 17private JTextField txtURL;
private JTabbedPane tp;
private JLabel lblStatus;
private ImageIcon ii = new ImageIcon ("close.gif");
private Dimension iiSize = new Dimension (ii.getIconWidth (),
ii.getIconHeight ());
private int tabCounter = 0;
public BrowserWithPrint (){
super ("Browser");
setDefaultCloseOperation (EXIT_ON_CLOSE);
JMenuBar mb = new JMenuBar ();
JMenu mFile = new JMenu ("File");
JMenuItem miFile = new JMenuItem ("Add Tab");
ActionListener addTabl = new ActionListener ()
{public void actionPerformed (ActionEvent e){
addTab ();
}};
Component c = tp.getSelectedComponent ();JScrollPane sp = (JScrollPane) c;
c = sp.getViewport ().getView ();
JEditorPane ep = (JEditorPane) c;
try
Trang 18{ ep.print ();
} catch (PrinterException pe) {
JOptionPane.showMessageDialog (BrowserWithPrint.this,
"Print error: "+pe.getMessage ());
}
}};
miPrint.addActionListener (printl);
mFile.add (miPrint);
mb.add (mFile);
setJMenuBar (mb);
JPanel pnlURL = new JPanel ();
pnlURL.setLayout (new BorderLayout ());
pnlURL.add (new JLabel ("URL: "), BorderLayout.WEST);
txtURL = new JTextField ("");
pnlURL.add (txtURL, BorderLayout.CENTER);
getContentPane ().add (pnlURL, BorderLayout.NORTH);
tp = new JTabbedPane ();
addTab ();
getContentPane ().add (tp, BorderLayout.CENTER);
lblStatus = new JLabel (" ");
getContentPane ().add (lblStatus, BorderLayout.SOUTH);
ActionListener al;
al = new ActionListener (){
public void actionPerformed (ActionEvent ae){
try{Component c = tp.getSelectedComponent ();
JScrollPane sp = (JScrollPane) c;
c = sp.getViewport ().getView ();
JEditorPane ep = (JEditorPane) c;
ep.setPage (ae.getActionCommand ());
Trang 19miPrint.setEnabled (true);
}catch (Exception e){
lblStatus.setText ("Browser problem: "+e.getMessage ());}
}};
JEditorPane ep = new JEditorPane ();
ep.setEditable (false);
ep.addHyperlinkListener (this);
tp.addTab (null, new JScrollPane (ep));
JButton tabCloseButton = new JButton (ii);
tabCloseButton.setActionCommand (""+tabCounter);
tabCloseButton.setPreferredSize (iiSize);
ActionListener al;
al = new ActionListener (){
public void actionPerformed (ActionEvent ae){
JButton btn = (JButton) ae.getSource ();
tp.removeTabAt (i);
break;
}
Trang 20tabCloseButton.addActionListener (al);
if (tabCounter != 0){
JPanel pnl = new JPanel ();
else
if (evtype == HyperlinkEvent.EventType.EXITED)lblStatus.setText (" ");
}public static void main (String [] args){
Runnable r = new Runnable ()
{public void run (){
new BrowserWithPrint ();
}};
EventQueue.invokeLater (r);
}}
Trang 21After selecting the Print menu item, the current tab’s editor pane is retrieved and itsprint()method is invoked to print the HTML content Figure 4-7 shows the print dialog.
Figure 4-7.The print dialog presents its own tabbed interface.
compo-combination of a string label and an icon on a tab header
The SpringLayout layout manager makes it possible to lay out a GUI using springsand struts Although this layout manager predates Java SE 6, it has suffered from bugssuch as not always correctly resolving its constraints Java SE 6 fixes this bug by basingthe algorithm used to calculate springs on the last two specified springs, along each axis.Java SE 6 has also greatly improved drag-and-drop for Swing components Theseimprovements have to do with telling a component how to determine drop locations and having Swing provide all relevant transfer information during a transfer
The ability to sort and filter a JTable’s contents has been simplified by Java SE 6 Byclicking a column header, you can sort rows according to the column’s contents You canalso filter rows based on regular expressions and other criteria, and display only thoserows that match the criteria
Trang 22Java SE 6 improves the Windows look and feel and the GTK look and feel by allowingthem to use the native widget rasterizer to render Swing’s components These improve-
ments make it possible to faithfully reproduce a native windowing system’s look and feel
on Windows, Linux, and Solaris platforms
A multithreaded Swing program can include a long-running task that needs to updatethe GUI when it completes This task must not be run on the event-dispatching thread;
otherwise, the GUI will be unresponsive The GUI must not be updated on any thread other
than the event-dispatching thread; otherwise, the program will violate the single-threaded
nature of the Swing toolkit Because it can be difficult to code for these requirements, Java
SE 6 introduces a new SwingWorker<T, V>class A subclass implements the doInBackground()
method, which runs on a worker thread, to perform a long-running task When this method
finishes, the done()method (overridden by the subclass) is invoked on the event-dispatching
thread, and the GUI can be safely updated from that method
Finally, Java SE 6 integrates printing support into JTextComponentso that you canprint the contents of various text components This support consists of a getPrintable()
method and three print()methods
Test Your Understanding
How well do you understand the changes to the Swing toolkit? Test your understanding
by answering the following questions and performing the following exercises (The
answers are presented in Appendix D.)
1. What does indexOfTabComponent()return if a tab is not associated with its Componentargument?
2. Which of DropMode.INSERTand DropMode.USE_SELECTIONcauses selected text to betemporarily deselected?
3. JTable’s public int convertRowIndexToModel(int viewRowIndex)method maps arow’s index in terms of the view to the underlying model The public int convertRowIndexToView(int modelRowIndex)method maps a row’s index in terms ofthe model to the view To better understand the relationship between the view andmodel indices, extend PriceList1with a list selection listener that presents theselected row’s (view) index and model index (via convertRowIndexToModel()) via anoption pane dialog As you sort this table via different column headers and selectdifferent rows (you might want to set the table’s selection mode to single selec-tion), you will notice that sorting affects only the view and not the model
4. Why is it necessary to have SwingWorker<T, V>’s doInBackground()method return avalue, and then retrieve this value from within the done()method?
5. Modify BrowseWithPrint.java(Listing 4-7) to work with PrintRequestAttributeSet
Trang 24Java SE 6’s internationalization (i18n) support ranges from Abstract Windowing
Toolkit-oriented non-English locale input bug fixes (see Chapter 3), to network-oriented
internationalized domain names (see Chapter 8), to these i18n-specific features:
• Japanese Imperial Era calendar
• Locale-sensitive services
• New locales
• Normalizer API
• ResourceBundleenhancements
Japanese Imperial Era Calendar
Many Japanese commonly use the Gregorian calendar Because Japanese governments
also use the Japanese Imperial Era calendar for various government documents, Java SE 6
introduces support for this calendar
In the Japanese Imperial Era calendar, eras are based on the reigning periods ofemperors; an era begins with an emperor’s ascension This calendar regards a year as a
combination of a Japanese era name (Heisei, for example) and the one-based year
num-ber within this era For example, Heisei 1 corresponds to 1989, and Heisei 19 corresponds
to 2007 Other eras supported by Java’s implementation of the Japanese Imperial Era
cal-endar are Meiji, Taisho, and Showa The calcal-endar rules keep track of eras and years
Date Handling
You can obtain an instance of the Japanese Imperial Era calendar by invoking the
java.util.Calendarclass’s public static Calendar getInstance(Locale aLocale)method
153
C H A P T E R 5
Trang 25with ja_JP_JPas the locale After obtaining this instance, you can set, fetch, and modifydates, as follows:
Calendar cal = Calendar.getInstance (new Locale ("ja", "JP", "JP"));
cal.setTime (new Date ());
System.out.println (cal.get (Calendar.ERA));
System.out.println (cal.get (Calendar.YEAR));
cal.add (Calendar.DAY_OF_MONTH, -120);
System.out.println (cal.get (Calendar.ERA));
System.out.println (cal.get (Calendar.YEAR));
If the current date were April 13, 2007, for example, the first two System.out.println()method calls would output 4 (which corresponds to the Heisei era) and 19, respectively.After subtracting 120 days from this date, the era would remain the same, but the yearwould change to 18
■ Note Sun’s Supported Calendars documentation (http://java.sun.com/javase/6/docs/
technotes/guides/intl/calendar.doc.html) provides a detailed look at its support for the JapaneseImperial Era calendar
Calendar Page Display
Let’s suppose you want to create a Swing program whose calendar page component presents a calendar page for the current month This component will adapt to differentcalendars based on locale For simplicity, let’s limit this program to English Gregorian,Japanese Gregorian, and Japanese Imperial Era calendars Let’s also assume that you’veinstalled appropriate fonts for rendering Japanese text The requirements for this pro-gram are as follows:
Present the month and era using locale-specific text Both requirements are
accom-modated by Calendar’s new public String getDisplayName(int field, int style,Locale locale)method, which is used with Calendar’s new LONGand SHORTstyle constants to obtain locale-specific display names with long and short styles (January versus Jan, for example) for certain calendar fields, such as Calendar.ERA.This method returns null if no string representation is applicable to the specific calendar field