Фон в потоках JavaFX
Система JavaFX ограничена тем, что не все элементы управления могут быть созданы из потока приложения JavaFX. Когда это имеет место для данного элемента управления или элемента пользовательского интерфейса, его документация отмечает это.
В частности, документация для WebView
гласит:
Объекты WebView должны создаваться и доступны исключительно из потока FX.
Метод init()
приложения JavaFX не выполняется в потоке приложения JavaFX. В моей среде (OS X, JavaFX 13) метод init()
приложения JavaFX вызывается потоком с именем «JavaFX-Launcher». Как видно, если поместить следующий код в init()
:
System.out.println("Thread name: " + Thread.currentThread().getName());
Размещение того же кода в методе start()
показывает, что он работает в другом потоке с именем «JavaFX». Тема приложения ". Это правильный поток для создания WebView.
Загрузчик FXML создает объекты на основе файла FXML. Если вы попытаетесь загрузить FXML из потока приложения JavaFX, и он содержит один из видов элементов управления, которые должны быть созданы в потоке приложения JavaFX, вы получите ошибку (как вы видите). Большинство элементов управления могут быть построены из потока JavaFX, поэтому в большинстве случаев это не проблема. Однако WebView
должен быть должен быть создан в потоке приложения JavaFX, поэтому вы не можете загрузить документ FXML с WebView
из потока приложения JavaFX.
Загрузите FXML, содержащий ссылку на WebView, из start()
, а не init()
Решение состоит в том, чтобы переместить местоположение, в которое вы загружаете FXML, содержащий WebView, из метода init()
вstart()
метод (предложенный kleopatra в комментариях), как показано ниже:
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.web.view")
public class WebViewApplication extends Application {
private ConfigurableApplicationContext context;
private Parent rootNode;
@Override
public void init() throws Exception {
SpringApplicationBuilder builder = new SpringApplicationBuilder(WebViewApplication.class);
context = builder.run(getParameters().getRaw().toArray(new String[0]));
}
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/WebView.fxml"));
loader.setControllerFactory(context::getBean);
rootNode = loader.load();
Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
double width = visualBounds.getWidth();
double height = visualBounds.getHeight();
primaryStage.setScene(new Scene(rootNode, width, height));
primaryStage.centerOnScreen();
primaryStage.show();
}
@Override
public void stop() throws Exception {
context.close();
}
}
Несвязанные рекомендации по проектированию
В качестве отступления я бы посоветовал делает ваше приложение JavaFX приложением Spring.
Вместо этого создайте отдельный класс для приложения Spring:
@SpringBootApplication
public class MySpringApplication {
// spring application implementation.
}
И пусть ваше приложение JavaFX вызывает run()
для SpringApplicationBuilder
экземпляра, который был инициализирован вашим конкретным приложением Springкласс (т. е. в вашем методе JavaFX init()
есть):
SpringApplicationBuilder builder = new SpringApplicationBuilder(
MySpringApplication.class
);
context = builder.run(
getParameters().getRaw().toArray(new String[0])
);
В противном случае у вас может быть два экземпляра приложения JavaFX, созданных во время выполнения (один приложением JavaFX), а другой - приложением Springбегун, который может сбивать с толку. Кроме того, разделив их, вы получите лучший дизайн за счет более четкого разделения интересов: приложение JavaFX отвечает за обработку событий жизненного цикла приложения JavaFX, а приложение Spring отвечает за события жизненного цикла Spring.
Затем вы можете запускать и тестировать свое весеннее приложение, полностью независимое от приложения JavaFX, что должно упростить тестирование и анализ кода.