You are receiving this e-mail because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy prominently on our Web site http://sun.com/privacy/

Please do not reply to the mailed version of the newsletter, this alias is not monitored. Feedback options are listed in the footer for both content and delivery issues.
  Welcome to the Core Java Technologies Tech Tips.
Core Java Technologies
TECHNICAL TIPS
November 15, 2005
View this issue as simple text
In This Issue
 
Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

» Splash Screens and Java SE 6
» Sorting and Filtering Tables

These tips were developed using a snapshot release of Java Platform, Standard Edition 6 (Java SE 6). You can download a snapshot release of Java SE 6 at http://jdk6.dev.java.net/.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

For more Java technology content, visit these sites:

java.sun.com - The latest Java platform releases, tutorials, and newsletters.

java.net - A web forum where enthusiasts of Java technology can collaborate and build solutions together.

java.com - Hot games, cool apps -- Experience the power of Java technology.

SPLASH SCREENS AND JAVA SE 6
 

According to Wikipedia, a splash screen is a computer term for an image that appears while a program or operating system is loading. It provides the user with a visual indicator that the program is initializing. Prior to Java SE 6 you could only offer the behavior of a splash screen by creating a window at the start of your main method and placing an image in it. Although this worked, it required the Java runtime to be fully initialized before the window appeared. This initialization included AWT and typically Swing, so that it delayed the initial graphical display. With Java SE 6, a new command-line option makes this functionality much easier. It also displays the image more quickly to the user, that is, even before the Java runtime has started. Final inclusion of the feature is subject to JCP approval.

Command Line Option

If you run a program from the command line, you can generate a splash screen through the -splash command line switch. This functionality is most useful when you're using a script, batch file, or desktop shortcut to run the program. The command line switch is followed by an image name:
   java -splash:Hello.png HelloWorld
Yes, that is a colon between -splash and the image name. This immediately displays the image before the runtime environment is fully initialized. The displayed image is centered on the screen. Splash screen images can be have GIF, PNG, or JPEG formats. As is the case for the regular Image class, splash screen images support animation, transparency, and translucency (translucency support is limited to Microsoft Windows 2000 or XP). The splash screen disappears when the first window is created by the application.

JAR File Manifests

Typically most users won't want to put -splash on their command line entry. So perhaps a more effective way of displaying a splash screen is to create a manifest file for an application, and then combine the application with the manifest and image in a JAR file. When a user launches the application from the JAR file, the splash screen appears. In this case, the user doesn't have to specify a command line option.

The manifest file option is named SplashScreen-Image. The option is followed by the image filename. The full path of the filename needs to be specified if the file is not at the top level of the JAR file.

Here's a simple example that demonstrates these new splash screen features. First, create the following program:
   import javax.swing.*;
   import java.awt.*;

   public class HelloSplash {
     public static void main(String args[]) {
       Runnable runner = new Runnable() {
         public void run() {
           try {
               Thread.sleep(1500);
           } catch (InterruptedException e) {
           }
           JFrame frame = new JFrame("Splash Me");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           JLabel label = new JLabel(
                "Hello, Splash", JLabel.CENTER);
           frame.add(label, BorderLayout.CENTER);
           frame.setSize(300, 95);
           frame.setVisible(true);
        }
       };
       EventQueue.invokeLater(runner);
     }
    }
Next, compile the program:
    javac HelloSplash.java
Then try out the command-line -splash. For simplicity, use a splash screen image that's in the same directory as the program (this is not an absolute requirement):
   java -splash:MyImage.png HelloSplash
You'll see MyImage centered on the screen immediately, followed by the application screen once the Java runtime environment initializes.

My Image

Hello Splash

Now let's try the JAR file approach. First create the manifest.mf file for the manifest. The contents of the file should look like this:
   Manifest-Version: 1.0
   Main-Class: HelloSplash
   SplashScreen-Image: MyImage.png
Then package the JAR file:
   jar -mcvf manifest.mf Splash.jar HelloSplash*.class MyImage.png
Then run the JAR without specifying the -splash command line option:
   java -jar Splash.jar
As before, you should see the splash screen followed by the application screen.

If your JAR file has a splash screen image specified in its manifest, and a user specifies a splash image from the command line, the command line image is given precedence and shown instead.

