JavaFX」タグアーカイブ

さくらのVNCコンソール

FirefoxでVPSのisoインストールを行おうとしたところ途中で起動するはずのVNCコンソールが起動しなかった。試しに、リモートコンソールの右にあるVNCコンソールリンクをクリックしてみても”Server returned status code 0”と怒られた。

必要となるJREはインストールしているはずだと思いつつ「ツール->アドオン->プラグイン」とみていくと「Java TM Platform ~」が入っていない。

インストール&Firefox再起動で解決。

 

JavaFXが悪さして長い間プラグインなかったのかな??

JavaFXの非同期処理中に画面を閉じたら。。。。

バックグラウンドでタスクを動かしている状態でJavaFXの画面を閉じる。

閉じる

すると、裏で走っていたTaskが終わった後もなんか生き残っている。

残骸

 

環境は1.7.0_45に入っているjfxrt.jarでEclipse実行。

ソースは下の感じ。

    @FXML
    private void handleExecAction(ActionEvent event) {
        this.logger.info("start");
        try {
            analizeTask = getAnalizeTask();
            pgBar.progressProperty().unbind();
            pgBar.progressProperty().bind(analizeTask.progressProperty());
            pgLabel.textProperty().bind(analizeTask.messageProperty());
            final ExecutorService exe = Executors.newSingleThreadExecutor();
            exe.submit(analizeTask);

    private Task<String> getAnalizeTask() {
        return new Task<String>() {
            @Override
            protected String call() throws Exception {
                logger.info("start");
                try {

 

とりあえずは、

  1. Applicationクラスにコントローラー持たしておいて
  2. stopメソッドからコントローラーの終了メソッドを呼んで
  3. その中からTaskのcancel呼んで
  4. Taskのキャンセルイベントのハンドラー内で強制終了かけてやる

で回避。

Task内の終了処理をきちんとやろうとするといろいろはまりそうですが。

 

1

    private FXMLController controller;

    @Override
    public void start(Stage stage) throws Exception {

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Scene.fxml"));
        Parent root = (Parent) fxmlLoader.load();
        controller = (FXMLController) fxmlLoader.getController();

2

    @Override
    public void stop() throws Exception {
        controller.destroy();
    }

3

public class FXMLController implements Initializable {    
    public void destroy() {
        if (analizeTask != null)
            analizeTask.cancel();
    }

4

            analizeTask.addEventHandler(WorkerStateEvent.WORKER_STATE_CANCELLED,
                    new EventHandler<WorkerStateEvent>() {
                        @Override
                        public void handle(WorkerStateEvent t) {
                            exe.shutdown();
                        }
                    });

JavaFXでFXMLを使った際のApplicationからcontrollerへのアクセス

FXMLクラスで”fx:controller”(シーンビルダーだとデフォルトで入っているはず)を指定しておいてアプリケーションクラスでFXMLLoader#getControllerを呼べばコントローラを取得できるのであとはごにょごにょすればOK。

注意点は、FXMLLoader#loadを呼んだ後でないとFXMLLoader#getControllerが取得できない(nullになる)こと。

 

(FXML)

<AnchorPane id="AnchorPane" prefHeight="427.0" prefWidth="423.5" 
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" 
fx:controller="jp.co.epea.FXMLController">
    <children>
        <VBox fx:id="vBox"

 

(Applicationクラス)

public class MainApp extends Application {

  private FXMLController controller;

    @Override
    public void start(Stage stage) throws Exception {

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Scene.fxml"));
        Parent root = (Parent)fxmlLoader.load();
        controller = (FXMLController) fxmlLoader.getController();

 

 

WebSocketにてJSON形式のデータをJavaFXとやり取りしてみる。の4

先ほどに続いて送受信部分

送信処理

  1. 画面の送信ボタンからSingleController#handleSendActionが呼ばれる。
  2. SingleController#handleSendActionから@ClientEndpointのsendメソッド(自分で作った普通のメソッド)を呼び出す。
  3. sendメソッド内でSession.getAsyncRemote().sendObject(dataObj)を呼び出す
  4. encodersに指定してあるClientEncoderクラスのencodeメソッドが呼び出される。
  5. encodeメソッドでエンコードされたデータ(JSON形式の文字列)がServerEndpointに送信される。

エコープログラムなのでServerEndpointで受信されたデータは(若干加工され)ClientEndpointに戻される。そのため、続けて受信処理が走る。

 

受信処理

  1. サーバからのデータがPushされる。
  2. @ClientEndpointのdecodersに指定してあるClientDecoderクラスのwillDecodeメソッドが呼び出され入力値がチェックされる。
  3. willDecodeの結果がtrueならば続けてdecodeメソッドが呼び出されてジェネリクスで指定した型(ClientData)にデコードされる。
  4. デコードされたデータを引数に@ClientEndpointの@OnMessageが呼び出される。ここはJavaFXのスレッド配下ではなく、WebSocketのスレッドに移っている。そのため、JavaFXのコントロールを直接操作することはできない。
  5. @OnMessageの中でPlatform.runLaterを呼び、JavaFXの画面操作(接続時処理ViewObj#write)の呼び出しを登録(?)する。
  6. JavaFXスレッドに戻り、JavaFXの画面操作が実行される。

(コントローラーの関連する部分)

public class SingleController implements Initializable {
    @FXML
    private void handleSendAction(ActionEvent event) {
        System.out.println("SingleController#handleSendAction");
        wsClient.send(msgInput.getText(), sess);
    }
}

(ClientEndpointの関連する部分)

@ClientEndpoint( 
   decoders = { ClientDecoder.class }, 
   encoders = { ClientEncoder.class })
public class WSJsonSingleClient {

    @OnMessage
    public void onMessage(ClientData dataObj) {
        System.out.println("WSJsonSingleClient#onMessage");
        final ClientData channeled = dataObj;
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                viewObj.write(
                        channeled.getSessionId(), 
                        channeled.getMessageTimeString(), 
                        channeled.getMessage());
            };
        });
    }

    public void send(String text,Session sess) {
        System.out.println("WSJsonSingleClient#send");
        ClientData dataObj = new ClientData(text);
        sess.getAsyncRemote().sendObject(dataObj);
    }
}

(ClientEncoder)

public class ClientEncoder implements Encoder.Text<ClientData> {

    @Override
    public void init(EndpointConfig paramEndpointConfig) {
        System.out.println("ClientEncoder#init");
    }

    @Override
    public void destroy() {
        System.out.println("ClientEncoder#destroy");
    }

    @Override
    public String encode(ClientData paramData) throws EncodeException {
        System.out.println("ClientEncoder#encode");
        JsonObject model = Json.createObjectBuilder()
                   .add("message", paramData.getMessage())
                   .add("messageTime",paramData.getMessageTime())
                   .build();
        return model.toString();
    }
}

(ClientDecoder)

public class ClientDecoder implements Decoder.Text<ClientData> {

    @Override
    public void destroy() {
        System.out.println("ClientDecoder#destroy");
    }

    @Override
    public void init(EndpointConfig arg0) {
        System.out.println("ClientDecoder#init");
    }

    @Override
    public ClientData decode(String inputString) throws DecodeException {
        System.out.println("ClientDecoder#decode");
        try{
            JsonObject jsonObject = Json.createReader(new StringReader(inputString)).readObject();
            return  new ClientData(jsonObject);
        } catch(Exception e){
            e.printStackTrace();
            throw new DecodeException(inputString,"ClientDecoder#decode失敗", (Throwable)e);
        }
    }

    @Override
    public boolean willDecode(String inputString) {
        try {
            System.out.println("ClientDecoder#willDecode");
            Json.createReader(new StringReader(inputString)).readObject();
            return true;
        } catch (JsonException ex) {
            ex.printStackTrace();
            return false;
        }
    }
}

github:https://github.com/epea/test01/tree/WF_JSON_FX_SINGLE

WebSocketにてJSON形式のデータをJavaFXとやり取りしてみる。の3

先ほどの続き

接続処理

  1. 画面の開始ボタンからSingleController#handleStartButtonActionが呼ばれる。
  2. handleStartButtonAction内でClientManager#connectToServerを呼びWebSocketの起動を開始する。
  3. WebSocketの@OnOpenが呼ばれる。ここはJavaFXのスレッド配下ではなく、WebSocketのスレッドに移っている。そのため、JavaFXのコントロールを直接操作することはできない。
  4. @OnOpenの中でPlatform.runLaterを呼び、JavaFXの画面操作(接続時処理ViewObj#open)の呼び出しを登録(?)する。
  5. JavaFXスレッドに戻り、JavaFXの画面操作が実行される。

切断処理1

  1. 画面の終了ボタンからSingleController#handleStoptButtonActionが呼ばれる。
  2. Session#closeを呼び出し、WebSocketの終了処理を開始する。
  3. 切断処理2に続く

 

切断処理2

  1. 「切断処理1」または「ServerEndpointからの切断」等により、WebSocketの@OnCloseが呼ばれる。ここはJavaFXのスレッド配下ではなく、WebSocketのスレッドに移っている。そのため、JavaFXのコントロールを直接操作することはできない。
  2. @OnCloseの中でPlatform.runLaterを呼び、JavaFXの画面操作(接続時処理ViewObj#close)の呼び出しを登録(?)する。
  3. JavaFXスレッドに戻り、JavaFXの画面操作が実行される。

(コントローラーの関連する部分)

public class SingleController implements Initializable {

    private WSJsonSingleClient wsClient = null;
    private Session sess = null;

    // 略

    @FXML
    private void handleStartButtonAction(ActionEvent event) {
        System.out.println("SingleController#handleStartButtonAction");
        try {
            ClientManager m = org.glassfish.tyrus.client.ClientManager
                    .createClient();
            URI clientURI = new URI("ws://localhost:8080/first/hellojson/");
            sess = m.connectToServer(wsClient, clientURI);

        } catch (DeploymentException | URISyntaxException e) {
            Logger.getLogger(SampleController.class.getName()).log(
                    Level.SEVERE, null, e);
        }
    }

    @FXML
    private void handleStoptButtonAction(ActionEvent event) {
        System.out.println("SingleController#handleStoptButtonAction");
        try {
            sess.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

   // 略
}

(ClientEndpointの関連する部分)

@ClientEndpoint( decoders = { ClientDecoder.class }, encoders = { ClientEncoder.class })
public class WSJsonSingleClient {
    // 略
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("WSJsonSingleClient#onOpen");
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                viewObj.open();
            };
        });
    }

    // 略

    @OnClose
    public void closeConnection(Session session) {
        System.out.println("WSJsonSingleClient#closeConnection");
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                viewObj.close();
            };
        });
    }
    // 略
}

github:https://github.com/epea/test01/tree/WF_JSON_FX_SINGLE

JSON送受信部分へ

 

WebSocketにてJSON形式のデータをJavaFXとやり取りしてみる。の2

先ほどの続き

前提条件

  • JavaFXのコントロール(ラベルとかボタンとか)はJavaFXのスレッド配下からでないと原則(※1)操作できない(と思う)
  • WebSocketはプログラム本体とは別のスレッドでデータの送受信を行う。
  • WebSocketのスレッド内からPlatform#runLaterを呼ぶことで、JavaFXのスレッド配下で行わせたい処理を登録できる。
  • 今の実装だと、接続状況の排他制御がきちんとされていないので、「サーバからの切断」と「クライアントからの起動」のシーケンスが重なったときとかにうまく動かないケースがでてくる。(はず)

※1 こちらにあるようにコントロールに結びついたObservableListを別スレッドから操作した場合は、その操作が画面に反映される。ラベルとかボタンとかのコントロールで試した範囲ではJavaFXのスレッドかどうかチェックにかかってうまくいかなかったがやりようはあるかもしれない。

ApplicationクラスとFXML

Applicationクラスは起動するだけ。

public class WSJsonSingle extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("SingleJson.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

 

FXMLはfx:idふって、onActionを紐付けている程度。

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane prefHeight="363.0" prefWidth="502.0" xmlns:fx="http://javafx.com/fxml" fx:controller="jp.co.epea.wsclient.SingleController">
  <children>
    <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="43.0" prefWidth="502.0" text="JSON送受信" />
    <VBox layoutY="43.0" prefHeight="331.0" prefWidth="502.0">
      <children>
        <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
          <children>
            <Button fx:id="startButton" mnemonicParsing="false" onAction="#handleStartButtonAction" text="開始" />
            <Button fx:id="stopButton" mnemonicParsing="false" onAction="#handleStoptButtonAction" text="終了" />
            <Label fx:id="statusLabel" text="ステータス" />
          </children>
        </HBox>
        <HBox prefHeight="100.0" prefWidth="200.0">
          <children>
            <TextField fx:id="msgInput" editable="false" prefWidth="200.0" />
            <Button fx:id="sendButton" mnemonicParsing="false" onAction="#handleSendAction" text="送信" />
          </children>
        </HBox>
        <VBox prefHeight="200.0" prefWidth="100.0">
          <children>
            <HBox prefHeight="100.0" prefWidth="200.0">
              <children>
                <Label text="発言者:" />
                <Label fx:id="nameLabel" text="発言者初期値(起動時に変更)" />
              </children>
            </HBox>
            <HBox prefHeight="100.0" prefWidth="200.0">
              <children>
                <Label text="発言日時:" />
                <Label fx:id="timeLabel" text="発言日時初期値(起動時に変更)" />
              </children>
            </HBox>
            <HBox prefHeight="100.0" prefWidth="200.0">
              <children>
                <Label text="発言内容:" />
                <Label fx:id="msgLabel" text="発言内容初期値(起動時に変更)" />
              </children>
            </HBox>
          </children>
        </VBox>
      </children>
    </VBox>
  </children>
</AnchorPane>

起動処理

WSJsonSingle#mainから。

画面項目の初期化と、ClientEndpointのインスタンス化(まだ接続しない)。

public class SingleController implements Initializable {

    private WSJsonSingleClient wsClient = null;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // コントロールをまとめたクラスを作って
        ViewObj obj = new ViewObj(nameLabel, timeLabel, msgLabel, statusLabel,
                msgInput, startButton, stopButton, sendButton);
        // ClientEndpointに渡してインスタンス化
        wsClient = new WSJsonSingleClient(obj);
    }
}

public class ViewObj {
    private Label nameLabel;
   // 略
    ViewObj(Label nameLabel, Label timeLabel, Label msgLabel,
            Label statusLabel, TextField msgInput, Button startButton,
            Button stopButton, Button sendButton) {
        super();
        // 略
        // コントロール類の初期化(項目設定とか、ボタンのdisable周りとか)
        this.init();
    }

    private void init(){
        nameLabel.setText("");
        // 略
    }
}

@ClientEndpoint( decoders = { ClientDecoder.class }, encoders = { ClientEncoder.class })
public class WSJsonSingleClient {

    private ViewObj viewObj;

    public WSJsonSingleClient(ViewObj viewObj) {
        this.viewObj = viewObj;
    }
    // 略
}

github:https://github.com/epea/test01/tree/WF_JSON_FX_SINGLE

続き

WebSocketにてJSON形式のデータをJavaFXとやり取りしてみる

Glassfish4とJavaFX間でJSON形式のデータをWebsocketにてやり取りしてみたのでメモ。

何ページかに分かれているけど実際にJSONのハンドリングをしている箇所はこちら

サーバサイドはこの前HTMLとやり取りしたものとほぼ同じ。

大まかな動きは以下。なお、表示はリスト形式ではなくてラベルの中身を置換していく形式(表示以外はやっていることはHTMLの時とほぼ一緒)

  1. HTMLからJSONで入力テキストと現在日時を送信。
  2. GlassfishのWebsocketで受信(&Decode)
  3. 受け取ったデータに情報(とりあえずユーザ情報代わりのセッションID)を付与し繋がっているクライアント(JavaFX&この前作ったHTML)全体にJSON形式で返信
  4. JavaFX(またはHTML)で受け取ったデータを表示

データ形式はこの前と同じ。(なので、クライアントはこの前のHTMLとJavaFXで併用できる。)

(JavaFX->glassfishのデータ形式)
{"message":"メッセージ","messageTime":時間(ミリ秒)}

(glassfish->JavaFXのデータ形式)
{"message":"メッセージ","sessionId":"セッションID","messageTime":"HH:mm:ss"}

斜体は変数

Maven

必要な依存関係を追加。(動作確認はeclipse上のM2E)

    <dependencies>
       <!-- JavaFX 2 -->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>javafx</artifactId>
            <version>2.2</version>
            <scope>system</scope>
            <systemPath>${javafx2.home}</systemPath>
        </dependency>
        <!-- Websocket (JSR-356) -->
        <!-- TYRUS-210の対応で1.2にあげている -->
        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-client</artifactId>
            <version>1.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-container-grizzly</artifactId>
            <version>1.2</version>
            <scope>compile</scope>
        </dependency>
        <!-- JSON Processing (JSR-353) -->
        <dependency>
            <groupId>javax.json</groupId>
            <artifactId>javax.json-api</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.json</artifactId>
            <version>1.0.2 </version>
        </dependency>
    </dependencies>

画面フロー

起動時

開始ボタンしか押せない状態。裏ではWebSocket用のClientEndPointをインスタンス化している。

initial

 

開始ボタンクリック後(の入力欄に文字入力した状態)

入力欄や送信ボタン・終了ボタンが使えるようになる。

bef_send

送信ボタンクリック後

入力メッセージと時間がサーバに送信される。そしてデータを受信したサーバにて加工(といってもセッションID文字列を付加しただけ)されたデータがクライアントに送られ、そのデータがラベルに表示される。

aft_send

 

終了ボタンクリック後

開始ボタンしか押せない状態になる。

closed

 

github:https://github.com/epea/test01/tree/WF_JSON_FX_SINGLE

続き。

M2E(Maven)のproperty外部化

以前JavaFXのMaven設定を行った際にjfxrt.jarへのパスはpomに直接記載していた。別端末(別のパス)で使用しようとしたときに外部化した際の手順。

 

設定を記載するsetting.xmlを作成。(proxyを使う際等に既に作っていることも多い。)

Defaultは下。(自分はEclipseの設定->Maven->ユーザ設定から変更)

    The Maven install: $M2_HOME/conf/settings.xml
    A user's install: ${user.home}/.m2/settings.xml

作成した内容は以下。

profile -> propertiesの下に、キー、値を指定する。

(参考サイト

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository/>
  <interactiveMode/>
  <usePluginRegistry/>
  <offline/>
  <pluginGroups/>
  <servers/>
  <mirrors/>
  <proxies/>
    <profiles>
        <profile>
            <id>javafx2</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <javafx2.home>C:\develop\pleiades43\pleiades\java\7\lib\jfxrt.jar</javafx2.home>
            </properties>
        </profile>
    </profiles>
  <activeProfiles/>
</settings>

pomで直接記載していた個所が変数で指定できるようになっている。

 

     <dependencies>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>${javafx2.home}</systemPath>
        </dependency>

 

今回参考にさせてもらったビルドまで記載されているブログ

JavaFXとWebsocketを連携してみる(On Glassfish4.0) その4

WebSocketで受け取ったデータをJavaFXのラベルに設定する方法とりあえず動いた。

大まかなフローは、

  1. WebSocket起動
  2. Websocketの@OnMessageでデータ受信
  3. @OnMessageの中でPlatform.runLaterを使ってJavaFXのスレッドを起動(コマンドの依頼??)
  4. Platform.runLaterの中でLabel#setTextを呼び出して値を更新

(ボタンイベントからWebsocketの起動周り)

public class SampleController {

    @FXML
    private Label testLabel;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        kickWebSocket();
    }

    private void kickWebSocket() {
        try {
            CountDownLatch messageLatch = new CountDownLatch(1);
            URI clientURI = new URI("ws://localhost:8080/first/hello/");
            ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager
                    .createClient();
            cliContainer.connectToServer(new WSClient(testLabel), clientURI);
            messageLatch.await(1, TimeUnit.SECONDS);
        } catch (DeploymentException | URISyntaxException
                | InterruptedException ex) {
            Logger.getLogger(SampleController.class.getName()).log(
                    Level.SEVERE, null, ex);
        }
    }
}

(OnMeessageから値の設定)

@ClientEndpoint
public class WSClient {

    private Label testLabel;

    public WSClient(Label testLabel) {
        this.testLabel = testLabel;
    }

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connection had opened.");
    }

    @OnMessage
    public void onMessage(String message) {
        if (message.length() == 0) {
            return;
        }
        final String channeled = message;
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                testLabel.setText(channeled);
            };
        });
    }

    @OnClose
    public void closeConnection(Session session) {
        System.out.println("Connection had closed.");
    }

    @OnError
    public void error(Session sess, Throwable t) {
        System.out.println("エラーです:" + sess.getId());
        t.printStackTrace();
    }
}

(一応サーバ側)

@ServerEndpoint("/hello/")
public class HelloWorld {

    static Set<Session> sessions = Collections
            .synchronizedSet(new HashSet<Session>());

    @OnMessage
    public void onMessage(String message) {
        System.out.println("message[" + message + "]");

        for (Session s : sessions) {
            s.getAsyncRemote().sendText(message);
        }
    }

    @OnOpen
    public void open(Session sess) {
        System.out.println("開始します:" + sess.getId());
        sessions.add(sess);
    }

    @OnClose
    public void close(Session sess) {
        System.out.println("終了します:" + sess.getId());
        sessions.remove(sess);
    }

    @OnError
    public void error(Session sess,Throwable t) {
        System.out.println("エラーです:" + sess.getId());
        t.printStackTrace();
    }
}

まだ、確認できていないのがこの実装で順序の保障できているかどうか。

(実装的にはWebSocketボタン押した回数立ち上がったりと適当な部分はありますが。)

JavaFXとWebsocketを連携してみる(On Glassfish4.0) その3

時系列のままに書いている間が漂ってきましたが。。。。

最初はボタンイベント(handleButtonAction)からjavafx.concurrent.Serviceをキックしていた。ただGrizzlyの中でWebsocket用のスレッドが立てられているので、「Websoketスレッド起動の処理」をスレッド化しても多分意味がないことに気づいた。少なくとも今問題になっている「Not on FX application thread」というやつの対策にはならなそう。

ボタンイベントから直接Websocket用のスレッド起動を行うように変更。

public class SampleController implements Initializable {

    @FXML
    private TableView<RowData> table;

    @FXML
    private TableColumn<RowData, String> column;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        try {
            CountDownLatch messageLatch = new CountDownLatch(1);
            URI clientURI = new URI("ws://localhost:8080/first/hello/");
            ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager
                    .createClient();
            cliContainer.connectToServer(new WSClient(table), clientURI);
            messageLatch.await(1, TimeUnit.SECONDS);
        } catch (DeploymentException | URISyntaxException
                | InterruptedException ex) {
            Logger.getLogger(SampleController.class.getName()).log(
                    Level.SEVERE, null, ex);
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        table.setEditable(true);
        column.setResizable(true);
        column.setCellValueFactory(new PropertyValueFactory<RowData, String>(
                "message"));
    }
}

予定通りWebsocket(のスレッド)はキックされている。

a

 

@OnMessageでLabelの値に反映させる方法は調査中。 -> 動いた

それを皮切りに”ObservableList経由で反映しているTableView”以外もやっつけるつもりだったけどそもそもできるか不安になってきた。。。