非同期処理を試してみた。
JavaFX をはじめてからいろいろ解らないことがあって思うように進まない。
9月、10月は個人的にいろいろ面倒な季節であってそのうちにクリスマスやお正月と忙しくなる。
それでも少しだけでも! と今回は「JavaFX 2ではじめる、GUI開発 第14回 非同期処理 」を試してみる。
デスクトップアプリでは必ず必要となる技術だけに記事の解説も丁寧に書かれていました。
感謝感激!です。
非同期処理を実装するにあたって JavaFX には Task クラスがありそれが便利に使えます。
また、Platform.runLater(() –> { // … });
でスレッドを起こすことができてだいたい Swing でできていたことは可能なようです。
詳しくは上記の記事をご覧になることをお勧めします。
まだ、記事を読んだだけでいろいろ試してはいないのですが、「スレッド間のデータ交換」が面白そうだったので
実際に動かしてみました。
NetBeans プロジェクトのサンプルプログラムがダウンロードで提供されていたので非常に助かります。
ただ、ローカルのファイルを開くとあまり重い処理にはならないので解りにくかった。
そこで JavaFX と openJDK のサイトの HTML ファイルを取得して表示させるようにしてみました。
結局、あーでもない、こーでもないと下の動画のようなものができあがってしまいました。(^_^;)
おまけに自信の無い不安なソースコードも載せておきますので間違い等ありましたら教えていただければ幸いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package jp.yucchi.tryasinc; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class TryAsync extends Application { @Override public void start(Stage stage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml")); Scene scene = new Scene(root); stage.setTitle("非同期処理"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
package jp.yucchi.tryasinc; import java.awt.Toolkit; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.net.URL; import java.util.ResourceBundle; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.logging.Logger; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Platform; import javafx.beans.value.ObservableValue; import javafx.concurrent.Task; import javafx.concurrent.Worker; import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; import javafx.scene.control.TextArea; import javafx.scene.control.TitledPane; import javafx.stage.Stage; import javafx.stage.WindowEvent; import javafx.util.Duration; public class FXMLDocumentController implements Initializable { @FXML private Label state; @FXML private Button startButton; @FXML private Button cancelButton; @FXML private TitledPane text_1; @FXML private TitledPane text_2; @FXML private TextArea textArea_1; @FXML private TextArea textArea_2; @FXML private ProgressIndicator progressIndicator; private final Works works = new Works(); private ExecutorService executor; private final BlockingQueue<String> queue_javafx = new LinkedBlockingQueue<>(); private final BlockingQueue<String> queue_openJDK = new LinkedBlockingQueue<>(); private Timeline timer; private CompletableFuture<String> javaFX; private CompletableFuture<String> openJDK; private CompletableFuture<Void> doAllWorks; Task<Void> task; private StringBuilder builder_javafx; private StringBuilder builder_openJDK; @FXML public void handleStart(ActionEvent event) { textArea_1.clear(); textArea_2.clear(); startButton.setDisable(true); cancelButton.setDisable(false); int procs = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); executor = Executors.newFixedThreadPool(procs); progressIndicator.setOpacity(1.0); javaFX = CompletableFuture.supplyAsync(() -> works.showJavaFX(), executor); openJDK = CompletableFuture.supplyAsync(() -> works.showOpenJDK(), executor); doAllWorks = CompletableFuture.allOf(javaFX, openJDK); task = new Task<Void>() { @Override protected Void call() throws Exception { doAllWorks.thenRunAsync(() -> { }); doAllWorks.get(); return null; } }; new Thread(task).start(); task.stateProperty().addListener((ObservableValue<? extends Worker.State> value, Worker.State oldState, Worker.State newState) -> { state.setText(oldState.toString() + " --> " + newState.toString()); }); Platform.runLater(() -> { task.setOnSucceeded((WorkerStateEvent e) -> { progressIndicator.setOpacity(0.0); System.out.println("Succeeded"); }); task.setOnFailed((WorkerStateEvent e) -> { System.out.println("Failed"); }); task.setOnRunning((WorkerStateEvent e) -> { System.out.println("Running"); }); task.setOnCancelled((WorkerStateEvent e) -> { System.out.println("Cancelled"); }); task.setOnScheduled((WorkerStateEvent e) -> { System.out.println("Scheduled"); }); timer = new Timeline( new KeyFrame( Duration.millis(100), (ActionEvent e) -> { try { builder_javafx = new StringBuilder(); builder_openJDK = new StringBuilder(); while (!queue_javafx.isEmpty()) { String line = queue_javafx.take(); builder_javafx.append(line); builder_javafx.append("\n"); } while (!queue_openJDK.isEmpty()) { String line = queue_openJDK.take(); builder_openJDK.append(line); builder_openJDK.append("\n"); } if (!(task.isCancelled())) { textArea_1.appendText(builder_javafx.toString()); textArea_2.appendText(builder_openJDK.toString()); } } catch (InterruptedException ex) { } if (task.isDone() || task.isCancelled()) { if (!(doAllWorks.isDone())) { executor.shutdownNow(); } timer.stop(); textArea_1.home(); textArea_2.home(); queue_javafx.clear(); queue_openJDK.clear(); builder_javafx = null; builder_openJDK = null; startButton.setDisable(false); cancelButton.setDisable(true); Toolkit.getDefaultToolkit().beep(); } if (doAllWorks.isDone()) { executor.shutdown(); } }) ); timer.setCycleCount(Timeline.INDEFINITE); timer.play(); }); } @FXML public void handleCancel(ActionEvent event) { if (task.isRunning()) { task.cancel(); textArea_1.appendText("\n\n<----- キャンセルしました。 ----->"); textArea_2.appendText("\n\n<----- キャンセルしました。 ----->"); progressIndicator.setOpacity(0.0); if (!(doAllWorks.isDone())) { executor.shutdownNow(); } } } private class Works { private String showJavaFX() { BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(new URL("https://www.java.net//community/javafx").openStream())); } catch (IOException ex) { Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex); } in.lines().forEach(e -> { queue_javafx.offer(e); }); return null; } private String showOpenJDK() { BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(new URL("http://openjdk.java.net/").openStream())); } catch (IOException ex) { Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex); } in.lines().forEach(e -> { queue_openJDK.offer(e); }); return null; } } public void setStage(Stage stage) { stage.setOnCloseRequest((WindowEvent event) -> { executor.shutdown(); }); } @Override public void initialize(URL url, ResourceBundle rb) { cancelButton.setDisable(true); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.geometry.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" prefHeight="548.0" prefWidth="753.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="jp.yucchi.tryasinc.FXMLDocumentController"> <children> <HBox alignment="CENTER_RIGHT" prefHeight="61.0" prefWidth="725.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0"> <children> <ProgressIndicator fx:id="progressIndicator" opacity="0.0" prefHeight="64.0" prefWidth="68.0" progress="-1.0" visible="true" /> <Label id="status" fx:id="state" alignment="CENTER" prefHeight="30.0" prefWidth="220.0" text=""> <HBox.margin> <Insets right="5.0" fx:id="x2" /> </HBox.margin> </Label> <Button fx:id="cancelButton" alignment="CENTER" contentDisplay="LEFT" mnemonicParsing="false" onAction="#handleCancel" prefHeight="30.0" prefWidth="200.0" text="CANCEL" HBox.margin="$x2" /> <Button fx:id="startButton" mnemonicParsing="false" onAction="#handleStart" prefHeight="30.0" prefWidth="200.0" text="START"> <HBox.margin> <Insets right="3.0" fx:id="x1" /> </HBox.margin> </Button> </children> </HBox> <Accordion prefHeight="448.0" prefWidth="725.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="86.0"> <expandedPane> <TitledPane fx:id="text_2" animated="true" text="openJDK"> <content> <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <children> <TextArea fx:id="textArea_2" prefHeight="400.0" prefWidth="721.0" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> </children> </AnchorPane> </content> </TitledPane> </expandedPane> <panes> <TitledPane fx:id="text_1" animated="true" prefHeight="435.0" prefWidth="725.0" text="JavaFX Java.net"> <content> <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <children> <TextArea fx:id="textArea_1" prefHeight="402.0" prefWidth="721.0" wrapText="true" AnchorPane.bottomAnchor="-2.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> </children> </AnchorPane> </content> </TitledPane> <fx:reference source="text_2" /> </panes> </Accordion> </children> </AnchorPane> |
もっといろいろ遊んでみたいけど解らないことが多すぎて調べる時間が足らない。(>_<。)
一日の時間が私だけ30時間にならないかと思う今日この頃です。
あっ、もう一つおまけに Java 8 を使っている新しい物好きな人は気が向いたらためしてみてください。
Webstart: click to launch this app as webstart (Java 8 実行環境必須)
TAGS: JavaFX | 2013年9月12日10:36 PM | Comment : 0