Beyond the Basics

Although the command-line -splash and manifest SplashScreen-Image options are sufficient for most needs, there is more to splash screens in Java SE 6. The java.awt package offers a SplashScreen class for more advanced functionality beyond simply showing a splash screen image.

Provided an image was created by either the -splash command line option or the SplashScreen-Image option in the manifest, the getSplashScreen() method of the SplashScreen class returns the generated screen. If no image was created, getSplashScreen() returns null.

Using other SplashScreen methods, you can discover various things related to a splash screen:
  • getBounds() returns the bounds of the splash screen rectangle.
  • getImageURL() returns the URL of the splash screen image.
  • getSize() returns the size of the splash screen window.
  • isVisible() indicates whether the splash screen is visible
You can change the image shown after the splash screen is loaded, but before the application starts. You have two ways to do this. The setImageURL() method allows you to provide a URL for a new image to display. The second approach, which is likely more typical, is to call the getGraphics() method to get the graphics context (java.awt.Graphics) of the window. You then update the image with any of the normal graphical and Java 2D APIs. That's because this is an instance of Graphics2D, not simply java.awt.Graphics. After you draw to the graphics context, you call the update() method of SplashScreen to draw the updated image.

Here's an example of the latter behavior, which cycles through a bunch of colors on the splash screen. Imagine this displaying a progress bar or some other state data indicating the progress of application initialization.
   import javax.swing.*;
   import java.awt.*;
   import java.awt.geom.*;
   import java.util.*;

   public class ExtendedSplash {
     public static void main(String args[]) {
       Runnable runner = new Runnable() {
         public void run() {
           Random random = new Random();
           SplashScreen splash = SplashScreen.getSplashScreen();
           Graphics2D g = (Graphics2D)splash.getGraphics();
           Dimension dim = splash.getSize();
           Color colors[] = {Color.RED, Color.ORANGE,
             Color.YELLOW, Color.GREEN, Color.BLUE,
             Color.MAGENTA};
           for (int i=0; i<100; i++) {
             g.setColor(colors[i % colors.length]);
             g.fillRect(50, 50, dim.width-100, dim.height-100);
             splash.update();
             try {
               Thread.sleep(250);
             } catch (InterruptedException ignored) {
             }
           }
           JFrame frame = new JFrame("Splash Me2");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           JLabel label =
             new JLabel("Hello, Splash", JLabel.CENTER);
           frame.add(label, BorderLayout.CENTER);
           frame.setSize(300, 95);
           frame.setVisible(true);
         }
       };
       EventQueue.invokeLater(runner);
     }
   }
color Splash

Notice how the drawing is done over the splash screen image.

After the color cycling is complete, the example shows the frame. This is typical of a startup process: after the initialization completes, show the frame, which hides the splash screen.

The final SplashScreen option to mention uses the close() method. You can call this method if you want to explicitly close the window and release the associated resources. It isn't necessary to explicitly call this method because it is called automatically when the first window is made visible.

For additional information on using splash screens, see the technical article New Splash-Screen Functionality in Java SE 6. Also see the javadoc for the SplashScreen class.

Back to Top

SORTING AND FILTERING TABLES
 

Java Standard Edition (Java SE) 6.0, adds some features that make sorting and filtering the contents of a Swing JTable much easier. (Final inclusion of these features is subject to JCP approval.) Most modern table-driven user interfaces allow users to sort columns by clicking on the table header. This could be done with the Swing JTable support in place prior to Java SE 6. However the functionality had to be added manually in a custom way for each table that needed this feature. With Java SE 6, enabling this functionality requires minimal effort. Filtering is another option commonly available with user interfaces. Filtering allows users to display only the rows in a table that match user-supplied criteria. With Java SE 6, enabling filtering of JTable contents is also much easier.

Sorting Rows

The basis for sorting and filtering rows in Java SE 6 is the abstract RowSorter class. RowSorter maintains two mappings, one of rows in a JTable to the elements of the underlying model, and back again. This allows for one to do sorting and filtering. The class is generic enough to work with both TableModel and ListModel. However only a TableRowSorter is provided with the Java SE 6 libraries to work with JTable.

