JavaFX: WYSIWYGエディタを作る
この記事は2014年のJavaFX Advent Calendarの5日目の記事です。
前日の記事はmike_neckさんのJavaFXで画面を作るときにFXMLを小さく作るです。
明日の記事はKatsumi Kokuzawaさんです。
JavaFXでHTMLのWYSIWYGエディタを作れないかな、と考えてたら、そのものずばりHTMLEditorというクラスがあります。
そのチュートリアルのサンプルコードをほんの少しカスタマイズして、既存のWebページを読み込んで、それをHTMLEditorで編集して、編集結果をブラウザ表示するというサンプルを作ってみました。
こんな感じ。

左側のセピアのブラウザがオリジナルのWebページです(ブラウザ側でセピアトーン効果をかけています)。真ん中上段のHTMLEditorで編集可能で、「Load Content in Browser」ボタンを押すと、下段のテキストエリアに編集済みのHTMLコードと、右側のブラウザに編集結果のページが表示されます。
ブラウザからHTMLのソースを取得してHTMLEditorにセットする部分が地味に面倒です。一発で取得できないものだろうか。
玩具みたいなものですが、複雑なページの一部を編集した際のHTMLソースが欲しい場合などに使えそうです。
import java.io.StringWriter;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Worker;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.effect.SepiaTone;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.web.HTMLEditor;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class HTMLEditorSample extends Application {
@Override
public void start(Stage stage) {
stage.setTitle("HTMLEditor Sample");
stage.setWidth(500);
stage.setHeight(500);
Scene scene = new Scene(new Group());
// 横にレイアウトする為のHBoxを追加
HBox base = new HBox();
VBox root = new VBox();
root.setPadding(new Insets(8, 8, 8, 8));
root.setSpacing(5);
root.setAlignment(Pos.BOTTOM_LEFT);
final HTMLEditor htmlEditor = new HTMLEditor();
htmlEditor.setStyle("-fx-font: 12 cambria; -fx-border-color: brown; -fx-border-style: dotted; -fx-border-width: 2;");
htmlEditor.setPrefHeight(245);
//HTMLのソースコードを表示するテキストエリアを追加
final TextArea htmlCode = new TextArea();
htmlCode.setWrapText(true);
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
//ブラウザにセピアトーン効果をかける
browser.setEffect(new SepiaTone());
ScrollPane scrollPane = new ScrollPane();
scrollPane.getStyleClass().add("noborder-scroll-pane");
scrollPane.setStyle("-fx-background-color: white");
scrollPane.setContent(browser);
scrollPane.setFitToWidth(true);
scrollPane.setPrefHeight(180);
//編集後のページを表示するWebViewを追加
final WebView viewer = new WebView();
final WebEngine engine = viewer.getEngine();
Button showHTMLButton = new Button("Load Content in Browser");
root.setAlignment(Pos.CENTER);
showHTMLButton.setOnAction(arg0 -> {
engine.loadContent(htmlEditor.getHtmlText());
//テキストエリアにHTMLソースコードを表示
htmlCode.setText(htmlEditor.getHtmlText());
});
// ページのロードが終了したときの処理。HTMLEditorにコンテンツを読み込む。
Platform.runLater(() -> {
webEngine.getLoadWorker().stateProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue == Worker.State.SUCCEEDED) {
Document doc = webEngine.getDocument();
DOMSource source = new DOMSource(doc);
StringWriter result = new StringWriter();
TransformerFactory transFactory = TransformerFactory.newInstance();
try {
Transformer transformer = transFactory.newTransformer();
transformer.transform(source, new StreamResult(result));
htmlCode.setText(result.toString());
htmlEditor.setHtmlText(result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
});
webEngine.load("http://soutoku.hatenablog.com/");
root.getChildren().addAll(htmlEditor, showHTMLButton, htmlCode);
//左からオリジナルページのブラウザ、エディタ、編集後のページのブラウザを並べる
base.getChildren().addAll(browser, root, viewer);
scene.setRoot(base);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}