簡體   English   中英

Javafx 具有多個 windows 的應用程序,適用於 2 個不同的用戶。 錯誤不在 FX 應用程序線程上;

[英]Javafx Application with multiple windows for 2 different users . error Not on FX application thread;

我正在構建一個 Java 獨立應用程序,兩個不同的用戶使用兩個不同的 GUI。 我想要兩個不同的線程,每個線程必須管理一個 GUI。 我有錯誤

線程“Thread-4”java.lang.IllegalStateException 中的異常:不在 FX 應用程序線程上; currentThread = Thread-4

我該如何解決?

package kapta.classes;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import kapta.classes.Utils.ThreadLocalSession;

import java.io.IOException;

 public class MainApp extends Application {

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

    System.out.println("here main");
    FXMLLoader fxmlLoader = new FXMLLoader(MainApp.class.getResource("Login.fxml"));
    Scene scene = new Scene(fxmlLoader.load());
    stage.setTitle("Mate");
    stage.setScene(scene);
    //stage.setFullScreen(true);
    stage.show();

    ThreadLocalSession firstUser = new ThreadLocalSession();
    new Thread(firstUser).start();

}



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


}

在 class ThreadLocalSession ==>

   package kapta.classes.Utils;


public class ThreadLocalSession implements Runnable
{

private static ThreadLocal<Session> userSession;
private String username;


public ThreadLocalSession(){}
public ThreadLocalSession(String username){
    this.username = username;
    this.userSession = new ThreadLocal<>();
}

public void setUsername(String username) {
    this.username = username;
}

public static void setUserSession(ThreadLocal<Session> userSession) {
    ThreadLocalSession.userSession = userSession;
}

public String getUsername() {
    return username;
}

public static ThreadLocal<Session> getUserSession() {
    return userSession;
}


@Override
public void run() {
    System.out.println("1");

    try {
        Platform.runLater(display());
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }



}

private Runnable display() throws IOException, InterruptedException {
    Thread.sleep(1000);
    System.out.println("trd");
    Stage stage = new Stage();
    FXMLLoader fxmlLoader = new FXMLLoader(MainApp.class.getResource("Login.fxml"));
    Scene scene = new Scene(fxmlLoader.load());
    stage.setTitle("New");
    stage.setScene(scene);
    stage.showAndWait();
    return null;
}

您應該將 Runnable 傳遞給 runLater 方法,發生的情況是您將 null 從顯示方法作為 Runnable 返回到 runLater,而實際的新 window 創建仍在調用顯示方法的線程中,這會導致異常。 嘗試將 Runnable 傳遞給 runLater:

@Override
public void run() {
    System.out.println("1");
    Platform.runLater(()->{
      System.out.println("trd");
      Stage stage = new Stage();
      FXMLLoader fxmlLoader = new FXMLLoader(MainApp.class.getResource("Login.fxml"));
      Scene scene = new Scene(fxmlLoader.load());
      stage.setTitle("New");
      stage.setScene(scene);
      stage.showAndWait();
    });
}

// or Platform.runLater(()->display())
/* or in the old fashion: 
   Platform.runLater(new Runnable{
         @override
         public void run(){ display(); }
   });
*/

我認為您誤解了如何將 Runnable object 傳遞給 Platform.runLater 之類的方法。

您的display()方法根本沒有創建 Runnable。 事實上,它總是返回 null,因此。 您根本沒有將 Runnable 傳遞給 Platform.runLater。

相反, display()立即執行所有 JavaFX 代碼。 換句話說,這一行:

Platform.runLater(display());

完全等同於:

Runnable task = display();
Platform.runLater(task);

問你可以看到,在調用 Platform.runLater之前display()已經完全執行。 所以它實際上根本沒有在以后運行:這是您看到的異常的原因:您在ThreadLocalSession.run()本身中運行代碼,而不是在 JavaFX 平台線程中。

此外,當前形式的display()方法不適合在 JavaFX 平台線程中運行,因為在該線程中不允許調用 Thread.sleep。 編譯器不會檢測到它,運行時也不能阻止你這樣做,但這樣做會導致所有事件處理在睡眠期間暫停。 在此期間,不會繪制任何節點,不會識別用戶輸入,也不會出現 windows。

您要做的是從您的run()方法調用 Thread.sleep,然后返回一個包含所有剩余代碼的 Runnable:

private Runnable display() throws IOException, InterruptedException {
    // This method is called from ThreadLocalSession.run(), so
    // we are not in the JavaFX platform thread.
    Thread.sleep(1000);

    Runnable displayer = new Runnable() {
        @Override
        public void run() {
            System.out.println("trd");
            Stage stage = new Stage();
            FXMLLoader fxmlLoader = new FXMLLoader(MainApp.class.getResource("Login.fxml"));
            try {
                Scene scene = new Scene(fxmlLoader.load());
                stage.setTitle("New");
                stage.setScene(scene);
                stage.showAndWait();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    };

    return displayer;
}

(你也可以寫一個 lambda 來表示一個 Runnable,但為了清楚起見,我選擇使用顯式語法。)

Runnable 的 run() 方法不允許拋出 IOException 這樣的已檢查異常,這就是為什么 IOException 需要在該方法內部捕獲的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM