Исключение при использовании компонентов Swing в приложении JavaFX - флаг javafx.embed.singleThread не работает - PullRequest
0 голосов
/ 24 марта 2020

Я работаю над приложением Java, в котором я использую этап JavaFX со встроенными компонентами Swing. Шаг за шагом я буду менять эти компоненты Swing на компоненты JavaFX, но в данный момент мне нужно скомпилировать и запустить приложение в этих условиях.

Для этого я установил флаг javafx.embed.singleThread в "true", чтобы избежать общей ошибки, возникающей при попытке использовать JavaFX и Swing в одном приложении. Делая это, когда я запускаю приложение из IDE (я использую IntelliJ), все работает нормально, но когда я генерирую артефакт для создания JAR приложения, запускаю приложение из командной строки (я использую Windows), это выдается ошибка:

Exception in Application start method
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
        at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)

Caused by: java.lang.RuntimeException: Exception in Application start method
        at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
        at java.lang.Thread.run(Unknown Source)

Caused by: java.lang.IllegalStateException: FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?
        at sample.Main.start(Main.java:41)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
        at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
        at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
        ... 1 more Exception running application sample.Main

Я читал о слиянии потоков JavaFX и Swing, и везде, где я ищу, я вижу один и тот же ответ, чтобы установить javafx.embed.singleThread в "true". Но в моем случае это не работает. Может быть, что-то, чего я не осознавал, и нужно, чтобы этот JAR-файл работал?

Это не первый раз, когда я создаю JAR-файлы, но это первый раз, когда я делаю это, используя приложение с обоими Компоненты JavaFX и Swing.

Я не могу загрузить весь проект, но в начале основного метода здесь выдается исключение:

if ( !EventQueue.isDispatchThread() ){
        throw new IllegalStateException(
                "FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?");
    }

Спасибо за предоставленную помощь или связанные ссылки .

ОБНОВЛЕНИЕ : Я пытался использовать флаг, предложенный @Slaw в его комментарии в командной строке при запуске приложения .jar, и он работает! Сейчас я пытаюсь установить этот флаг не в командной строке, а в коде. Здесь я показываю, как запускается мое приложение и как я расширяюсь из класса Application:

public class Main extends Application {

SwingMainMenuRoundedPanel buttonsPanel = new SwingMainMenuRoundedPanel();

public Main() throws IOException {
    System.setProperty("javafx.embed.singleThread", "true");
}

@Override
public void start(Stage primaryStage) throws Exception {
//System.setProperty("javafx.embed.singleThread", "true");
    if ( !EventQueue.isDispatchThread() ){
        throw new IllegalStateException(
                "FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?");
    }

    //Add Swing view and interface components to the FX frame
    SwingNode viewNode = addSwingNodeToFXFrame(primaryStage);
    //----------------------------------------------

    //Add FX view and interface components to the FX frame

    //----------------------------------------------

    // Auxiliary panel with provisional content
    Accordion auxiliaryPanelFX = new Accordion();

    // Do the lay-out using FX
    HBox hbox = new HBox(viewNode, auxiliaryPanelFX);
    HBox.setHgrow(viewNode, Priority.ALWAYS);

    // Show the window
    primaryStage.setScene(new Scene(hbox));
    primaryStage.setFullScreen(true);
    primaryStage.setTitle("FXApp");
    primaryStage.setResizable(false);
    primaryStage.show();

}
...
}

Я попытался установить флаг свойства System внутри конструктора, как вы можете видеть сейчас, а также в закомментированной строке в Метод start (), но он не работает, я думаю, из-за причины, которую @Slaw сказал в своем комментарии. Системное свойство не устанавливается до запуска потока JavaFX. Каким будет правильный способ установки свойства System по коду в моем случае?

Большое спасибо за ваши комментарии!

1 Ответ

1 голос
/ 24 марта 2020

из ваш комментарий :

этот флаг является опцией конфигурации конфигурации IntelliJ для сборки / запуска.

В этом ваша проблема , Конфигурация Build / Run, которую вы настраиваете в IntelliJ, имеет значение только в IDE. После развертывания приложения системное свойство больше не устанавливается, поэтому проверка не проходит. Одним из решений является указание системного свойства при выполнении jar приложения:

java -Djavafx.embed.singleThread=true -jar <path-to-jar>

Но это не удобно. К сожалению, я не верю, что есть способ указать неявные системные свойства, например, в файле манифеста. В этом случае, однако, должно быть достаточно установить системное свойство в коде перед запуском среды выполнения JavaFX. Например:

package sample; // package name taken from your stack trace

import javafx.application.Application;

public class Launcher {

  public static void main(String[] args) {
    System.setProperty("javafx.embed.singleThread", "true");
    // "Main.class" taken from your stack trace
    Application.launch(Main.class, args);
  }
}

Обратите внимание, я создал основной класс, который не расширяет Application. Это связано с тем, что основной метод в подклассе Application вызывается после , а среда выполнения JavaFX уже инициализирована (несмотря на то, что вам все еще нужно вызывать launch). Хотя я не проверял его, я предполагаю, что установка системного свойства не будет иметь никакого эффекта после инициализации, следовательно, отдельный основной класс.

...