problèmes de compatibilité javafx 8-Champs statiques FXML


J'ai conçu une application javafx qui fonctionne bien dans jdk 7. Lorsque j'essaie de l'exécuter en java 8, j'obtiens les exceptions ci-dessous:

javafx.fxml.LoadException: 
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2617)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2595)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3230)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3191)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3164)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3140)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3132)


Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Root cannot be null
    at javafx.scene.Scene.<init>(Scene.java:364)
    at javafx.scene.Scene.<init>(Scene.java:232)
        at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:204)
    at javafx.concurrent.EventHelper.fireEvent(EventHelper.java:219)
    at javafx.concurrent.Task.fireEvent(Task.java:1357)
    at javafx.concurrent.Task.setState(Task.java:720)
    at javafx.concurrent.Task$TaskCallable$2.run(Task.java:1438)
    at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
    at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
    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.access$300(WinApplication.java:39)
    at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
    at java.lang.Thread.run(Thread.java:744)

J'ai découvert que la raison en est dans la méthode initialize de la classe controller, je ne suis pas en mesure d'utiliser les méthodes intégrées dans un composant statique. (Par exemple: staticMyTextField.setText () est à l'origine du problème en java 8 mais pas en java 7). Je ne suis pas en mesure de trouver quoi que ce soit documenté à ce sujet dans les guides javafx. Quelqu'un peut-il veuillez fournir quelques idées sur les raisons pour lesquelles cela cause un problème dans Java 8? Et partagez également des documents liés à cela, le cas échéant.

Author: jewelsea, 2014-04-16

1 answers

, Il semble que vous essayez d'injecter un TextField dans un champ statique. Quelque chose comme

@FXML
private static TextField myTextField ;

Cela a apparemment fonctionné dans JavaFX 2.2. Cela ne fonctionne pas dans JavaFX 8. Comme aucune documentation officielle n'a jamais pris en charge cette utilisation, elle ne viole pas vraiment la rétrocompatibilité, bien que la documentation sur ce que fait exactement le FXMLLoader soit assez lamentable.

Cela n'a pas vraiment de sens de rendre les champs @FXML injectés statiques. Lorsque vous chargez un fichier FXML, il crée nouveaux objets pour chacun des éléments du fichier FXML. Une nouvelle instance de contrôleur est associée à chaque appel à FXMLLoader.load(...) et les champs de cette instance de contrôleur sont injectés avec les objets correspondants créés pour les éléments FXML. Les champs injectés sont donc nécessairement spécifiques à l'instance du contrôleur. Si vous aviez des champs injectés statiques dans le contrôleur et que vous avez chargé deux fois le même fichier FXML et l'avez affiché deux fois dans l'interface utilisateur, vous n'auriez aucun moyen de faire référence les deux ensembles de contrôles.

Mise à Jour: Réponse à la question dans les commentaires

En particulier, n'utilisez pas de champs statiques uniquement pour leur permettre d'être accessibles depuis l'extérieur de la classe. Un champ statique a une seule valeur appartenant à la classe, au lieu d'une valeur pour chaque instance de la classe, et la décision de rendre les champs statiques ne doit être prise que si cela a du sens. En d'autres termes, static définit portée, pas accessibilité. Pour autoriser l'accès à l'instance de données, il vous suffit d'avoir une référence à l'instance. Le FXMLLoader a une méthode getController() qui vous permet de récupérer une référence au contrôleur.

Un point connexe: ce n'est pas non plus une bonne idée d'exposer les contrôles de l'interface utilisateur à partir du contrôleur. Vous devriez plutôt exposer les données. Par exemple, au lieu de définir une méthode getTextField() dans le contrôleur, définissez plutôt une méthode textProperty() qui renvoie un StringProperty représentant le contenu du TextField. La raison en est que lorsque votre patron vient à le bureau et vous dit qu'il veut le TextField sera remplacé par un TextArea, ou ComboBox<String>, ou un autre contrôle, alors il va être beaucoup plus difficile si les classes en dehors du contrôleur à l'aide de votre TextField. La structure des données représentées par votre contrôleur est beaucoup moins susceptible de changer que la mise en œuvre de la façon dont les données sont présentées à l'utilisateur.

Pour quelques exemples

 31
Author: James_D, 2018-01-24 00:36:03