Подтвердить что ты не робот

JavaFX 2.1: Инструментарий не инициализирован

Мое приложение основано на Swing. Я хотел бы представить JavaFX и настроить его для рендеринга сцены на вторичном дисплее. Я мог бы использовать JFrame для хранения JFXPanel, который мог бы содержать JFXPanel, но я хотел бы достичь этого с помощью API JavaFX.

Подклассификация com.sun.glass.ui.Приложение и использование Application.launch(это) не является опцией, потому что вызывающий поток будет заблокирован.

При создании экземпляра Stage из Swing EDT появляется ошибка:

java.lang.IllegalStateException: Toolkit not initialized

Любые указатели?


EDIT: Выводы

Проблема: нетривиальное приложение GUI Swing должно запускать компоненты JavaFX. Процесс запуска приложения инициализирует графический интерфейс после запуска зависимого служебного уровня.

Решения

Подкласс JavaFX Application class и запустите его в отдельном потоке, например:

public class JavaFXInitializer extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        // JavaFX should be initialized
        someGlobalVar.setInitialized(true);
    }
}

Sidenote: поскольку метод Application.launch() принимает в качестве аргумента Class<? extends Application>, необходимо использовать глобальную переменную для сигнатуры среды JavaFX.

Альтернативный подход: создать экземпляр JFXPanel в потоке диспетчера событий Swing:

final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        new JFXPanel(); // initializes JavaFX environment
        latch.countDown();
    }
});
latch.await();

Используя этот подход, вызывающий поток будет ждать настройки среды JavaFX.

Выберите любое решение, которое вам подходит. Я пошел со вторым, потому что ему не нужна глобальная переменная, чтобы сигнализировать инициализацию среды JavaFX, а также не тратить поток.

4b9b3361

Ответ 1

Найден решение. Если я просто создаю JFXPanel из Swing EDT перед вызовом JavaFX Platform.runLater, он работает. Я не знаю, насколько это надежное решение, я могу выбрать JFXPanel и JFrame, если окажется неустойчивым.

public class BootJavaFX {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new JFXPanel(); // this will prepare JavaFX toolkit and environment
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        StageBuilder.create()
                                .scene(SceneBuilder.create()
                                        .width(320)
                                        .height(240)
                                        .root(LabelBuilder.create()
                                                .font(Font.font("Arial", 54))
                                                .text("JavaFX")
                                                .build())
                                        .build())
                                .onCloseRequest(new EventHandler<WindowEvent>() {
                                    @Override
                                    public void handle(WindowEvent windowEvent) {
                                        System.exit(0);
                                    }
                                })
                                .build()
                                .show();
                    }
                });
            }
        });
    }
}

Ответ 2

Единственный способ работать с JavaFX - это подкласс Application или использовать JFXPanel, именно потому, что они готовят env и toolkit.

Блокирующая нить может быть решена с помощью new Thread(...).

Хотя я предлагаю использовать JFXPanel, если вы используете JavaFX в той же виртуальной машине, что и Swing/AWT, вы можете найти более подробную информацию здесь: Можно ли использовать AWT с JavaFx?

Ответ 3

Я проверил исходный код, чтобы инициализировать его

com.sun.javafx.application.PlatformImpl.startup(()->{});

и выйти из него

com.sun.javafx.application.PlatformImpl.exit();

Ответ 4

Я использовал следующее при создании unittests для тестирования обновлений javaFX tableview

public class testingTableView {
        @BeforeClass
        public static void initToolkit() throws InterruptedException
        {
            final CountDownLatch latch = new CountDownLatch(1);
            SwingUtilities.invokeLater(() -> {
                new JFXPanel(); // initializes JavaFX environment
                latch.countDown();
            });

            if (!latch.await(5L, TimeUnit.SECONDS))
                throw new ExceptionInInitializerError();
        }

        @Test
        public void updateTableView() throws Exception {

            TableView<yourclassDefiningEntries> yourTable = new TableView<>();
            .... do your testing stuff

        }
    }

хотя этот пост не связан с тестированием, тогда он помог мне заставить мой unittest работать

  • без initToolkit BeforeClass, тогда экземпляр TableView в unittest даст сообщение с отсутствующим набором инструментов

Ответ 5

Также можно явно инициализировать инструментарий, вызвав: com.sun.javafx.application.PlatformImpl#startup(Runnable)

Немного взломанный, из-за использования * Impl, но полезен, если вы не хотите использовать Application или JXFPanel по какой-либо причине.

повторно отправить себя из этого сообщения

Ответ 6

private static Thread thread;

public static void main(String[] args) {

    Main main = new Main();
    startup(main);
    thread = new Thread(main);
    thread.start();
}

public static void startup(Runnable r) {
    com.sun.javafx.application.PlatformImpl.startup(r);
}

@Override
public void run() {
    SoundPlayer.play("BelievexBelieve.mp3");
}

Это моё решение. Класс называется Main и реализует Runnable. Метод startup(Runnable r) является ключевым.

Ответ 7

Начиная с JavaFX 9, вы можете запускать приложение JavaFX без расширения класса Application, вызывая Platform.startup():

Platform.startup(() ->
{
    // This block will be executed on JavaFX Thread
}

Этот метод запускает среду выполнения JavaFX.