﻿{"id":1772,"date":"2014-12-11T01:07:57","date_gmt":"2014-12-10T16:07:57","guid":{"rendered":"http:\/\/yucchi.jp\/blog\/?p=1772"},"modified":"2014-12-11T01:19:03","modified_gmt":"2014-12-10T16:19:03","slug":"swingnode-%e3%81%a8-textflow","status":"publish","type":"post","link":"http:\/\/yucchi.jp\/blog\/?p=1772","title":{"rendered":"SwingNode \u3068 TextFlow"},"content":{"rendered":"<p>\u3053\u306e\u30a8\u30f3\u30c8\u30ea\u30fc\u306f\u3001<a href=\"http:\/\/www.adventar.org\/calendars\/380\" target=\"_blank\">JavaFX Advent Calendar 2014<\/a>, 11\u65e5\u76ee\u306e\u304a\u307e\u3051\u3067\u3059\u3002<\/p>\n<p>\u6628\u65e5\u306f @toruwest \u3055\u3093\u306e\u300c<a href=\"http:\/\/toruwest.hatenablog.com\/entry\/2014\/12\/10\/110731\" target=\"_blank\">JavaFX\u306eTreeView\u3067\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3057\u3066\u307f\u308b<\/a>\u300d\u3067\u3057\u305f\u3002<\/p>\n<p>\u660e\u65e5\u306f @skrb \u3055\u3093\u306e\u300cJava Advent Calendar\u3068\u4e00\u7dd2\u306b\u306a\u306b\u304b\u66f8\u304d\u307e\u3059\u300d\u3067\u3059\u3002<\/p>\n<p>\u4eca\u5e74\u3082 JavaFX \u3067\u3044\u308d\u3044\u308d\u306a\u3053\u3068\u3092\u697d\u3057\u3093\u3060\u306e\u3067\u305d\u306e\u3046\u3061\u306e\u4e00\u90e8\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002<\/p>\n<p>\u306f\u3058\u3081\u306b\u3001Swing \u3067\u306f JTextPane \u3063\u3066\u306e\u304c\u3042\u3063\u3066\u666e\u901a\u306e JTextArea \u3088\u308a\u3082\u67d4\u8edf\u306b\u6271\u3048\u307e\u3059\u3002<\/p>\n<p>\u30c6\u30ad\u30b9\u30c8\u306e\u30b9\u30bf\u30a4\u30eb\u3092\u7c21\u5358\u306b\u5909\u66f4\u3067\u304d\u305f\u308a\u3057\u3066\u3068\u3066\u3082\u4fbf\u5229\u3067\u3057\u305f\u3002<\/p>\n<p>JavaFX \u306b JTextPane \u306b\u76f8\u5f53\u3059\u308b\u3082\u306e\u304c\u3042\u308b\u304b\u3068\u8a00\u3048\u3070\u7121\u3055\u305d\u3046\u3067\u3059\u3002<\/p>\n<p>\u7de8\u96c6\u3067\u304d\u306a\u304f\u3066\u8868\u793a\u3060\u3051\u306a\u3089 TextFlow \u304c\u304b\u306a\u308a\u5f37\u529b\u306b\u4f7f\u3048\u307e\u3059\u3002<\/p>\n<p>\u79c1\u306f TextFlow \u3092\u4f7f\u3046\u306e\u3092\u8e8a\u8e87\u3063\u3066\u306a\u3093\u3068\u304b JTextPane \u3092 JavaFX \u3067\u4f7f\u3063\u3066\u3084\u308d\u3046\u3068 SwingNode \u306b\u624b\u3092\u51fa\u3057\u3066\u3057\u307e\u3044\u307e\u3057\u305f\u3002<\/p>\n<p>\u4f55\u3092\u3057\u305f\u304b\u3063\u305f\u304b\u3068\u3044\u3046\u3068\u30c6\u30ad\u30b9\u30c8\u691c\u7d22\u3067\u691c\u7d22\u6587\u5b57\u306b\u30d2\u30c3\u30c8\u3057\u305f\u3089\u305d\u306e\u6587\u5b57\u3092\u826f\u304f\u89e3\u308b\u3088\u3046\u306b\u8272\u3065\u3051\u3001\u592a\u5b57\u8868\u793a\u3092\u3057\u305f\u304b\u3063\u305f\u3060\u3051\u3067\u3059\u3002<\/p>\n<p>SwingNode \u306f javafx.embed.swing.SwingNode \u30af\u30e9\u30b9\u3067\u3053\u308c\u3092\u4f7f\u3046\u306b\u306f<\/p>\n<p>public void setContent(JComponent content)<\/p>\n<p>\u3067 Swing \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u30bb\u30c3\u30c8\u3057\u307e\u3059\u3002<\/p>\n<p>\u305f\u3060\u3057\u3001JavaFX \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u308f\u305a\u306b<\/p>\n<p>public static void invokeLater(Runnable doRun) \u30e1\u30bd\u30c3\u30c9\u3092\u4f7f\u7528\u3057\u3066<\/p>\n<p>doRun.run()\u3092\u3001AWT\u30a4\u30d9\u30f3\u30c8\u30fb\u30c7\u30a3\u30b9\u30d1\u30c3\u30c1\u30fb\u30b9\u30ec\u30c3\u30c9\u3067\u975e\u540c\u671f\u7684\u306b\u5b9f\u884c\u3055\u305b\u307e\u3059\u3002<\/p>\n<p>\u3053\u306e\u30e1\u30bd\u30c3\u30c9\u306f\u5b9f\u969b\u306f java.awt.EventQueue.invokeLater()\u3092\u547c\u3073\u51fa\u3057\u3066\u3044\u308b\u3060\u3051\u3067\u3059\u3002<\/p>\n<p>Swing \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u64cd\u4f5c\u3092\u3059\u308b\u3068\u304d\u306b\u306f\u9762\u5012\u3060\u3051\u3069 AWT \u306e\u30b9\u30ec\u30c3\u30c9\u3067\u3063\u3066\u3053\u3068\u306e\u3088\u3046\u3067\u3059\u3002<\/p>\n<p>\u306f\u3063\u304d\u308a\u8a00\u3063\u3066\u3088\u3063\u307d\u3069\u306e\u4e8b\u60c5\u304c\u306a\u3044\u304b\u304e\u308a SwingNode \u306a\u3093\u3066\u4f7f\u304a\u3046\u3068\u601d\u308f\u306a\u3044\u3002(^_^;)<\/p>\n<p>\u3044\u3064\u3082\u901a\u308a\u96d1\u306a\u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0\u3092\u8f09\u305b\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<p><pre title=\"FXMLDocument.fxml\">\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\r\n<?import javafx.scene.text.*?>\r\n<?import javafx.geometry.*?>\r\n<?import javafx.embed.swing.*?>\r\n<?import java.lang.*?>\r\n<?import java.util.*?>\r\n<?import javafx.scene.*?>\r\n<?import javafx.scene.control.*?>\r\n<?import javafx.scene.layout.*?>\r\n\r\n<AnchorPane id=\"AnchorPane\" maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"330.0\" prefWidth=\"400.0\" xmlns=\"http:\/\/javafx.com\/javafx\/8\" xmlns:fx=\"http:\/\/javafx.com\/fxml\/1\" \r\n\r\nfx:controller=\"jp.yucchi.swingnodeexample.FXMLDocumentController\">\r\n   <children>\r\n      <VBox prefHeight=\"330.0\" prefWidth=\"400.0\" AnchorPane.bottomAnchor=\"0.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.topAnchor=\"0.0\">\r\n         <children>\r\n            <TextArea fx:id=\"textArea\" prefHeight=\"125.0\" prefWidth=\"400.0\" wrapText=\"true\">\r\n               <font>\r\n                  <Font size=\"16.0\" \/>\r\n               <\/font>\r\n               <VBox.margin>\r\n                  <Insets left=\"10.0\" right=\"10.0\" top=\"10.0\" \/>\r\n               <\/VBox.margin>\r\n            <\/TextArea>\r\n            <HBox prefHeight=\"50.0\" prefWidth=\"400.0\">\r\n               <children>\r\n                  <TextField fx:id=\"textField\" prefHeight=\"40.0\" prefWidth=\"190.0\">\r\n                     <HBox.margin>\r\n                        <Insets bottom=\"5.0\" right=\"5.0\" top=\"5.0\" \/>\r\n                     <\/HBox.margin>\r\n                     <padding>\r\n                        <Insets bottom=\"3.0\" left=\"3.0\" right=\"3.0\" top=\"3.0\" \/>\r\n                     <\/padding>\r\n                     <font>\r\n                        <Font name=\"Monospaced Regular\" size=\"16.0\" \/>\r\n                     <\/font>\r\n                  <\/TextField>\r\n                  <ToggleButton fx:id=\"search\" mnemonicParsing=\"false\" onAction=\"#handleSearch\" prefHeight=\"40.0\" prefWidth=\"190.0\" text=\"Search\">\r\n                     <HBox.margin>\r\n                        <Insets bottom=\"5.0\" left=\"5.0\" top=\"5.0\" \/>\r\n                     <\/HBox.margin>\r\n                     <font>\r\n                        <Font size=\"16.0\" \/>\r\n                     <\/font>\r\n                  <\/ToggleButton>\r\n               <\/children>\r\n               <padding>\r\n                  <Insets left=\"10.0\" right=\"10.0\" \/>\r\n               <\/padding>\r\n            <\/HBox>\r\n            <SwingNode id=\"swingNode\" fx:id=\"swingNode\">\r\n               <VBox.margin>\r\n                  <Insets left=\"10.0\" right=\"10.0\" \/>\r\n               <\/VBox.margin>\r\n            <\/SwingNode>\r\n         <\/children>\r\n      <\/VBox>\r\n   <\/children>\r\n<\/AnchorPane>\r\n\r\n<\/pre>\n<\/p>\n<p><pre title=\"SwingNodeExample.java\">\r\npackage jp.yucchi.swingnodeexample;\r\n\r\nimport javafx.application.Application;\r\nimport javafx.fxml.FXMLLoader;\r\nimport javafx.scene.Parent;\r\nimport javafx.scene.Scene;\r\nimport javafx.stage.Stage;\r\n\r\n\/**\r\n *\r\n * @author Yucchi\r\n *\/\r\npublic class SwingNodeExample extends Application {\r\n\r\n    @Override\r\n    public void start(Stage stage) throws Exception {\r\n        Parent root = FXMLLoader.load(getClass().getResource(\"FXMLDocument.fxml\"));\r\n\r\n        Scene scene = new Scene(root);\r\n        stage.setTitle(\"SwingNode Example\");\r\n        stage.setScene(scene);\r\n        stage.setResizable(false);\r\n        stage.show();\r\n\r\n    }\r\n\r\n    \/**\r\n     * @param args the command line arguments\r\n     *\/\r\n    public static void main(String[] args) {\r\n        launch(args);\r\n    }\r\n\r\n}\r\n\r\n<\/pre>\n<pre title=\"FXMLDocumentController.java\">\r\npackage jp.yucchi.swingnodeexample;\r\n\r\nimport java.awt.Color;\r\nimport java.awt.Dimension;\r\nimport java.awt.Font;\r\nimport java.net.URL;\r\nimport java.util.ResourceBundle;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\nimport javafx.beans.binding.Bindings;\r\nimport javafx.embed.swing.SwingNode;\r\nimport javafx.event.ActionEvent;\r\nimport javafx.fxml.FXML;\r\nimport javafx.fxml.Initializable;\r\nimport javafx.scene.control.TextArea;\r\nimport javafx.scene.control.TextField;\r\nimport javafx.scene.control.ToggleButton;\r\nimport javax.swing.JScrollPane;\r\nimport javax.swing.JTextPane;\r\nimport javax.swing.SwingUtilities;\r\nimport javax.swing.text.DefaultEditorKit;\r\nimport javax.swing.text.DefaultStyledDocument;\r\nimport javax.swing.text.SimpleAttributeSet;\r\nimport javax.swing.text.StyleConstants;\r\n\r\n\/**\r\n *\r\n * @author Yucchi\r\n *\/\r\npublic class FXMLDocumentController implements Initializable {\r\n\r\n    @FXML\r\n    TextArea textArea;\r\n\r\n    @FXML\r\n    TextField textField;\r\n\r\n    @FXML\r\n    ToggleButton search;\r\n\r\n    @FXML\r\n    SwingNode swingNode;\r\n\r\n    private JTextPane textPane;\r\n\r\n    @FXML\r\n    public void handleSearch(ActionEvent event) {\r\n\r\n        if (search.isSelected()) {\r\n            search.setText(\"Clear\");\r\n            makeSearchText();\r\n        } else {\r\n            search.setText(\"Search\");\r\n            textArea.setText(\"\");\r\n            textField.setText(\"\");\r\n\r\n            SwingUtilities.invokeLater(() -> {\r\n                textPane.setText(null);\r\n            });\r\n        }\r\n\r\n    }\r\n\r\n    @Override\r\n    public void initialize(URL url, ResourceBundle rb) {\r\n\r\n        SwingUtilities.invokeLater(() -> {\r\n\r\n            textPane = new JTextPane();\r\n            textPane.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 16));\r\n            textPane.setPreferredSize(new Dimension(390, 145));\r\n\r\n            JScrollPane scroll = new JScrollPane(textPane);\r\n            scroll.setWheelScrollingEnabled(true);\r\n\r\n            swingNode.setContent(scroll);\r\n\r\n        });\r\n\r\n        search.disableProperty()\r\n                .bind(\r\n                        Bindings.when(textArea.textProperty().isEmpty().or(textField.textProperty().isEmpty()))\r\n                        .then(true)\r\n                        .otherwise(false));\r\n\r\n    }\r\n\r\n    private void makeSearchText() {\r\n\r\n        SwingUtilities.invokeLater(() -> {\r\n            textPane.setText(textArea.getText());\r\n            final SimpleAttributeSet set = new SimpleAttributeSet();\r\n            StyleConstants.setBold(set, true);\r\n            StyleConstants.setBackground(set, Color.WHITE);\r\n            StyleConstants.setForeground(set, Color.RED);\r\n            final DefaultStyledDocument document = (DefaultStyledDocument) textPane.getDocument();\r\n            document.putProperty(DefaultEditorKit.EndOfLineStringProperty, \"\\n\");\r\n\r\n            final Pattern thePattern = Pattern.compile(textField.getText());\r\n            final Matcher matcher = thePattern.matcher(textArea.getText());\r\n\r\n            while (matcher.find()) {\r\n                int start = matcher.start();\r\n                int length = matcher.end() - start;\r\n                document.setCharacterAttributes(start, length, set, false);\r\n\r\n            }\r\n\r\n        });\r\n\r\n    }\r\n\r\n}\r\n\r\n<\/pre>\n<\/p>\n<p>\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5b9f\u884c\u7d50\u679c\u306f\u6b21\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/1.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"1\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"1\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/1_thumb.png\" width=\"404\" height=\"364\"><\/a><\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/2.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"2\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"2\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/2_thumb.png\" width=\"404\" height=\"359\"><\/a><\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/3.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"3\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"3\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/3_thumb.png\" width=\"404\" height=\"362\"><\/a><\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/4.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"4\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"4\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/4_thumb.png\" width=\"404\" height=\"359\"><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>\u3044\u3061\u304a\u3046\u52d5\u304f\u3051\u3069\u898b\u6804\u3048\u304c\u826f\u3044\u3082\u306e\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u306d\u3002<\/p>\n<p>\u3061\u306a\u307f\u306b\u79c1\u306f\u7591\u308a\u6df1\u3044\u4eba\u9593\u306a\u306e\u3067\u8a66\u3057\u306b AWT \u306e\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u308f\u306a\u3051\u308c\u3070\u672c\u5f53\u306b\u99c4\u76ee\uff1f\u306a\u306e\u304b\u8a66\u3057\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n<p>\u30b3\u30f3\u30d1\u30a4\u30eb\u306f\u901a\u308a\u307e\u3057\u305f\u3002<\/p>\n<p>\u5b9f\u884c\u6642\u30a8\u30e9\u30fc\u3067\u3082\u51fa\u308b\u306e\u304b\u306a\u3068\u601d\u3044\u304d\u3084\u4f55\u3082\u8d77\u3053\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002<\/p>\n<p>\u3053\u306e\u3088\u3046\u306a\u5c0f\u3055\u306a\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u306f\u306f\u3063\u304d\u308a\u3057\u305f\u4e0d\u5177\u5408\u304c\u51fa\u306a\u3044\u3088\u3046\u3067\u3059\u3002<\/p>\n<p>\u88cf\u3092\u8fd4\u305b\u3070\u975e\u5e38\u306b\u5371\u967a\u3060\u3068\u3044\u3046\u3053\u3068\u306b\u306a\u308b\u306e\u304b\u306a\uff1f<\/p>\n<p>\u3082\u3046\u4e00\u3064\u6c17\u304c\u304b\u308a\u306a\u3053\u3068\u306f\u6642\u3005\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u8d77\u52d5\u6642\u306b\u9ed2\u304f\u306a\u3063\u3066\u3057\u307e\u3046\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<p>\u3084\u3063\u3071\u308a\u4f55\u304b\u7121\u7406\u304c\u3042\u308b\u306e\u304b\u3082\u3057\u308c\u306a\u3044\u3002\uff08\u5358\u306a\u308b\u30d0\u30b0\u3060\u3068\u601d\u3046\u3002\uff09<\/p>\n<p>\u305d\u3093\u306a\u3053\u3093\u306a\u3067\u305b\u3063\u304b\u304f JavaFX \u3067\u30d7\u30ed\u30b0\u30e9\u30e0\u7d44\u3080\u3093\u3060\u304b\u3089\u53e4\u3044 Swing \u306a\u3093\u3066\u9762\u5012\u306a\u601d\u3044\u3057\u3066\u307e\u3067\u4f7f\u3044\u305f\u304f\u306a\u3044\u3088\u306d\uff01<\/p>\n<p>\u305d\u3053\u3067 TextFlow \u3092\u4f7f\u3063\u3066\u307f\u308b\u3053\u3068\u306b\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>TextFlow \u306f JTextPane \u3068\u9055\u3063\u3066\u7de8\u96c6\u304c\u3067\u304d\u307e\u305b\u3093\u3002<\/p>\n<p>\u305f\u3060\u8868\u793a\u3059\u308b\u3060\u3051\u3067\u3059\u3002<\/p>\n<p>\u4f7f\u3044\u65b9\u3082\u81f3\u3063\u3066\u7c21\u5358\u3067\u3059\u3002<\/p>\n<p>javafx.scene.text.Text \u30af\u30e9\u30b9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u751f\u6210\u3057\u305d\u308c\u306b\u30c6\u30ad\u30b9\u30c8\u53ca\u3073\u66f8\u5f0f\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<p>\u305d\u306e Text \u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092 TextFlow \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u751f\u6210\u6642\u306e\u30b3\u30f3\u30b9\u30c8\u30e9\u30af\u30bf\u306e\u5f15\u6570\u3068\u3057\u3066\u6e21\u3057\u3066\u3042\u3052\u308c\u3070\u3044\u3044\u3060\u3051\u3067\u3059\u3002<\/p>\n<p>\u3082\u3057\u304f\u306f textFlow.getChildren().add(text); \u3068\u3057\u3066 TextFlow \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u52a0\u3048\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\u7c21\u5358\u306b\u4f7f\u3048\u3066\u30b9\u30bf\u30a4\u30eb\u306e\u81ea\u7531\u5ea6\u3082 JtextPane \u3088\u308a\u9059\u304b\u306b\u9ad8\u3044\u306e\u3067\u4f7f\u3044\u9053\u306f\u3042\u308b\u304b\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<p>Text \u306e\u30b9\u30bf\u30a4\u30eb\u306f public final void setStyle(String value) \u3092\u4f7f\u3063\u3066\u8a2d\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<p>\u5f15\u6570\u306f\u30a4\u30f3\u30e9\u30a4\u30f3 CSS \u3092\u4e0e\u3048\u308b\u3060\u3051\u306e\u304a\u624b\u8efd\u4ed5\u69d8\u3067\u3059\u3002<\/p>\n<p>TextFlow \u3092\u4f7f\u3063\u305f\u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0\u3082\u8f09\u305b\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<p><pre title=\"FXMLDocument.fxml\">\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\r\n<?import javafx.scene.text.*?>\r\n<?import javafx.geometry.*?>\r\n<?import javafx.embed.swing.*?>\r\n<?import java.lang.*?>\r\n<?import java.util.*?>\r\n<?import javafx.scene.*?>\r\n<?import javafx.scene.control.*?>\r\n<?import javafx.scene.layout.*?>\r\n\r\n<AnchorPane id=\"AnchorPane\" maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"330.0\" prefWidth=\"400.0\" xmlns=\"http:\/\/javafx.com\/javafx\/8\" xmlns:fx=\"http:\/\/javafx.com\/fxml\/1\" \r\n\r\nfx:controller=\"jp.yucchi.textflowexample.FXMLDocumentController\">\r\n   <children>\r\n      <VBox prefHeight=\"330.0\" prefWidth=\"400.0\" AnchorPane.bottomAnchor=\"0.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.topAnchor=\"0.0\">\r\n         <children>\r\n            <TextArea fx:id=\"textArea\" prefHeight=\"125.0\" prefWidth=\"400.0\" wrapText=\"true\">\r\n               <font>\r\n                  <Font size=\"16.0\" \/>\r\n               <\/font>\r\n               <VBox.margin>\r\n                  <Insets left=\"10.0\" right=\"10.0\" top=\"10.0\" \/>\r\n               <\/VBox.margin>\r\n            <\/TextArea>\r\n            <HBox prefHeight=\"50.0\" prefWidth=\"400.0\">\r\n               <children>\r\n                  <TextField fx:id=\"textField\" prefHeight=\"40.0\" prefWidth=\"190.0\">\r\n                     <HBox.margin>\r\n                        <Insets bottom=\"5.0\" right=\"5.0\" top=\"5.0\" \/>\r\n                     <\/HBox.margin>\r\n                     <padding>\r\n                        <Insets bottom=\"3.0\" left=\"3.0\" right=\"3.0\" top=\"3.0\" \/>\r\n                     <\/padding>\r\n                     <font>\r\n                        <Font name=\"Monospaced Regular\" size=\"16.0\" \/>\r\n                     <\/font>\r\n                  <\/TextField>\r\n                  <ToggleButton fx:id=\"search\" mnemonicParsing=\"false\" onAction=\"#handleSearch\" prefHeight=\"40.0\" prefWidth=\"190.0\" text=\"Search\">\r\n                     <HBox.margin>\r\n                        <Insets bottom=\"5.0\" left=\"5.0\" top=\"5.0\" \/>\r\n                     <\/HBox.margin>\r\n                     <font>\r\n                        <Font size=\"16.0\" \/>\r\n                     <\/font>\r\n                  <\/ToggleButton>\r\n               <\/children>\r\n               <padding>\r\n                  <Insets left=\"10.0\" right=\"10.0\" \/>\r\n               <\/padding>\r\n            <\/HBox>\r\n            <ScrollPane prefHeight=\"145.0\" prefWidth=\"380.0\">\r\n               <content>\r\n                  <TextFlow fx:id=\"textFlow\" prefHeight=\"140.0\" prefWidth=\"380.0\" style=\"-fx-background-color: white;\" \/>\r\n               <\/content>\r\n               <VBox.margin>\r\n                  <Insets left=\"10.0\" right=\"10.0\" \/>\r\n               <\/VBox.margin>\r\n            <\/ScrollPane>\r\n         <\/children>\r\n      <\/VBox>\r\n   <\/children>\r\n<\/AnchorPane>\r\n\r\n<\/pre>\n<\/p>\n<p><pre title=\"TextFlowExample.java\">\r\npackage jp.yucchi.textflowexample;\r\n\r\nimport javafx.application.Application;\r\nimport javafx.fxml.FXMLLoader;\r\nimport javafx.scene.Parent;\r\nimport javafx.scene.Scene;\r\nimport javafx.stage.Stage;\r\n\r\n\/**\r\n *\r\n * @author Yucchi\r\n *\/\r\npublic class TextFlowExample extends Application {\r\n\r\n    @Override\r\n    public void start(Stage stage) throws Exception {\r\n        Parent root = FXMLLoader.load(getClass().getResource(\"FXMLDocument.fxml\"));\r\n\r\n        Scene scene = new Scene(root);\r\n        stage.setTitle(\"TextFlow Example\");\r\n        stage.setScene(scene);\r\n        stage.show();\r\n    }\r\n\r\n    \/**\r\n     * @param args the command line arguments\r\n     *\/\r\n    public static void main(String[] args) {\r\n        launch(args);\r\n    }\r\n\r\n}\r\n\r\n<\/pre>\n<\/p>\n<p><pre title=\"FXMLDocumentController.java\">\r\npackage jp.yucchi.textflowexample;\r\n\r\nimport java.net.URL;\r\nimport java.util.ResourceBundle;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\nimport javafx.beans.binding.Bindings;\r\nimport javafx.event.ActionEvent;\r\nimport javafx.fxml.FXML;\r\nimport javafx.fxml.Initializable;\r\nimport javafx.scene.control.TextArea;\r\nimport javafx.scene.control.TextField;\r\nimport javafx.scene.control.ToggleButton;\r\nimport javafx.scene.text.Text;\r\nimport javafx.scene.text.TextFlow;\r\n\r\n\/**\r\n *\r\n * @author Yucchi\r\n *\/\r\npublic class FXMLDocumentController implements Initializable {\r\n\r\n    @FXML\r\n    TextArea textArea;\r\n\r\n    @FXML\r\n    TextField textField;\r\n\r\n    @FXML\r\n    ToggleButton search;\r\n\r\n    @FXML\r\n    TextFlow textFlow;\r\n\r\n    private Text text;\r\n\r\n    @FXML\r\n    public void handleSearch(ActionEvent event) {\r\n\r\n        if (search.isSelected()) {\r\n            search.setText(\"Clear\");\r\n            makeSearchText();\r\n        } else {\r\n            search.setText(\"Search\");\r\n            textArea.setText(\"\");\r\n            textField.setText(\"\");\r\n            textFlow.getChildren().removeAll(textFlow.getChildren());\r\n        }\r\n\r\n    }\r\n\r\n    @Override\r\n    public void initialize(URL url, ResourceBundle rb) {\r\n\r\n        search.disableProperty()\r\n                .bind(\r\n                        Bindings.when(textArea.textProperty().isEmpty().or(textField.textProperty().isEmpty()))\r\n                        .then(true)\r\n                        .otherwise(false));\r\n\r\n    }\r\n\r\n    private void makeSearchText() {\r\n\r\n        int pos = 0;\r\n        String sourceText = textArea.getText();\r\n\r\n        final Pattern thePattern = Pattern.compile(textField.getText());\r\n        final Matcher matcher = thePattern.matcher(sourceText);\r\n\r\n        int start;\r\n        int end;\r\n\r\n        while (matcher.find()) {\r\n\r\n            start = matcher.start();\r\n            end = matcher.end();\r\n\r\n            if (start == 0) {\r\n\r\n                this.text = new Text(sourceText.substring(start, end));\r\n                this.text.setStyle(\"-fx-font-size: 24px;-fx-fill: linear-gradient(from 0% 0% to 100% 200%, repeat, aqua 0%, red 50%);-fx-stroke: black;-fx-stroke-width: 1;\");\r\n                textFlow.getChildren().add(this.text);\r\n                pos = end;\r\n            } else {\r\n                if (pos != start) {\r\n\r\n                    this.text = new Text(sourceText.substring(pos, start));\r\n                    this.text.setStyle(\"-fx-font-size: 16px;\");\r\n                    textFlow.getChildren().add(this.text);\r\n                }\r\n\r\n                this.text = new Text(sourceText.substring(start, end));\r\n                this.text.setStyle(\"-fx-font-size: 24px;-fx-fill: linear-gradient(from 0% 0% to 100% 200%, repeat, aqua 0%, red 50%);-fx-stroke: black;-fx-stroke-width: 1;\");\r\n                textFlow.getChildren().add(this.text);\r\n                pos = end;\r\n            }\r\n\r\n        }\r\n\r\n        if (pos < sourceText.length()) {\r\n\r\n            this.text = new Text(sourceText.substring(pos, sourceText.length()));\r\n            this.text.setStyle(\"-fx-font-size: 16px;\");\r\n            textFlow.getChildren().add(this.text);\r\n        }\r\n\r\n    }\r\n\r\n}\r\n\r\n<\/pre>\n<\/p>\n<p>\u3053\u306e\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5b9f\u884c\u7d50\u679c\u306f\u6b21\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/5.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"5\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"5\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/5_thumb.png\" width=\"404\" height=\"359\"><\/a><\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/21.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"2\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"2\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/2_thumb1.png\" width=\"404\" height=\"359\"><\/a><\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/7.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"7\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"7\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/7_thumb.png\" width=\"404\" height=\"362\"><\/a><\/p>\n<p><a href=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/8.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" title=\"8\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"8\" src=\"http:\/\/yucchi.jp\/blog\/wp-content\/uploads\/2014\/12\/8_thumb.png\" width=\"404\" height=\"357\"><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>\u3084\u3063\u3071 JavaFX \u30aa\u30f3\u30ea\u30fc\u3067\u3064\u304f\u3063\u305f\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u307b\u3046\u304c\u898b\u6804\u3048\u304c\u3044\u3044\u3067\u3059\u306d\uff01<\/p>\n<p>\u305d\u308c\u306b\u3057\u3066\u3082 JavaFX \u3063\u3066\u304a\u3082\u3057\u308d\u3044\u306d\uff01<\/p>\n<p>\u3053\u306e\u4e8c\u3064\u306e\u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u306f JavaFX Night \u3067\u6afb\u5ead\u3055\u3093\u304c\u4f8b\u3092\u6319\u3052\u3066\u3044\u305f\u3088\u3046\u306a\u3053\u3068\u3092\u3053\u306e\u4e8c\u3064\u306e\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u3084\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>TextField \u3068 TextArea \u306b\u6587\u5b57\u304c\u5165\u529b\u3055\u308c\u3066\u306a\u3051\u308c\u3070\u30c8\u30b0\u30eb\u30dc\u30bf\u30f3\u3092\u975e\u6d3b\u6027\u5316\u306b\u3057\u3001\u6587\u5b57\u304c\u5165\u529b\u3055\u308c\u305f\u3089\u6d3b\u6027\u5316\u3055\u305b\u308b\u3053\u3068\u3092 Bind \u3092\u4f7f\u3063\u3066\u5b9f\u88c5\u3057\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#666666\">search.disableProperty()<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .bind(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bindings.when(textArea.textProperty().isEmpty().or(textField.textProperty().isEmpty()))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .then(true)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .otherwise(false));<\/font><\/p>\n<p>Java \u3089\u3057\u304f\u306a\u3044\u6c17\u304c\u3057\u306a\u3044\u3067\u3082\u306a\u3044\u3067\u3059\u304c\u4fbf\u5229\u3067\u3059\u3002<\/p>\n<p>\u3042\u3063\u3001\u3064\u307e\u308a\u691c\u7d22\u3057\u3066\u304b\u3089 TextArea \u304b TextField \u3092\u3069\u3061\u3089\u304b\u306e\u30c6\u30ad\u30b9\u30c8\u3092\u7a7a\u306b\u3057\u3066\u3057\u307e\u3063\u305f\u3089 Clear \u3067\u304d\u306a\u3044\u3063\u3066\u3053\u3068\u306b\u306a\u308b\u306a\u3002<\/p>\n<p>\u307e\u3063\u3001\u3044\u3044\u304b\u3002<\/p>\n<p>\u30c8\u30b0\u30eb\u30dc\u30bf\u30f3\u4f7f\u3063\u3061\u3083\u3063\u305f\u304b\u3089\u306a\u3041\u30fb\u30fb\u30fb<\/p>\n<p>\u305f\u3060\u306e\u30b5\u30f3\u30d7\u30eb\u306a\u306e\u3067\u305d\u3053\u3089\u3078\u3093\u306f\u898b\u9003\u3057\u3066\u304f\u3060\u3055\u3044\u307e\u3057\uff01(&gt;_&lt;\uff61)<\/p>\n<p><font color=\"#ff0000\" size=\"4\"><strong>JavaFX \u697d\u3057\u3044\uff01<\/strong><\/font><\/p>\n<div id=\"scid:0767317B-992E-4b12-91E0-4F059A8CECA8:fb0bb7fe-b023-4ebd-ba43-e6ee23aa2cff\" class=\"wlWriterEditableSmartContent\" style=\"float: none; padding-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px\">Hatena \u30bf\u30b0: <a href=\"http:\/\/b.hatena.ne.jp\/t\/JavaFX\" rel=\"tag\">JavaFX<\/a><\/div>\n<div class='wp_social_bookmarking_light'>\n            <div class=\"wsbl_hatena\"><a href='\/\/b.hatena.ne.jp\/add?mode=confirm&url=http%3A%2F%2Fyucchi.jp%2Fblog%2F%3Fp%3D1772&title=SwingNode%20%E3%81%A8%20TextFlow' title='\u3053\u306e\u30a8\u30f3\u30c8\u30ea\u30fc\u3092\u306f\u3066\u306a\u30d6\u30c3\u30af\u30de\u30fc\u30af\u306b\u8ffd\u52a0' rel=nofollow class='wp_social_bookmarking_light_a' target=_blank><img src='http:\/\/yucchi.jp\/blog\/wp-content\/plugins\/wp-social-bookmarking-light\/public\/images\/hatena.gif' alt='\u3053\u306e\u30a8\u30f3\u30c8\u30ea\u30fc\u3092\u306f\u3066\u306a\u30d6\u30c3\u30af\u30de\u30fc\u30af\u306b\u8ffd\u52a0' title='\u3053\u306e\u30a8\u30f3\u30c8\u30ea\u30fc\u3092\u306f\u3066\u306a\u30d6\u30c3\u30af\u30de\u30fc\u30af\u306b\u8ffd\u52a0' width='16' height='12' class='wp_social_bookmarking_light_img' \/><\/a><\/div>\n            <div class=\"wsbl_facebook\"><a href='http:\/\/www.facebook.com\/share.php?u=http%3A%2F%2Fyucchi.jp%2Fblog%2F%3Fp%3D1772&t=SwingNode%20%E3%81%A8%20TextFlow' title='Facebook \u306b\u30b7\u30a7\u30a2' rel=nofollow class='wp_social_bookmarking_light_a' target=_blank><img src='http:\/\/yucchi.jp\/blog\/wp-content\/plugins\/wp-social-bookmarking-light\/public\/images\/facebook.png' alt='Facebook \u306b\u30b7\u30a7\u30a2' title='Facebook \u306b\u30b7\u30a7\u30a2' width='16' height='16' class='wp_social_bookmarking_light_img' \/><\/a><\/div>\n            <div class=\"wsbl_google_plus_one\"><g:plusone size=\"medium\" annotation=\"none\" href=\"http:\/\/yucchi.jp\/blog\/?p=1772\" ><\/g:plusone><\/div>\n            <div class=\"wsbl_twitter\"><a href=\"https:\/\/twitter.com\/share\" class=\"twitter-share-button\" data-url=\"http:\/\/yucchi.jp\/blog\/?p=1772\" data-text=\"SwingNode \u3068 TextFlow\" data-lang=\"ja\">Tweet<\/a><\/div>\n    <\/div>\n<br class='wp_social_bookmarking_light_clear' \/>\n","protected":false},"excerpt":{"rendered":"<p>\u3053\u306e\u30a8\u30f3\u30c8\u30ea\u30fc\u306f\u3001JavaFX Advent Calendar 2014, 11\u65e5\u76ee\u306e\u304a\u307e\u3051\u3067\u3059\u3002 \u6628\u65e5\u306f @toruwest \u3055\u3093\u306e\u300cJavaFX\u306eTreeView\u3067\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3057\u3066\u307f\u308b\u300d\u3067\u3057\u305f\u3002 \u660e\u65e5\u306f @skrb \u3055\u3093\u306e\u300cJava Advent Calendar\u3068\u4e00\u7dd2\u306b\u306a\u306b\u304b\u66f8\u304d\u307e\u3059\u300d\u3067\u3059\u3002 \u4eca\u5e74\u3082 JavaFX \u3067\u3044\u308d\u3044\u308d\u306a\u3053\u3068\u3092\u697d\u3057\u3093\u3060\u306e\u3067\u305d\u306e\u3046\u3061\u306e\u4e00\u90e8\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002 \u306f\u3058\u3081\u306b\u3001Swing \u3067\u306f JTextPane \u3063\u3066\u306e\u304c\u3042\u3063\u3066\u666e\u901a\u306e JTextArea \u3088\u308a\u3082\u67d4\u8edf\u306b\u6271\u3048\u307e\u3059\u3002 \u30c6\u30ad\u30b9\u30c8\u306e\u30b9\u30bf\u30a4\u30eb\u3092\u7c21\u5358\u306b\u5909\u66f4\u3067\u304d\u305f\u308a\u3057\u3066\u3068\u3066\u3082\u4fbf\u5229\u3067\u3057\u305f\u3002 JavaFX \u306b JTextPane \u306b\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[21],"class_list":["post-1772","post","type-post","status-publish","format-standard","hentry","category-javafx","tag-javafx"],"_links":{"self":[{"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1772","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1772"}],"version-history":[{"count":3,"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1772\/revisions"}],"predecessor-version":[{"id":1775,"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1772\/revisions\/1775"}],"wp:attachment":[{"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1772"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1772"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/yucchi.jp\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1772"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}