LOADING TEXT FILES IN SWING EFFICIENTLY ======================================= Suppose that you'd like to read a large text file into a Swing text area, using either a JTextArea or a JTextPane object. Are there any efficiency issues to consider in this operation? To find out, you can set up a test program that uses JTextComponent.read to read in a text file into a text area. Then experiment. Run the program specifying first a JTextArea and then a JTextPane as the target for the text, and compare the program running times. Here's a program you can use to run the test: import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.text.*; import java.io.*; public class ReadDemo { // read the file into the pane static void readin(String fn, JTextComponent pane) { try { FileReader fr = new FileReader(fn); pane.read(fr, null); fr.close(); } catch (IOException e) { System.err.println(e); } } public static void main(String args[]) { final JFrame frame = new JFrame("Read Demo"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); // set up the text pane, either a JTextArea or JTextPane final JTextComponent textpane = new JTextArea(); //final JTextComponent textpane = new JTextPane(); // set up a scroll pane for the text pane final JScrollPane pane = new JScrollPane(textpane); pane.setPreferredSize(new Dimension(600, 600)); // set up the file chooser String cwd = System.getProperty("user.dir"); final JFileChooser jfc = new JFileChooser(cwd); final JLabel elapsed = new JLabel("Elapsed time: "); JButton filebutton = new JButton("Choose File"); filebutton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (jfc.showOpenDialog(frame) != JFileChooser.APPROVE_OPTION) return; File f = jfc.getSelectedFile(); // record the current time and read the file final long s_time = System.currentTimeMillis(); frame.setCursor(Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR)); readin(f.toString(), textpane); // wait for read to complete and update time SwingUtilities.invokeLater(new Runnable() { public void run() { frame.setCursor(Cursor. getPredefinedCursor( Cursor.DEFAULT_CURSOR)); long t = System.currentTimeMillis() - s_time; elapsed.setText("Elapsed time: " + t); } }); } }); JPanel buttonpanel = new JPanel(); buttonpanel.add(filebutton); buttonpanel.add(elapsed); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add("North", buttonpanel); panel.add("Center", pane); frame.getContentPane().add(panel); frame.pack(); frame.setVisible(true); } } The program displays a Choose File button. Click on the button, and a file chooser dialog appears. You can then select a text file to read into the text area. Depending on which of these two lines is uncommented: final JTextComponent textpane = new JTextArea(); //final JTextComponent textpane = new JTextPane(); the text will be read into a JTextArea or into a JTextPane. JTextArea supports plain text (similar to the old AWT TextArea class), while JTextPane handles text with attributes (such as underlining or italics). The program records the time just before reading the file. Then it records the time after the file is read. The elapsed time is the difference between the two times. Notice how SwingUtilities.invokeLater is used to display the elapsed time. It is necessary because the read method is asynchronous, that is, the read operation is not complete when the method returns. Display updating may noticeably lag behind, because updating is done via events placed on the event queue, and the program calls read from the event dispatch thread. You can demonstrate the display lag by compiling and running the program after commenting out a number of lines: // SwingUtilities.invokeLater(new Runnable() { // public void run() { frame.setCursor(Cursor. getPredefinedCursor( Cursor.DEFAULT_CURSOR)); long t = System.currentTimeMillis() - s_time; elapsed.setText("Elapsed time: " + t); // } // }); You will see that the wrong elapsed time is posted when you make this change. The time is calculated after read returns. Unfortunately, this calculation fails to account for the fact that the file is still being processed for display purposes. The larger the file, the more inaccurate the elapsed time calculation. This problem is most pronounced when you read into a JTextPane. Getting back to the example program... so, there will be update events to process after actionPerformed returns. To deal with this issue, for timing purposes, SwingUtilities.invokeLater is called to queue a runnable task. The runnable task displays the elapsed time once the read/display operation is complete. The task runs after all the events ahead of it in the queue have been processed. When you run the test you will see that text can be read into a JTextArea 3-4 times faster than into a JTextPane. To make sure that the comparison is fair, you need to ensure that the file you are reading is either cached or uncached in both cases, that is, that both file reads are directly from disk, or else directly from the operating system cache. The "bottom line" is that JTextPane does more for you than JTextArea, but at higher cost. If you're simply interested in reading plain text, there may be no point in paying that cost. . . . . . . . . . . . . . . . . . . . . . . . .