HTML の表示


多目的なテキストコンポーネント

経験ある技術者ほど、HTML を表示するコントロールの開発の困難さがわかります
HTML はエラーを発生させませんし、書き方もクリエイターによって癖があります
そのため、アプリケーションは様々な例外に備えて、それでも正常に表示できるよう
文字列の解析を小泉総理大臣のように柔軟かつ大胆に行わなければなりません

さらに、現代では CSS や JavaScript も標準的な存在になっています
これらに対応できなければ、十分な閲覧ソフトウェアの開発は困難です

実は、Swing は HTML や RFT ドキュメントを表示する機能を提供しています
これは javax.swing.JEditorPane クラスで実装されています
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--javax.swing.JComponent
                    |
                    +--javax.swing.text.JTextComponent
                          |
                          +--javax.swing.JEditorPane

public class JEditorPane extends JTextComponent
このクラスは、次のコンストラクタを公開しています

public JEditorPane()
public JEditorPane(URL initialPage) throws IOException
public JEditorPane(String url) throws IOException
public JEditorPane(String type , String text)

initialPage には、表示するドキュメントを示す URL を
url には表示するドキュメントの URL の文字列表現を指定します
これらを用いた場合は、そのファイルを参照して初期化されます

type には指定されたテキストの MIME 形式を
text には type で指定した MIME に従った形式の文字列を指定します
デフォルトでは text/plain、text/html、text/rtf のいずれかを指定できます

例えば type と text を指定するコンストラクタを用いれば
コンポーネントに表示する書式情報を HTML や RTF 形式を用いて行えます
Web 開発経験者などであれば、このような手法は直感的なので好まれるでしょう
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test {
	public static void main(String args[]) {
		JFrame frame = new JFrame("Kitty on your lap");
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosed(WindowEvent e) {
				System.exit(0);
			}
		});

		try {
			JEditorPane html = new JEditorPane(args[0]);
			frame.getContentPane().add(new JScrollPane(html));
		}
		catch(Exception err) { System.out.println(err); }
		frame.setSize(400 , 400);
		frame.setVisible(true);
	}
}


このプログラムは、コマンドライン引数から指定した URL 指定します
プログラムは、指定された URL のファイルを表示するというものです
上の図は、これを作成している当時のこの Web のホームページです

しかし、実は Swing の HTML 処理にはいくつもの問題があります
これらの処理は将来において問題が解決されると Sun は主張しています
少なくとも Java 1.4.0 の時点では、まともな動作を期待するべきではありません
XHTML や不正な HTML を平然と使っているファイルを指定すれば、とたんに例外となります

MIME タイプは JEditorPane.setContentType() で指定することができます
MIME に適応したテキストを挿入するには、これまで通り setText() を使って行います
MIME タイプの取得には JEditorPane.getContentPane() を使います

public final void setContentType(String type)
public final String getContentType()

type には MIME タイプを指定します
ページを新たに設定するには JEditorPane.setPage() を使います
現在のページは JEditorPane.getPage() で得ることができます

public void setPage(String url) throws IOException
public void setPage(URL page) throws IOException
public URL getPage()

url には、新たに表示するページの URL の文字列表現を
page には表示するページの URL を指定します

ところで、こうしたページの場合は編集されたくないという場合があることでしょう
表示用としてテキストコンポーネントを使いたい場合は
JTextComponent.setEditable() メソッドを使って編集可能状態を設定します
編集可能状態は JTextComponent.isEditable() で取得できます

public void setEditable(boolean b)
public boolean isEditable()

b には、編集可能であれば true を指定します
デフォルトでは、編集可能状態の HTML はコメントなどの不要な情報も表示してしまいます
これは、閲覧ソフトでは必要としない情報です
しかし、編集不可状態の場合は、そのような不要な情報は表示しません
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test extends JFrame implements ActionListener {
	JEditorPane html = new JEditorPane();
	JTextField addr = new JTextField("http://");

	public static void main(String args[]) {
		(new Test()).setVisible(true);
	}
	public Test() {
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosed(WindowEvent e) {
				System.exit(0);
			}
		});

		addr.addActionListener(this);
		html.setEditable(false);

		getContentPane().add(addr , BorderLayout.NORTH);
		getContentPane().add(new JScrollPane(html));
		setSize(400 , 300);
	}

	public void actionPerformed(ActionEvent e) {
		try { html.setPage(addr.getText()); }
		catch(Exception err) {}
	}
}
このプログラムは、編集不可状態のHTML表示用の簡易ブラウザとして機能します
上部のアドレス入力フィールドにアドレスを入力し Enter キーを押してください