In the simplest case, you pass the TableModel to the TableRowSorter constructor, and then pass the created RowSorter into the setRowSorter() method of JTable. Here's an example program, SortTable, that demonstrates the approach:
   import javax.swing.*;
   import javax.swing.table.*;
   import java.awt.*;

   public class SortTable {
     public static void main(String args[]) {
       Runnable runner = new Runnable() {
        public void run() {
           JFrame frame = new JFrame("Sorting JTable");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           Object rows[][] = {
               {"AMZN", "Amazon", 41.28},
               {"EBAY", "eBay", 41.57},
               {"GOOG", "Google", 388.33},
               {"MSFT", "Microsoft", 26.56},
               {"NOK", "Nokia Corp", 17.13},
               {"ORCL", "Oracle Corp.", 12.52},
               {"SUNW", "Sun Microsystems", 3.86},
               {"TWX",  "Time Warner", 17.66},
               {"VOD",  "Vodafone Group", 26.02},
               {"YHOO", "Yahoo!", 37.69}
             };
           String columns[] = {"Symbol", "Name", "Price"};
           TableModel model =
               new DefaultTableModel(rows, columns) {
             public Class getColumnClass(int column) {
               Class returnValue;
               if ((column >= 0) && (column < getColumnCount())) {
                 returnValue = getValueAt(0, column).getClass();
               } else {
                 returnValue = Object.class;
               }
               return returnValue;
             }
           };

           JTable table = new JTable(model);
           RowSorter<TableModel> sorter =
             new TableRowSorter<TableModel>(model);
           table.setRowSorter(sorter);
           JScrollPane pane = new JScrollPane(table);
           frame.add(pane, BorderLayout.CENTER);
           frame.setSize(300, 150);
           frame.setVisible(true);
         }
       };
       EventQueue.invokeLater(runner);
     }
   }
Sort Table 1

Click on one of the columns of the displayed table, and notice that the contents of the column are reordered.

Sort Table 2

You might ask why not simply use the DefaultTableModel, as opposed to creating a custom subclass of it? The answer is that TableRowSorter has a set of rules to follow for sorting columns. By default, all columns of a table are thought to be of type Object. So, sorting is done by calling toString(). By overriding the default getColumnClass() behavior of DefaultTableModel, RowSorter sorts according to the rules of that class, assuming it implements Comparable. You can also install a custom Comparator for a column by calling setComparator(int column, Comparator comparator).

The key three lines in the SortTable program that are pertinent to sorting are shown here:
           JTable table = new JTable(model);
           RowSorter<TableModel> sorter =
             new TableRowSorter<TableModel>(model);
           table.setRowSorter(sorter);
The first line associates the model with the table. The second line creates a RowSorter specific to the model. The third line associates the RowSorter with the JTable. This enables a user to click on the column header to sort that column. Clicking a second time on the same column reverses the sort order.

If you want to add your own action when the sort order changes, you can attach a RowSorterListener to the RowSorter. The interface has one method:
   void sorterChanged(RowSorterEvent e)
The method allows you to update the text on the status bar, or perform some additional task. The RowSorterEvent for the action allows you to discover how many rows were present before the sort, in the event that the RowSorter filtered rows in or out of the view.

Filtering Table Rows

You can associate a RowFilter with the TableRowSorter and use it to filter the contents of a table. For instance, you can use a RowFilter such that a table displays only rows where the name starts with the letter A or where the stock price is greater than $50. The abstract RowFilter class has one method that is used for filtering:
   boolean include(RowFilter.Entry<? extends M,? extends I> entry)
For each entry in the model associated with the RowSorter, the method indicates whether the specified entry should be shown in the current view of the model. In many cases, you don't need to create your own RowFilter implementation. Instead, RowFilter offers six static methods for creating filters.
  • andFilter(Iterable<? extends RowFilter<? super M,? super I>> filters)
  • dateFilter(RowFilter.ComparisonType type, Date date, int... indices)
  • notFilter(RowFilter<M,I> filter)
  • numberFilter(RowFilter.ComparisonType type, Number number, int... indices)
  • orFilter(Iterable<? extends RowFilter<? super M,? super I>> filters)
  • regexFilter(String regex, int... indices)
For the RowFilter factory methods that have an argument of indices (dateFilter, numberFilter, regexFilter), only the set of columns corresponding to the specified indices are checked in the model. If no indices are specified, all columns are checked for a match.

