| JEditorPane |
|---|
JEditorPane is sort of a fancy text area that can display text
derived from different file formats. The built-in version supports
HTML and RTF (Rich Text Format) only, but you can build "editor kits"
to handle special purpose applications. In principle, you
choose the type of document you want to display by calling
setContentType and specify a custom editor kit via setEditorKit.
Note that unless you extend it, legal
choices are "text/html" (the default), "text/plain" (which is also
what you get if you supply an unknow type), and "text/rtf".
In practice, however, JEditorPane is almost always used for displaying
HTML. If you have plain text, you might as well use JTextField.
RTF support is pretty primitive. You put content into the
JEditorPane one of four ways.
JEditorPane is via
the constructor, where you supply either a URL
object or a String corresponding
to a URL (which, in applications, could be a
file: URL to read off the local disk). Note that this throws
IOException, so needs to be in a try/catch block.
setPage on a JEditorPane instance
that was created via the empty constructor. The setPage method also takes
either a URL object or a String, and also throws
IOException. This is generally used when the content
is determined at run-time by some user action.
setText on a JEditorPane instance,
supplying a String that is the actual content,
read, supplying
an InputStream and an HTMLDocument object.
JEditorPane can be editable, but in practice it tends to look
pretty poor, so it is most often used simply to display HTML,
and you call setEditable(false) on it. Finally, as with all
Swing components, scrolling is realized by dropping it in
a JScrollPane. Thus, here's the most
common way you use JEditorPane:
String url = "http://host/path";
try {
JEditorPane htmlPane = new JEditorPane(url);
htmlPane.setEditable(false);
someWindow.add(new JScrollPane(htmlPane);
} catch(IOException ioe) {
System.err.println("Error displaying " + url);
}
JEditorPane to
display HTML text. In such a case, you can detect when the
user selects a link, can determine which link was selected,
and can replace the contents of the JEditorPane with the
document at the specified URL (by using setPage). To
do this, attach a HyperlinkListener (notice that it is
HyperlinkListener, not HyperLinkListener) via
addHyperlinkListener, and implement
the hyperlinkUpdate method to catch events. Once you get the
event, you need to look up its specific type via getEventType
and compare that to HyperlinkEvent.EventType.ACTIVATED.
This last point was not needed in early releases of Swing, but
as of Java 1.2, if you neglect it, then the link will be followed
whenever the mouse simple moves over the link.
Here is an example:
public class SomeWindow extends JFrame implements HyperlinkListener {
private JEditorPane htmlPane;
...
public void hyperlinkUpdate(HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
try {
htmlPane.setPage(event.getURL());
} catch(IOException ioe) {
// Some warning to user
}
}
}
}
JEditorPane that can display
HTML and follow links, you have a simple but functioning Web browser.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
public class Browser extends JFrame implements HyperlinkListener,
ActionListener {
public static void main(String[] args) {
if (args.length == 0)
new Browser("http://www.apl.jhu.edu/~hall/");
else
new Browser(args[0]);
}
private JIconButton homeButton;
private JTextField urlField;
private JEditorPane htmlPane;
private String initialURL;
public Browser(String initialURL) {
super("Simple Swing Browser");
this.initialURL = initialURL;
addWindowListener(new ExitListener());
WindowUtilities.setNativeLookAndFeel();
JPanel topPanel = new JPanel();
topPanel.setBackground(Color.lightGray);
homeButton = new JIconButton("home.gif");
homeButton.addActionListener(this);
JLabel urlLabel = new JLabel("URL:");
urlField = new JTextField(30);
urlField.setText(initialURL);
urlField.addActionListener(this);
topPanel.add(homeButton);
topPanel.add(urlLabel);
topPanel.add(urlField);
getContentPane().add(topPanel, BorderLayout.NORTH);
try {
htmlPane = new JEditorPane(initialURL);
htmlPane.setEditable(false);
htmlPane.addHyperlinkListener(this);
JScrollPane scrollPane = new JScrollPane(htmlPane);
getContentPane().add(scrollPane, BorderLayout.CENTER);
} catch(IOException ioe) {
warnUser("Can't build HTML pane for " + initialURL
+ ": " + ioe);
}
Dimension screenSize = getToolkit().getScreenSize();
int width = screenSize.width * 8 / 10;
int height = screenSize.height * 8 / 10;
setBounds(width/8, height/8, width, height);
setVisible(true);
}
public void actionPerformed(ActionEvent event) {
String url;
if (event.getSource() == urlField)
url = urlField.getText();
else // Clicked "home" button instead of entering URL
url = initialURL;
try {
htmlPane.setPage(new URL(url));
urlField.setText(url);
} catch(IOException ioe) {
warnUser("Can't follow link to " + url + ": " + ioe);
}
}
public void hyperlinkUpdate(HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
try {
htmlPane.setPage(event.getURL());
urlField.setText(event.getURL().toExternalForm());
} catch(IOException ioe) {
warnUser("Can't follow link to "
+ event.getURL().toExternalForm() + ": " + ioe);
}
}
}
private void warnUser(String message) {
JOptionPane.showMessageDialog(this, message, "Error",
JOptionPane.ERROR_MESSAGE);
}
}
Note: also requires
WindowUtilities.java
and ExitListener.java,
shown earlier, and
JIconButton.java,
shown later in this page.
import javax.swing.*;
public class JIconButton extends JButton {
public JIconButton(String file) {
super(new ImageIcon(file));
setContentAreaFilled(false);
setBorderPainted(false);
setFocusPainted(false);
}
}
JEditorPane still only supports a subset
of standard HTML. Many constructs cannot be displayed properly, and
worse yet, many standard constructs crash the JEditorPane, generating
long and ugly error messages. So although writing a simple browser is fun,
it is risky in a real application to accept HTML input that you haven't
tested previously. So perhaps the single best use of JEditorPane is
to display non-editable HTML that you have written (and tested!), supplied as on-line
help for your application. This is such a good idea that Sun has provided
a small package called JavaHelp that helps in this regard by making
an outline (displayed in a JTree), generating an index, and so forth.
See the JavaHelp
home page for more details.