ハイパーリンク

ここまで HTML が表示できれば、誰もがハイパーリンクをしたいと思うでしょう
ですが、デフォルトではハイパーリンクはサポートされておりません
ハイパーリンクを行うには、イベントを処理する必要があります

編集不可状態の JEditorPane のアンカーテキストにマウスが移動した場合
javax.swing.event.HyperlinkListener が呼び出されます

public interface HyperlinkListener extends EventListener

このインターフェイスは、ハイパーリンクに対するイベントが発生した場合の
HyperlinkListener.hyperlinkUpdate() メソッドが宣言されています

public void hyperlinkUpdate(HyperlinkEvent e)

e にはハイパーリンクの情報をパッケージ化したイベントクラスを指定します
これは javax.swing.event.HyperlinkEvent クラスです
java.lang.Object
  |
  +--java.util.EventObject
        |
        +--javax.swing.event.HyperlinkEvent

public class HyperlinkEvent extends EventObject
このクラスは次のようなコンストラクタを公開しています
おそらく、ほとんどの開発者はこのクラスをインスタンス化することはないでしょう
public HyperlinkEvent(
	Object source ,
	HyperlinkEvent.EventType type , URL u
)
public HyperlinkEvent(
	Object source , HyperlinkEvent.EventType type ,
	URL u , String desc
)
public HyperlinkEvent(
	Object source , HyperlinkEvent.EventType type ,
	URL u , String desc , Element sourceElement
)
source には、イベントを発生させたオブジェクトを
type には、ハイパーリンクに対するアクションのタイプを指定します
desc にはリンクの説明を表す文字列を
sourceElement にはアンカーを表す Document 内の要素を示す Element を指定します

Element インターフェイスは、SGML における要素特性を表現するためのものです
HTML を記述/解析する構造の基本となるインターフェイスですが、この場では省略します

HyperlinkEvent.EventType は、ハイパーリンクのイベントがどのようなものかを表します
ハイパーリンクイベントは、マウスカーソルがリンク文字列に重なった時や
リンク文字をクリックしたときなどに発生するため、これを解析することができます
これは javax.swing.event.HyperlinkEvent.EventType クラスが
定義している次のいずれかのフィールド定数で表すことができます

public static final class HyperlinkEvent.EventType extends Object

定数解説
public static final HyperlinkEvent.EventType ACTIVATED クリックした
public static final HyperlinkEvent.EventType ENTERED マウスカーソルが入った
public static final HyperlinkEvent.EventType EXITED マウスカーソルが出た

このイベントタイプを得るには HyperlinkEvent.getEventType() を使います
また、リンク先の URL は HyperlinkEvent.getURL() で得ることができます

public HyperlinkEvent.EventType getEventType()
public URL getURL()

これらの情報を使って、ページを移動させることができるでしょう
ハイパーリンクイベントを実現するには、リスナを
JEditorPane.addHyperlinkListener() に登録しなければいけません
リスナの解除は JEditorPane.removeHyperlinkListener() で行えます

public void addHyperlinkListener(HyperlinkListener listener)
public void removeHyperlinkListener(HyperlinkListener listener)

listener には登録、または削除するリスナを指定します
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class Test extends JFrame implements ActionListener , HyperlinkListener {
	JEditorPane html = new JEditorPane();
	JTextField addr = new JTextField("http://");

	public static void main(String args[]) {
		(new Test()).setVisible(true);
	}
	public Test() {
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosed(WindowEvent e) {
				System.exit(0);
			}
		});

		addr.addActionListener(this);
		html.setEditable(false);
		html.addHyperlinkListener(this);

		getContentPane().add(addr , BorderLayout.NORTH);
		getContentPane().add(new JScrollPane(html));
		setSize(400 , 300);
	}
	public void actionPerformed(ActionEvent e) {
		try { html.setPage(addr.getText()); }
		catch(Exception err) {}
	}
	public void hyperlinkUpdate(HyperlinkEvent e) {
		if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) return;
		String url = e.getURL().toString();
		addr.setText(url);
		try { html.setPage(url); } catch(Exception err) {}
	}
}
このプログラムは、リンク文字や画像をクリックすることによって
ハイパーリンクイベントが発生し、ページを移動することができます
ハイパーリンクイベントでは、イベントがクリックによって行われたのかを確認し
クリックによって発生した時のみ、ページを変更します



前のページへ戻る次のページへ