Я пытался вставить контроллер в VBox и AnchorPane, но оба они не работают, и я действительно не понимаю.
Вы упоминаете, пытаясь поставить fx:controller
атрибут как для элемента VBox
, так и для элемента AnchorPane
.Код, который вы показываете, является вашей попыткой добавить его к элементу AnchorPane
.Запуск вашего кода на моем компьютере в результате LoadException
вы наблюдаете.Эта проблема решается путем помещения атрибута fx:controller
в элемент VBox
(корневой элемент ):
<VBox prefHeight="720.0" prefWidth="1025.0"
xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.mycompany.testing.FXMLDocumentController">
<!--- Rest of FXML file omitted for brevity -->
Примечание : Изначально я заметил другую проблему, когда вы не закрывали элементы <VBox>
или <children>
.Тем не менее, эти закрывающие теги были там все время;они просто не рендерится в вашем вопросе, , как указал Фабиан Я забыл проверить это.
Однако , это приводит к другому исключению.
// Beginning of stack trace omitted for brevity...
Caused by: java.lang.NullPointerException
at com.mycompany.testing.FXMLDocumentController.closeLabelPressed(FXMLDocumentController.java:16)
at com.mycompany.testing.LabelTest.start(LabelTest.java:28)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Этопроблема в конечном итоге вызвана этим кодом в LabelTest#start
:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/LabelCloseTest.fxml"));
Parent root = loader.load();
FXMLDocumentController fdc = new FXMLDocumentController(); // the real problem
fdc.closeLabelPressed(); // accesses the labelTest field which is null
Поскольку вы используете fx:controller
, FXMLLoader
создаст свой собственный экземпляр FXMLDocumentController
.Именно в этот случай вводятся аннотированные поля @FXML
.С другой стороны, вы создаете свой собственный экземпляр, в который в не будут введены поля.Вы должны использовать экземпляр FXMLDocumentController
, созданный FXMLLoader
.
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/LabelCloseTest.fxml"));
Parent root = loader.load();
// gets instance from FXMLLoader, must be called after load()
FXMLDocumentController fdc = loader.getController();
fdc.closeLabelPressed();
Однако , в то время как ваш код (с исправлениями до сих пор) будет делать то, что вам нужноне правильный способ сделать это.Метод closeLabelPressed
выглядит так, как будто вы намереваетесь использовать его как обработчик событий, поскольку вы пометили его @FXML
.Однако вы не связываете этот метод с файлом FXML, а вместо этого метод добавляет EventHandler
к Label
.Настройте правильно, вам вообще не следует звонить closeLabelPressed
из LabelTest
.
Первое, что вы должны сделать, это связать метод с Label
через файл FXML.
<!-- previous omitted for brevity -->
<Label fx:id="labelTest" layoutX="1007.0" layoutY="5.0" prefHeight="10.0" prefWidth="5.0" text="X"
textFill="WHITE" onMousePressed="#closeLabelPressed">
<!-- rest omitted for brevity -->
Обратите внимание на атрибут onMousePressed
.
Второе, что нужно сделать, это изменить метод closeLabelPressed
в FXMLDocumentController
.
package com.mycompany.testing;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
public class FXMLDocumentController {
@FXML
private Label labelTest;
@FXML
private void closeLabelPressed(MouseEvent event) {
Platform.exit();
}
}
Теперь метод вызывается при нажатии Label
.Внутренне, FXMLLoader
устанавливает свойство onMousePressed
(из labelTest
) в EventHandler
, которое вызывает closeLabelPressed
.Я также изменил использование System.exit(0)
на Platform.exit()
.Последнее позволит корректно завершить работу среды JavaFX (что позволит вам выполнить очистку в таких местах, как Application#stop
), в то время как первое немедленно завершит работу JVM (и не вернется нормально). Примечание: впрыск Label
может больше не понадобиться .
Третье, что нужно сделать, это удалить вызов closeLabelPressed
в методе LabelTest.start
.
После этих изменений ваш код должен работать должным образом.
Что касается запроса учебных пособий (что не по теме переполнения стека, см. Справочный центр ), которое вы, вероятно, можетенайти много с помощью поиска Google.Официальные источники см. В разделах JavaFX: Начало работы с JavaFX (последнее обновление для JavaFX 8) и Введение в FXML .Здесь также есть много вопросов , связанных с FXML, здесь о переполнении стека.