The dateFilter allows you to check for a matching date. The numberFilter checks for a matching number. The notFilter is used for reversing another filter, in other words, it includes entries that the supplied filter does not include. You can use it to do things like find entries where something was not done on 12/25/2005. The andFilter and orFilter are for logically combining other filters. The regexFilter uses a regular expression for filtering. Here's a program, FilterTable, that uses a regexFilter to filter table content:
   import javax.swing.*;
   import javax.swing.table.*;
   import java.awt.*;
   import java.awt.event.*;
   import java.util.regex.*;

   public class FilterTable {
     public static void main(String args[]) {
       Runnable runner = new Runnable() {
         public void run() {
           JFrame frame = new JFrame("Sorting JTable");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           Object rows[][] = {
             {"AMZN", "Amazon", 41.28},
             {"EBAY", "eBay", 41.57},
             {"GOOG", "Google", 388.33},
             {"MSFT", "Microsoft", 26.56},
             {"NOK", "Nokia Corp", 17.13},
             {"ORCL", "Oracle Corp.", 12.52},
             {"SUNW", "Sun Microsystems", 3.86},
             {"TWX",  "Time Warner", 17.66},
             {"VOD",  "Vodafone Group", 26.02},
             {"YHOO", "Yahoo!", 37.69}
           };
           Object columns[] = {"Symbol", "Name", "Price"};
           TableModel model =
              new DefaultTableModel(rows, columns) {
             public Class getColumnClass(int column) {
               Class returnValue;
               if ((column >= 0) && (column < getColumnCount())) {
                 returnValue = getValueAt(0, column).getClass();
               } else {
                 returnValue = Object.class;
               }
               return returnValue;
             }
           };
           JTable table = new JTable(model);
           final TableRowSorter<TableModel> sorter =
                   new TableRowSorter<TableModel>(model);
           table.setRowSorter(sorter);
           JScrollPane pane = new JScrollPane(table);
           frame.add(pane, BorderLayout.CENTER);
           JPanel panel = new JPanel(new BorderLayout());
           JLabel label = new JLabel("Filter");
           panel.add(label, BorderLayout.WEST);
           final JTextField filterText =
               new JTextField("SUN");
           panel.add(filterText, BorderLayout.CENTER);
           frame.add(panel, BorderLayout.NORTH);
           JButton button = new JButton("Filter");
           button.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
               String text = filterText.getText();
               if (text.length() == 0) {
                 sorter.setRowFilter(null);
               } else {
                 try {
                   sorter.setRowFilter(
                       RowFilter.regexFilter(text));
                 } catch (PatternSyntaxException pse) {
                   System.err.println("Bad regex pattern");
                 }
               }
             }
           });
           frame.add(button, BorderLayout.SOUTH);
           frame.setSize(300, 250);
           frame.setVisible(true);
         }
       };
       EventQueue.invokeLater(runner);
     }
   }
The display sets a filter for all strings with the characters SUN somewhere in them. This is specified by the string "SUN". Use the characters '^' and '$' to test for exact matches at the beginning and end of the string respectively.

Filter Table 1

The filter internally uses Matcher.find() for inclusion testing when the user presses the "Filter" button at the bottom.

Filter Table 2

Change the filter text to change the set of rows shown in the table. If you want to see all the rows in the table, remove the filter text.

One last thing worth mentioning -- when sorting or filtering, the selection is in terms of the view. So that if you need to map to the underlying model, you need to call the convertRowIndexToModel() method. Similarly, if you want to convert from the model to the view you need to use convertRowIndexToView().

For more information about RowSorter, TableRowSorter, and RowFilter see the javadoc for the respective classes:

RowSorter
TableRowSorter
RowFilter

Back to Top

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.
Comments? Send your feedback on the Tech Tips: http://developers.sun.com/contact/feedback.jsp?category=newslet

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
  • Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE).
  • Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME).
You can subscribe to these and other Java technology developer newsletters or manage your current newsletter subscriptions on the Sun Developer Network Subscriptions page

ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/developer/JDCTechTips/index.html

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

© 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://sun.com/suntrademarks
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc. 10 Network Circle, MPK10-209 Menlo Park, CA 94025 US