S-JIS[2007-02-02/2009-04-20] 変更履歴

JEditorPane(Swing)

JEditorPaneは、テキストを表示(編集)するためのペイン(領域?)。
HTML文書も一応扱うことが出来る。
スクロールさせたい場合はJScrollPaneに組み合わせて使う。


プレインテキスト

単純な例として、単純(スタイル・装飾を使わない)なテキストを表示する例。

	/**
	 * テキストエディター初期化
	 */
	private void initPane(Container c) {
		JEditorPane editor = new JEditorPane();
		editor.setEditable(true); // 編集可能

		// 初期表示するテキスト
		editor.setText("Hello, Swing");

		c.add(editor);
	}

JTextPane


HTMLテキスト

基礎的なHTMLなら、かなり簡単に表示することが出来る。

	/**
	 * HTMLエディター初期化
	 */
	private void initPane(Container c) {
		JEditorPane editor = new JEditorPane();
		editor.setContentType("text/html");
		editor.setEditable(true); // 編集可能

		// 初期表示するHTML
		editor.setText("<b>Hello</b>, <i>Swing</i>");

		c.add(editor);
	}
		JEditorPane editor = new JEditorPane("text/html", "<b>Hello</b>, <i>Swing</i>");
		editor.setEditable(true); // 編集可能

		c.add(editor);

ただし、デフォルトのパーサーが解釈できないようなHTMLタグは、妙な表示になる。
また、編集も(書き込み・削除・カット&ペーストくらいなら)そのままで出来てしまうが、例えば改行がbrタグになるわけでもない。


HTMLファイルの読み込み

JEditorPaneは、内部でHTMLDocumentクラスを使ってテキスト(文書)を保持している。[/2007-02-05]
ファイルから読み込む場合は、Documentインスタンスを更新してやる。

import javax.swing.text.EditorKit;
import javax.swing.text.html.HTMLDocument;
	private void readHtmlFile(JEditorPane editor, String file_name) {
		HTMLDocument doc = (HTMLDocument) editor.getDocument();
		doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
		editor.setContentType("text/html");

		File f = new File(file_name);
		try {
			URL u = new URL("file:" + f.getParent() + "/");
			doc.setBase(u);
		} catch (MalformedURLException e1) {
			System.out.println(e1);
		}

		EditorKit kit = editor.getEditorKit();

		Reader r = null;
		try {
			r = new FileReader(f);
			kit.read(r, doc, 0);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (r != null) try { r.close(); } catch (IOException e) {}
		}
	}

setBase()を呼んでベースとなるディレクトリを指定することにより、HTML内で相対パスで指定されたスタイルシートやイメージ(画像)ファイルが取得されて表示に反映される。[2007-02-05]

途中でIgnoreCharsetDirectiveという怪しいプロパティをセットしているが、これはHTMLEditorKit#read()の中で使われる。
デフォルトでは、JEditorPaneで指定されているコンテキストタイプHTMLファイル内で指定されているコンテキストタイプが一致しない場合に例外が発生する。IgnoreCharsetDirectiveをTRUEにしておくと、不一致でもエラーにならない。
しかしこういう設定を文字列のプロパティで指定しなきゃいけないなんて、変な設計…。

参考: わたなべごうさんの電波…とどいた?


HTMLファイル書き出し

JEditorPaneで保持しているHTMLをファイルに出力するには、以下のようにする。
(OutputStreamでなく、Writerのwirte()メソッドも用意されている。というか、実体はWriter用

	private void writeHtmlFile(JEditorPane editor, String file_name) {
		Document doc = editor.getDocument();
		EditorKit kit = editor.getEditorKit();

		FileOutputStream os = null;
		try {
			os = new FileOutputStream(file_name);
			kit.write(os, doc, 0, doc.getLength());
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (os != null) try { os.close(); } catch (IOException e) {}
		}
	}

出力してみると分かるが、HTMLは最初に読み込んだものとは違う形で出力されている。
(必要なhtmlタグやbodyタグが追加されたり、改行が変わったりインデントがスペースだったり…)
しかも日本語がコード(&#nnnnn;)で出力される!

多大な余力があれば、独自のwrite()を作るのが良さげ。[2007-02-04]


HTMLフォント変更

JEditorPaneでHTMLを表示するとき、デフォルトのフォントはSerifだかになっている。
JEditorPane#setFont()を使っても、このフォントは変わらない。

これは、暗黙に指定される“bodyタグのスタイル”がそうなっているから。
したがって、bodyタグのデフォルトフォントを変えてやればよい。

import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.StyleSheet;
	private void initFont(JEditorPane editor) {
		HTMLDocument doc = (HTMLDocument) editor.getDocument();
		StyleSheet ss = doc.getStyleSheet();
		StyleSheet[] sss = ss.getStyleSheets();

		for (int i = sss.length - 1; i >= 0; i--) {
			Style body = sss[i].getStyle("body");	//StyleはAttributeSetの具象クラス
			if (body != null) {
				StyleConstants.setFontFamily(body, "MS PGothic");
				StyleConstants.setFontSize(body, 14);
				break;
			}
		}
	}

for文が大きい方から小さい方へ向かうようにしているのは、addStyleSheet()で新しいスタイルシートを追加した場合は先頭(0番)に追加されるようだから。
デフォルトのスタイルシートなら一番最初に登録されるので、きっと末尾に近い番号になるはず。


JDK1.5以降では、HONOR_DISPLAY_PROPERTIESというプロパティーをtrueにしてやることで、setFont()によるフォント指定を有効にすることが出来る。[2009-04-19]

		editor.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);	//setFont()が有効になる

参考: teraiさんのHtmlを使ったJLabelとJEditorPaneの無効化


リンククリック

JEditorPaneでは、編集不可(setEditable(false))の場合は、ハイパーリンク(アンカー<a>〜</a>)をクリックすることが出来る。[2009-04-20]
背景を透過色にしてフォントもラベルに合わせれば、クリック可能なラベルのように扱うことが出来る。

編集不可の場合はリンクのイベントが発生するようになるので、それを捕捉してやればリンククリック時の処理を行える。

import javax.swing.event.HyperlinkListener;
	String str =
		"<a href='http://www.ne.jp/asahi/hishidama/home/tech/java/swing/index.html'>Swing</a>の" +
		"リンクの実験";
	JEditorPane text = new JEditorPane("text/html", str);

	text.setEditable(false);	//編集不可
	text.setOpaque(false);	//背景を透過

	text.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);	//フォントを有効化
	text.setFont(new JLabel().getFont());					//フォントを指定

	text.addHyperlinkListener(new HyperlinkHandler());	//リンクイベントリスナーを登録

リンクのイベントというのは、マウスがそのリンク上に入った時と出た時、およびリンクをクリックした時。
ただしイベントリスナーのメソッドとしては一種類しか無いので、イベントタイプによって判断する必要がある。

import java.net.URL;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
class HyperlinkHandler implements HyperlinkListener {

	@Override
	public void hyperlinkUpdate(HyperlinkEvent e) {
		if (e.getEventType() == EventType.ACTIVATED) {	//クリックされた時
			URL url = e.getURL();

			//デフォルトのブラウザーを使ってリンク先を表示
			Desktop dp = Desktop.getDesktop();
			try {
				dp.browse(url.toURI());
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}
}

参考: teraiさんのHyperlinkを、JLabel、JButton、JEditorPaneで表示


Swing目次へ戻る / Java目次へ戻る / 新機能へ戻る
メールの送信先:ひしだま