Я изучаю JavaFX, и я столкнулся с проблемой, связанной с созданием экземпляров контроллеров, которые я не могу решить. По сути, мне интересно, возможно ли выполнить одно из следующих действий:
- Передать параметр конструктору контроллера при включении F XML с
<fx:include>
; или - Укажите пользовательский экземпляр контроллера, который будет использоваться при включении файла F XML с
<fx:include>
.
Обратите внимание, что эти проблемы связаны. Фактически, причина, по которой я спрашиваю о варианте (2), заключается в том, что он решит вариант (1).
Моя настройка
I иметь следующий «основной» файл F XML:
<!-- XML declaration, imports, etc. removed for brevity -->
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml">
<!-- ... -->
<center>
<!-- Note that PageSwitcher is a custom control that is capable of switching between pages — you should be able to ignore it here. -->
<PageSwitcher fx:id="mainPageSwitcher" currentPageIndex="0">
<!-- ... -->
<fx:include source="dashboard.fxml" fx:id="dashboard" />
</PageSwitcher>
</center>
</BorderPane>
У него есть связанный контроллер MainPaneController
. Я не буду отображать его здесь, но могу при необходимости.
Возможно, вы заметили, что мой основной файл F XML не имеет атрибута fx:controller
в его BorderPane
, несмотря на то, что что я сказал, что у него есть связанный контроллер. Это потому, что вместо того, чтобы позволить FXMLLoader
создать контроллер для меня (и, таким образом, я не могу передать параметры конструктору класса контроллера), я выбрал при загрузке главной страницы F XML в моем главном классе приложения (то есть классе, расширяющем Application), чтобы создать свой собственный экземпляр класса MainPaneController
. Вы можете увидеть метод start()
моего основного класса приложений:
@Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader mainPaneLoader;
MainPaneController mainPaneController;
Parent mainPane;
// Initialize the project manager.
projectManager = new ProjectManager(primaryStage);
// Initialize the main pane loader.
mainPaneLoader = new FXMLLoader();
// Initialize the main pane controller.
mainPaneController = new MainPaneController(projectManager);
// Load the main pane.
mainPaneLoader.setController(mainPaneController);
mainPaneLoader.setLocation(getClass().getResource(MAIN_PANE_FXML_PATH));
mainPane = mainPaneLoader.load();
Scene mainScene;
// Create the main scene and add it to the primary scene.
mainScene = new Scene(mainPane);
primaryStage.setScene(mainScene);
// Initialize the primary stage.
primaryStage.setTitle(APPLICATION_TITLE);
// Show the primary stage.
primaryStage.show();
}
Обратите внимание, что объект "менеджер проекта", определенный выше и переданный в конструктор контроллера главной панели, на самом деле является основной причиной этого весь вопрос; это (помимо передачи на главный контроллер) объект, который мне нужно передать контроллеру файла F XML, который я включил в основной файл F XML, используя <fx:include>
.
Теперь, этот подход создания моего собственного экземпляра контроллера и передачи его FXMLLoader
работает очень хорошо для меня. Это позволяет мне легко, без каких-либо размышлений, передавать параметры конструктору контроллера. Тем не менее, он работает только тогда, когда у меня есть объект FXMLoader
, которому можно присвоить экземпляр контроллера.
В случае other , где я включаю файл F XML из основного F Файл XML с использованием <fx:include>
, JavaFX создает для меня контроллер, не предоставляя мне возможности либо (1) передать параметры конструктору контроллера, либо (2) использовать мой собственный экземпляр контроллера.
Что я попробовал
Во время исследования этой проблемы я наткнулся на этот вопрос StackOverflow , который, по-видимому, имел какое-то отношение к проблеме , Из него я узнал о FXMLLoader.setControllerFactory()
, который поначалу казался способным решить эту проблему. Однако, чтобы использовать его, я был вынужден использовать какое-то довольно грязное отражение, чтобы проверить, может ли конструктор типа принять мой объект, а затем использовать more отражение для создания контроллера, все время надеясь, что нет ошибки должны были быть брошены из-за лазейки в моем коде. Я был вынужден признать, что это не сработало.
Я также экспериментировал, вместо того, чтобы передать свой объект конструктору контроллера, установив объект на контроллере после контроллер был инициализирован. Однако это не сработало, потому что мне нужно было использовать объект в методе initialize()
моего контроллера, который вызывается до . Я бы установил объект на контроллере. Потенциально это можно обойти, добавив другой метод инициализации , в котором может быть расположена любая функциональность, требующая объекта, например, objectInitialized()
; но тогда мне нужно было бы добавить этот метод к каждому контроллеру, которому нужна эта функциональность, и я должен был бы не забыть вызвать все эти методы в какой-то момент. Кроме того, я хотел, чтобы объект был полем final
в классе контроллера; очевидно, он не может быть окончательным, если его нужно установить извне.
Наконец, я также рассмотрел вариант, что для каждого файла F XML, который мне нужно включить в основной файл F XML, вместо включения его в FMXL, я мог бы сделать это из Java контроллер. Таким образом, я мог создать свой собственный FXMLLoader
, установить на нем свой собственный экземпляр контроллера и, таким образом, решить проблему. Тем не менее, я бы, по возможности, предпочел бы сохранить весь код пользовательского интерфейса в файлах F XML.
Summary
In Итак, мне нужен способ передать параметры конструктору моего контроллера при использовании <fx:include>
.
. Я понимаю, что это длинный вопрос и довольно сложный вопрос, поэтому я очень благодарен за любую помощь, которую вы можете предоставить. , Также, пожалуйста, дайте мне знать в комментариях, если мне нужно что-то уточнить или опубликовать дополнительный код.
Спасибо всем за помощь!
—Jacob