I l@ve RuBoard |
![]() ![]() |
23.2 Overview of the Editor KitsThe following sections provide an overview of the various editor kits. With minor variations, this information applies to all editor kits. 23.2.1 The EditorKit ClassThe EditorKit class is the abstract base class for all editor kits. It has a number of methods that define the model (e.g., createDefaultDocument( )), the view (e.g., getViewFactory( )), the capabilities (getActions( )), and the I/O strategy (read( ) and write( )) for a given type of document content. Figure 23-2 shows the EditorKit class and the many classes and interfaces it interacts with. Figure 23-2. EditorKit class diagram![]() This figure shows several important things about the EditorKit class. First, each EditorKit instance is typically associated with a single JEditorPane (though in some cases, it doesn't care). The EditorKit defines how to create a default Document as well as how to read and write the Document to a stream. In addition, each EditorKit may define a ViewFactory responsible for creating View objects for each Element in the Document. Finally, the diagram shows that an EditorKit may define a set of Actions that it supports. The other classes shown in the diagram are the subclasses of EditorKit and AbstractAction. We'll look at each of these classes, as well as some inner classes not shown on the diagram, throughout this chapter. 23.2.1.1 PropertiesEditorKit defines the properties shown in Table 23-3. The actions property defines the set of actions that can be used on a text component, which uses a model and a view produced by this EditorKit. contentType indicates the MIME type of the data that this kit supports. The viewFactory property is the ViewFactory object used to create View objects for the Elements of the document type produced by the kit. The accessors for all three of these properties are abstract.
23.2.1.2 Abstract methodsThe following methods must be defined by implementations of this class:
Figure 23-3. Default document creation using EditorKit![]()
These read( ) and write( ) methods support any arbitrary text format. For simple text, the data read and written is plain text; more advanced editor kits might be able to read attribute and style information or well-defined markup languages like HTML or XML. 23.2.1.3 Other methodsThese methods are not abstract, but the default implementations do nothing:
23.2.2 The TextAction ClassWay back in Chapter 3, we introduced the Action interface and the AbstractAction default implementation. To quickly review, Actions are a way to encapsulate some common piece of functionality, along with an associated name, icon, and other attributes. Action extends the ActionListener interface, so any Action can be added as a listener to components that fire Action events. When working with any word processor or basic editor, you perform "actions" all the time. The simplest example occurs every time you type a character. Some action is performed to add that character to the document and the display. More interesting examples include making a segment of text bold, copying a selection of text, or changing the current font. Swing provides support for many of these common activities through classes that extend the TextAction abstract class. The specific actions available are defined as inner classes of the EditorKit subclasses. We'll cover each of these in the sections that follow. In this section, we'll briefly cover the TextAction class itself, so you understand what all these new actions have in common. Appendix B lists all the actions provided by Swing's standard components. Note that if you want to define your own Action implementations that manipulate text components, they don't have to extend TextAction. In most cases you'll want to because its getTextComponent( ) method makes it convenient to create a single instance that can work with multiple text components. 23.2.2.1 Constructor
23.2.2.2 Static method
23.2.2.3 Protected methods
23.2.3 The DefaultEditorKit ClassDefaultEditorKit, a subclass of EditorKit, provides a great deal of default behavior applicable to most document types. As we'll see, the most interesting features available in this class are provided by the actions it supports through its numerous inner classes. When used directly, DefaultEditorKit supports only plain-text data. Its actions deal with tasks such as copying and pasting data, and its I/O methods read and write only plain text. However, the important thing about this class is that it can be extended to add more features, and the actions it defines are still useful. We'll see extensions of DefaultEditorKit in the sections that follow. 23.2.3.1 PropertiesDefaultEditorKit defines values for the properties shown in Table 23-4. Each action is an instance of an inner class capable of performing a given task. The contentType for editors using DefaultEditorKit is "text/plain", indicating that styled text is not supported. The viewFactory property is set to null, indicating that users of this class must provide ViewFactory support via the TextUI.
23.2.3.2 ConstantsDefaultEditorKit defines 52[3] action names (Strings, shown in Table 23-5) as constant values, though their names aren't all-caps as you'd expect given the Java naming conventions.
All but six of these names are public; six are declared with default (package) access and are thus intended for internal use. Behind each action name is an inner class (some classes are used by multiple actions) that extends TextAction to carry out the action. Several of these action classes are public, so we describe them in more detail after this section. However, even with the nonpublic classes, you can get to an instance of the action using these constants, along with the actions property. The following example shows a common strategy for doing this. We store all the actions in a local Hashtable so that we can access them by name. In this example, we then retrieve the "cut" action from the table using the DefaultEditorKit.cutAction constant: Hashtable actionHash = new Hashtable( ); Action[] actions = edKit.getActions( ); for (int i=0; i<actions.length; i++) { String name = (String)actions[i].getValue(Action.NAME); actionHash.put(name, actions[i]); } Action cut = (Action)actionHash.get(DefaultEditorKit.cutAction);
It would have been nice if EditorKit had been enhanced to take advantage of ActionMap to spare us this sort of effort. Perhaps someday . . . 23.2.3.3 Using actionsLet's look at a simple example that shows how these actions can be used. This program creates a JTextArea and adds all the available actions to a menu (the list is pretty long, so we split it into two submenus). As we discussed in Chapter 14, we can add these Action objects directly to the menu. The default action names appear as menu selections. Since JTextArea gets its actions from the DefaultEditorKit, you'll see each of the actions listed in Table 23-5 when you run this program. By blindly adding all the actions, we avoid interacting with the editor kit directly in this program. At the end of this section, we'll look at a much more useful example that uses DefaultEditorKit directly. // TextActionExample.java // import javax.swing.*; import javax.swing.text.*; // Simple TextAction example public class TextActionExample { public static void main(String[] args) { // Create a text area. JTextArea ta = new JTextArea( ); ta.setLineWrap(true); // Add all actions to the menu (split into two menus to make it more usable). Action[] actions = ta.getActions( ); JMenuBar menubar = new JMenuBar( ); JMenu actionmenu = new JMenu("Actions"); menubar.add(actionmenu); JMenu firstHalf = new JMenu("1st Half"); JMenu secondHalf = new JMenu("2nd Half"); actionmenu.add(firstHalf); actionmenu.add(secondHalf); int mid = actions.length/2; for (int i=0; i<mid; i++) { firstHalf.add(actions[i]); } for (int i=mid; i<actions.length; i++) { secondHalf.add(actions[i]); } // Show it. JFrame f = new JFrame( ); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane( ).add(ta); f.setJMenuBar(menubar); f.setSize(300, 200); f.setVisible(true); } } That's all there is to it! All we did was call getActions( ) on the JTextArea (which ultimately retrieved the actions from a DefaultEditorKit) and added each action to the menu. Of course, most of these actions would never be provided as menu options, and for those that would, you'd want to change the label (the default labels are all lowercase, and the words are hyphen-separated, as in cut-to-clipboard). The example at the end of the section is a bit more realistic. 23.2.3.4 Constructor
23.2.3.5 MethodsThe following methods provide default implementations for all the abstract methods defined in EditorKit:
23.2.4 Useful ActionsIn the next few sections, we'll give a brief overview of some key actions defined as public static inner classes of DefaultEditorKit. The first of these is the default action used to insert text into the active JTextComponent. The constructors aren't described individually, as they simply set up the proper name for each action. We'll simply describe the actionPerformed method that implements the purpose of each action. In each case, the method has the standard signature, public void actionPerformed(ActionEvent e).
23.2.5 A Simple Text EditorIn the next example, we'll show how to provide some of the things you'd expect from a basic editor. Our first editor supports the following features:
When we run it, our simple editor looks something like Figure 23-4.[4]
Figure 23-4. SimpleEditor![]() Here's the source code for SimpleEditor. It's designed to be easily extensible, allowing us to add features of the more advanced editor kits. This class serves as the base class for the other examples in this chapter. // SimpleEditor.java // import javax.swing.*; import javax.swing.text.*; import java.awt.*; import java.io.*; import java.awt.event.*; import java.util.Hashtable; // An example showing several DefaultEditorKit features. This class is designed // to be easily extended for additional functionality. public class SimpleEditor extends JFrame { public static void main(String[] args) { SimpleEditor editor = new SimpleEditor( ); editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); editor.setVisible(true); } // Create an editor. public SimpleEditor( ) { super("Swing Editor"); textComp = createTextComponent( ); makeActionsPretty( ); Container content = getContentPane( ); content.add(textComp, BorderLayout.CENTER); content.add(createToolBar( ), BorderLayout.NORTH); setJMenuBar(createMenuBar( )); setSize(320, 240); } // Create the JTextComponent subclass. protected JTextComponent createTextComponent( ) { JTextArea ta = new JTextArea( ); ta.setLineWrap(true); return ta; } // Add icons and friendly names to actions we care about. protected void makeActionsPretty( ) { Action a; a = textComp.getActionMap( ).get(DefaultEditorKit.cutAction); a.putValue(Action.SMALL_ICON, new ImageIcon("icons/cut.gif")); a.putValue(Action.NAME, "Cut"); a = textComp.getActionMap( ).get(DefaultEditorKit.copyAction); a.putValue(Action.SMALL_ICON, new ImageIcon("icons/copy.gif")); a.putValue(Action.NAME, "Copy"); a = textComp.getActionMap( ).get(DefaultEditorKit.pasteAction); a.putValue(Action.SMALL_ICON, new ImageIcon("icons/paste.gif")); a.putValue(Action.NAME, "Paste"); a = textComp.getActionMap( ).get(DefaultEditorKit.selectAllAction); a.putValue(Action.NAME, "Select All"); } // Create a simple JToolBar with some buttons. protected JToolBar createToolBar( ) { JToolBar bar = new JToolBar( ); // Add simple actions for opening and saving. bar.add(getOpenAction( )).setText(""); bar.add(getSaveAction( )).setText(""); bar.addSeparator( ); // Add Cut/Copy/Paste buttons. bar.add(textComp.getActionMap( ).get(DefaultEditorKit.cutAction)).setText(""); bar.add(textComp.getActionMap( ).get(DefaultEditorKit.copyAction)).setText(""); bar.add(textComp.getActionMap( ).get(DefaultEditorKit.pasteAction)).setText(""); return bar; } // Create a JMenuBar with file and edit menus. protected JMenuBar createMenuBar( ) { JMenuBar menubar = new JMenuBar( ); JMenu file = new JMenu("File"); JMenu edit = new JMenu("Edit"); menubar.add(file); menubar.add(edit); file.add(getOpenAction( )); file.add(getSaveAction( )); file.add(new ExitAction( )); edit.add(textComp.getActionMap( ).get(DefaultEditorKit.cutAction)); edit.add(textComp.getActionMap( ).get(DefaultEditorKit.copyAction)); edit.add(textComp.getActionMap( ).get(DefaultEditorKit.pasteAction)); edit.add(textComp.getActionMap( ).get(DefaultEditorKit.selectAllAction)); return menubar; } // Subclass can override to use a different open action. protected Action getOpenAction( ) { return openAction; } // Subclass can override to use a different save action. protected Action getSaveAction( ) { return saveAction; } protected JTextComponent getTextComponent( ) { return textComp; } private Action openAction = new OpenAction( ); private Action saveAction = new SaveAction( ); private JTextComponent textComp; private Hashtable actionHash = new Hashtable( ); // ********** ACTION INNER CLASSES ********** // // A very simple exit action public class ExitAction extends AbstractAction { public ExitAction( ) { super("Exit"); } public void actionPerformed(ActionEvent ev) { System.exit(0); } } // An action that opens an existing file class OpenAction extends AbstractAction { public OpenAction( ) { super("Open", new ImageIcon("icons/open.gif")); } // Query user for a filename and attempt to open and read the file into the // text component. public void actionPerformed(ActionEvent ev) { JFileChooser chooser = new JFileChooser( ); if (chooser.showOpenDialog(SimpleEditor.this) != JFileChooser.APPROVE_OPTION) return; File file = chooser.getSelectedFile( ); if (file == null) return; FileReader reader = null; try { reader = new FileReader(file); textComp.read(reader, null); } catch (IOException ex) { JOptionPane.showMessageDialog(SimpleEditor.this, "File Not Found", "ERROR", JOptionPane.ERROR_MESSAGE); } finally { if (reader != null) { try { reader.close( ); } catch (IOException x) {} } } } } // An action that saves the document to a file class SaveAction extends AbstractAction { public SaveAction( ) { super("Save", new ImageIcon("icons/save.gif")); } // Query user for a filename and attempt to open and write the text component's // content to the file. public void actionPerformed(ActionEvent ev) { JFileChooser chooser = new JFileChooser( ); if (chooser.showSaveDialog(SimpleEditor.this) != JFileChooser.APPROVE_OPTION) return; File file = chooser.getSelectedFile( ); if (file == null) return; FileWriter writer = null; try { writer = new FileWriter(file); textComp.write(writer); } catch (IOException ex) { JOptionPane.showMessageDialog(SimpleEditor.this, "File Not Saved", "ERROR", JOptionPane.ERROR_MESSAGE); } finally { if (writer != null) { try { writer.close( ); } catch (IOException x) {} } } } } } Let's look at a few of the methods from this example. The first interesting method is called makeActionsPretty( ). This method adds icons to the actions we're going to display and changes the text for these actions. This way, our user interface displays nice names like Cut instead of cut-to-clipboard. It uses the ActionMap associated with the text component to look up the standard actions, as described in Chapter 3. In createToolBar( ), we get instances of two inner classes, OpenAction and SaveAction, and add them to our JToolBar. We get these actions by calling getOpenAction( ) and getSaveAction( ) to allow subclasses to provide different implementations of these actions. We then get the cut, copy, and paste actions. We've chosen not to display the text for the actions in the toolbar, so we call setText("") on the JButton returned by each add( ) call. For more details on Swing's handy JToolBar class, see Chapter 14. The createMenuBar( ) method is similar to createToolBar( ). We add two additional actions here: exit and select-all. In this method, we don't strip the text from the menu items, allowing both the icon and text to be displayed. Finally, we define action classes for exiting the application, and for opening and saving files. These last two actions call the JTextComponent's read( ) and write( ) methods, which take advantage of the editor kit's read( ) and write( ) methods. For more details on another handy Swing class we've used here, JFileChooser, see Chapter 12. If you compare this example to the version from our first edition,[5] you'll see some good evidence of the maturation of Swing over the last few years. We've been able to remove an entire page of code because of features that Swing now gives us for free. ActionMaps eliminated the need for our own code to organize and look up the text components' Actions. We also had a method that added entries to the component's KeyMap for moving around by word and extending the selection using the keyboard. We made no effort to do this in an L&F-appropriate way. Luckily, the new InputMap associated with JTextArea provides all these capabilities for us, and it is L&F-sensitive. In the Windows, Metal, and Motif L&Fs, you can move the caret a word at a time by holding down Ctrl while pressing an arrow key; in the Mac L&F, the Command key serves this purpose. In all L&Fs, holding down Shift during cursor movement extends the selection in that direction.
23.2.6 The StyledEditorKit ClassStyledEditorKit extends DefaultEditorKit to provide additional features for styled text. It is the kit used by the JTextPane class. Like DefaultEditorKit, this class defines a number of new TextActions. In this class, all of these action classes are public. We'll look at each of them at the end of this section. 23.2.6.1 PropertiesStyledEditorKit defines the properties and default values shown in Table 23-6. The actions property is the set of actions defined for DefaultEditorKit, augmented with actions for setting text alignment and font family, size, and style attributes. The exact actions provided are shown in Table 23-7. In this table, the first column is the inner class name, the next column is the action name (Action.NAME), and the last column lists parameter values passed to the specific action class constructor. Additional actions can be created by instantiating the desired action class and passing different values to the constructor.
The characterAttributeRun property indicates the Element in which the caret is currently located. This is updated whenever the kit's JEditorPane fires a CaretEvent. Similarly, the inputAttributes property provides access to the attribute set in use at the current caret position. This property is used by the JTextPane class whenever content is added to the document. The viewFactory defined by StyledEditorKit is an inner class capable of creating View objects for different types of Elements. The View objects created by this factory depend on the name property of the Element passed to the create( ) method, as shown in Table 23-8.
23.2.6.2 Constructor
23.2.6.3 EditorKit methodsThese methods override those defined in DefaultEditorKit or EditorKit:
23.2.7 The StyledEditorKit.StyledTextAction ClassAs discussed earlier, StyledEditor defines several public inner classes to perform actions related to styled text. This public abstract class extends TextAction and serves as the base class for all the other action inner classes. 23.2.7.1 Constructor
23.2.7.2 Protected methodsThese protected methods are available to any subclass of StyledTextAction. None of them does anything really new, they just save you a few steps for certain common tasks. If you define your own styled text actions, some of these methods will come in handy.
The following seven classes are public, static extensions of the StyledTextAction abstract class. Instances of these classes are provided as default actions for the StyledEditorKit, but you can create additional instances if the exact action you want is not provided as a default. Each class contains only a constructor and its actionPerformed( ) method, so we'll detail only the interesting methods as we did for DefaultEditorKit's actions. Unless otherwise noted, each of these classes uses the setCharacterAttributes( ) method, defined in StyledTextAction, to update the attributes for the current selection, if there is one, or the attributes for text to be inserted. 23.2.7.3 The StyledEditorKit.FontFamilyAction class
23.2.7.4 The StyledEditorKit.FontSizeAction class
23.2.7.5 The StyledEditorKit.ForegroundAction class
23.2.7.6 The StyledEditorKit.AlignmentAction class
23.2.7.7 The StyledEditorKit.BoldAction class
23.2.7.8 The StyledEditorKit.ItalicAction class
23.2.7.9 The StyledEditorKit.UnderlineAction class
23.2.8 A Better EditorEarlier in this chapter, we created a class called SimpleEditor that used some of the actions provided by DefaultEditorKit. Now we'll extend that class to create StyleEditor, which uses many of the new actions we've just introduced. When run, StyledEditor looks like Figure 23-5. Figure 23-5. StyledEditor: a text editor that supports user-defined styles![]() There's not a lot in this class that's new. We override several of the methods defined in SimpleEditor to add actions to the toolbar and menu. These include actions for changing the font's style, size, and family. We also take advantage of the text component's InputMap to add new key mappings that change the font style since these aren't built into Swing the way SimpleEditor's actions were. We use the default AWT toolkit's getMenuShortcutKeymask( ) method to accomplish this in an L&F-appropriate manner. Under most L&Fs, the keys Ctrl-B, Ctrl-I, and Ctrl-U toggle bold, italics and underlining while in the Mac L&F, Command-B, Command-I, and Command-U are used instead. Here's the code for our new and improved editor: // StyledEditor.java // import javax.swing.*; import javax.swing.text.*; import java.awt.event.*; import java.awt.Toolkit; // An extension of SimpleEditor that adds styled-text features public class StyledEditor extends SimpleEditor{ public static void main(String[] args) { StyledEditor editor = new StyledEditor( ); editor.setVisible(true); editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } // Create a styed editor. public StyledEditor( ) { updateInputMap( ); // Install our style-related keystrokes } // Override to create a JTextPane. protected JTextComponent createTextComponent( ) { return new JTextPane( ); } // Add icons and friendly names for font actions. protected void makeActionsPretty( ) { super.makeActionsPretty( ); Action a; a = getTextComponent( ).getActionMap( ).get("font-bold"); a.putValue(Action.SMALL_ICON, new ImageIcon("icons/bold.gif")); a.putValue(Action.NAME, "Bold"); a = getTextComponent( ).getActionMap( ).get("font-italic"); a.putValue(Action.SMALL_ICON, new ImageIcon("icons/italic.gif")); a.putValue(Action.NAME, "Italic"); a = getTextComponent( ).getActionMap( ).get("font-underline"); a.putValue(Action.SMALL_ICON, new ImageIcon("icons/underline.gif")); a.putValue(Action.NAME, "Underline"); a = getTextComponent( ).getActionMap( ).get("font-family-SansSerif"); a.putValue(Action.NAME, "SansSerif"); a = getTextComponent( ).getActionMap( ).get("font-family-Monospaced"); a.putValue(Action.NAME, "Monospaced"); a = getTextComponent( ).getActionMap( ).get("font-family-Serif"); a.putValue(Action.NAME, "Serif"); a = getTextComponent( ).getActionMap( ).get("font-size-10"); a.putValue(Action.NAME, "10"); a = getTextComponent( ).getActionMap( ).get("font-size-12"); a.putValue(Action.NAME, "12"); a = getTextComponent( ).getActionMap( ).get("font-size-16"); a.putValue(Action.NAME, "16"); a = getTextComponent( ).getActionMap( ).get("font-size-24"); a.putValue(Action.NAME, "24"); } // Add key mappings for font style features. protected void updateInputMap( ) { // Extend the input map used by our text component. InputMap map = getTextComponent( ).getInputMap( ); int mask = Toolkit.getDefaultToolkit( ).getMenuShortcutKeyMask( ); KeyStroke bold = KeyStroke.getKeyStroke(KeyEvent.VK_B, mask, false); KeyStroke italic = KeyStroke.getKeyStroke(KeyEvent.VK_I, mask, false); KeyStroke under = KeyStroke.getKeyStroke(KeyEvent.VK_U, mask, false); map.put(bold, "font-bold"); map.put(italic, "font-italic"); map.put(under, "font-underline"); } // Add font actions to the toolbar. protected JToolBar createToolBar( ) { JToolBar bar = super.createToolBar( ); bar.addSeparator( ); bar.add(getTextComponent( ).getActionMap( ).get("font-bold")).setText(""); bar.add(getTextComponent( ).getActionMap( ).get("font-italic")).setText(""); bar.add(getTextComponent( ).getActionMap( ).get("font-underline")).setText(""); return bar; } // Add font actions to the menu. protected JMenuBar createMenuBar( ) { JMenuBar menubar = super.createMenuBar( ); JMenu font = new JMenu("Font"); menubar.add(font); JMenu style = new JMenu("Style"); JMenu family = new JMenu("Family"); JMenu size = new JMenu("Size"); font.add(style); font.add(family); font.add(size); style.add(getTextComponent( ).getActionMap( ).get("font-bold")); style.add(getTextComponent( ).getActionMap( ).get("font-underline")); style.add(getTextComponent( ).getActionMap( ).get("font-italic")); family.add(getTextComponent( ).getActionMap( ).get("font-family-SansSerif")); family.add(getTextComponent( ).getActionMap( ).get("font-family-Monospaced")); family.add(getTextComponent( ).getActionMap( ).get("font-family-Serif")); size.add(getTextComponent( ).getActionMap( ).get("font-size-10")); size.add(getTextComponent( ).getActionMap( ).get("font-size-12")); size.add(getTextComponent( ).getActionMap( ).get("font-size-16")); size.add(getTextComponent( ).getActionMap( ).get("font-size-24")); // Don't forget that we can define new actions too! size.add(new StyledEditorKit.FontSizeAction("64", 64)); return menubar; } } The last thing we do is create a new action using one of the StyledEditorKit inner classes, to remind ourselves that we're not restricted to those actions defined as defaults by the kit. We're free to create new instances as needed. 23.2.8.1 Saving styled documentsOne feature that's missing from our StyledEditor is the ability to read and write styled text. Unfortunately, StyledEditorKit does not override the read( ) and write( ) methods, so any documents saved from our StyledEditor are saved as plain text. To fix this problem, we'd ideally want to create a new editor kit that saved all the Style and Element information associated with the Document. For now, we'll provide an alternative solution by extending our editor once again and adding the ability to serialize the Document object to a file and then read it back in.[6] Note that we'll actually serialize all the attribute and style information that is part of the document. We can't do the same sort of thing in an editor kit subclass because the editor kit's read( ) methods are set up to read the contents of a file into an existing document. Serializing the entire document and then reading it back would not fit this model, since the process of reading a serialized object creates a new document.
Here's the source for an editor that allows styled documents to be saved and opened without losing their text attributes. All we've done is provided new implementations of the getSaveAction( ) and getOpenAction( ) methods and defined the new actions returned by these methods. // IOStyledEditor.java // import javax.swing.*; import javax.swing.text.*; import java.awt.event.*; import java.io.*; // An extension of StyledEditor that adds document serialization public class IOStyledEditor extends StyledEditor { public static void main(String[] args) { IOStyledEditor te = new IOStyledEditor( ); te.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); te.setVisible(true); } // Provide a new open action. protected Action getOpenAction( ) { if (inAction == null) inAction = new InAction( ); return inAction; } // Provide a new save action. protected Action getSaveAction( ) { if (outAction == null) outAction = new OutAction( ); return outAction; } private Action inAction; private Action outAction; // An action that saves the document as a serialized object class OutAction extends AbstractAction { public OutAction( ) { super("Serialize Out", new ImageIcon("icons/save.gif")); } public void actionPerformed(ActionEvent ev) { JFileChooser chooser = new JFileChooser( ); if (chooser.showSaveDialog(IOStyledEditor.this) != JFileChooser.APPROVE_OPTION) return; File file = chooser.getSelectedFile( ); if (file == null) return; FileOutputStream writer = null; try { Document doc = getTextComponent( ).getDocument( ); writer = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(writer); oos.writeObject(doc); // Write the document. } catch (IOException ex) { JOptionPane.showMessageDialog(IOStyledEditor.this, "File Not Saved", "ERROR", JOptionPane.ERROR_MESSAGE); } finally { if (writer != null) { try { writer.close( ); } catch (IOException x) {} } } } } // An action that reads the document as a serialized object class InAction extends AbstractAction { public InAction( ) { super("Serialize In", new ImageIcon("icons/open.gif")); } public void actionPerformed(ActionEvent ev) { JFileChooser chooser = new JFileChooser( ); if (chooser.showOpenDialog(IOStyledEditor.this) != JFileChooser.APPROVE_OPTION) return; File file = chooser.getSelectedFile( ); if (file == null) return; FileInputStream reader = null; try { reader = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(reader); Object o = ois.readObject( ); // Read the document. getTextComponent( ).setDocument((Document)o); } catch (IOException ex) { JOptionPane.showMessageDialog(IOStyledEditor.this, "File Input Error", "ERROR", JOptionPane.ERROR_MESSAGE); } catch (ClassNotFoundException ex) { JOptionPane.showMessageDialog(IOStyledEditor.this, "Class Not Found", "ERROR", JOptionPane.ERROR_MESSAGE); } finally { if (reader != null) { try { reader.close( ); } catch (IOException x) {} } } } } } As you can see from the code, all we've done is take advantage of the fact that the Swing document classes are serializable. This allows us to write the Document model out to a file and read it back in without losing any of the information contained in the model. If something goes wrong while reading or writing the file, an appropriate warning dialog pops up using the JOptionPane class from Chapter 10. ![]() |
I l@ve RuBoard |
![]() ![]() |