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); } }