JavaFX 2.1: boîte à outils non initialisée

mon application est basée sur le Swing. Je voudrais présenter JavaFX et le configurer pour rendre une scène sur un écran secondaire. Je pourrais utiliser un JFrame pour tenir un JFXPanel qui pourrait contenir un JFXPanel mais je voudrais réaliser cela avec L'API JavaFX.

sous-classement com.soleil.verre.interface.L'Application et l'utilisation de l'Application.launch (this) n'est pas une option car le thread d'invocation serait bloqué.

lors de l'instanciation D'une étape de Swing EDT, le l'erreur que j'obtiens est:

java.lang.IllegalStateException: Toolkit not initialized

des conseils?


EDIT: Conclusions

Problème : Non-trivial Swing interface graphique aux besoins de l'application à exécuter JavaFX composants. Le processus de démarrage de l'Application initialise l'interface graphique après le démarrage d'une couche de service dépendante.

Solutions

Sous-Classe JavaFX Classe d'Application et l'exécuter dans un filetage séparé par exemple:

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

Sidenote: Parce Que L'Application.la méthode launch () prend un Class<? extends Application> comme argument, il faut utiliser une variable globale pour signaler que L'environnement JavaFX a été initialisé.

approche Alternative: instancier JFXPanel en Swing Event Dispatcher Fil :

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

en utilisant cette approche le fil d'appel va attendre Jusqu'à ce que JavaFX environnement soit mis en place.

choisissez la solution que vous voulez. Je suis allé avec le second parce qu'il n'a pas besoin d'une variable globale pour signaler l'initialisation de L'environnement JavaFX et aussi ne gaspille pas un fil.

51
demandé sur Dan Vulpe 2012-06-30 15:39:30

6 réponses

la seule façon de travailler avec JavaFX est d'appliquer la sous-classe ou D'utiliser JFXPanel, exactement parce qu'ils préparent env et toolkit.

Le fil de blocage

peut être résolu en utilisant new Thread(...) .

bien que je suggère D'utiliser Jfxpanel si vous utilisez JavaFX dans la même VM que Swing/AWT, vous pouvez trouver plus de détails ici: est-il correct d'utiliser AWT avec JavaFx?

21
répondu Sergey Grinev 2017-05-23 12:03:02

a trouvé une solution. Si je crée juste un JFXPanel à partir de Swing EDT avant d'invoquer la plate-forme JavaFX.runLater il fonctionne. Je ne sais pas si cette solution est fiable, je pourrais choisir JFXPanel et JFrame s'il s'avère être instable.

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();
                    }
                });
            }
        });
    }
}
18
répondu Dan Vulpe 2012-06-30 20:19:15

j'ai vérifié le code source et c'est pour initialiser

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

et d'en sortir

com.sun.javafx.application.PlatformImpl.exit();
6
répondu user28775 2017-10-26 14:11:14

j'ai utilisé la suite lors de la création de unittests pour tester les mises à jour de tableview javaFX

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

        }
    }

même si ce post n'est pas lié à des tests, alors il m'a aidé à obtenir mon unittest pour travailler

  • sans la pré-classe Inittoolkit, alors l'instanciation de TableView dans l'unittest donnerait un message de boîte à outils manquante
4
répondu serup 2016-07-13 07:41:59

il y a aussi moyen d'initialiser la boîte à outils explicitement, en appelant: com.sun.javafx.application.PlatformImpl#startup(Runnable)

petit peu hacky, en raison de l'utilisation de *Impl, mais est utile, si vous ne voulez pas utiliser Application ou JXFPanel pour une raison quelconque.

re-poster moi-même à partir de ce post

4
répondu krzychek 2017-05-23 12:26:24
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");
}

C'est ma solution. La classe S'appelle Main et implémente Runnable. La méthode startup(Runnable r) est la clé.

0
répondu Jack Lin 2018-05-12 02:11:40