Я неоднократно сталкивался с методом setControllerFactory.К сожалению, я не могу найти хорошее объяснение того, как правильно его использовать и какова его конкретная цель:
По умолчанию метод FXMLLoader.load()
создает экземпляр контроллера, названный в документе fxml, используя 0-арг конструктор.Метод FXMLLoader.setControllerFactory
используется, когда вы хотите, чтобы ваш объект FXMLLoader определил экземпляры контроллеров определенным образом, например, использовал другой конструктор контроллера для определенных аргументов, вызывал метод на контроллере до его возврата и т. Д., Как в
FXMLLoader loader = new FXMLLoader(...);
loader.setControllerFactory(c -> {
return new MyController("foo", "bar");
});
Теперь при вызове loader.load()
контроллер будет создан, как указано выше.Однако вызов метода FXMLLoader.setController
на существующем контроллере может быть проще.
Мне кажется, что я бы больше всего выиграл от метода / класса, с помощью которого я мог бы организовать все свои пользовательские контроллеры, загрузитьи инициализировать их в подходящее время, а затем снова получить к ним доступ
Когда я впервые столкнулся с этой проблемой, как вы, я попробовал и повторил много подходов.В конце концов я остановился на том, что превратил мой основной класс приложений в синглтон.Шаблон синглтона великолепен, когда вам нужно создать один экземпляр класса, который должен быть доступен во всей вашей программе.Я знаю, что есть много людей, которые будут с этим сталкиваться (поскольку это, по сути, глобальная переменная с добавленной структурой), но я обнаружил, что это значительно уменьшило сложность, так как мне больше не нужно было управлять несколько искусственной структурой ссылок на объекты.идти в разные стороны.
Синглтон позволяет контроллерам взаимодействовать с вашим основным классом приложения, вызывая, например, MyApp.getSingleton ().Находясь в основном классе приложения, вы можете затем организовать все свои представления в частном HashMap и добавить общедоступные методы add (...), remove (...) и activ (...), которые могут добавлять или удалять представления.с карты или активируйте представление на карте (т. е. установите корень сцены для нового представления).
Для приложения с множеством представлений, которые могут быть помещены в разные пакеты, вы можете организовать их расположения с помощью перечисления:
public enum View {
LOGIN("login/Login.fxml"),
NEW_USER("register/NewUser.fxml"),
USER_HOME("user/UserHome.fxml"),
ADMIN_HOME("admin/AdminHome.fxml");
public final String location;
View(String location) {
this.location = "/views/" + location;
}
}
Ниже приведен пример основного класса приложения:
public final class MyApp extends Application {
// Singleton
private static MyApp singleton;
public MyApp() { singleton = this; }
public static MyApp getSingleton() { return singleton; }
// Main window
private Stage stage;
private Map<View, Parent> parents = new HashMap<>();
@Override
public void start(Stage primaryStage) {
stage = primaryStage;
stage.setTitle("My App");
add(View.LOGIN);
stage.setScene(new Scene(parents.get(View.LOGIN)));
stage.show();
}
public void add(View view) {
var loader = new FXMLLoader(getClass().getResource(view.location));
try {
Parent root = loader.load();
parents.put(view, root);
} catch (IOException e) { /* Do something */ }
}
public void remove(View view) {
parents.remove(view);
}
public void activate(View view) {
stage.getScene().setRoot(parents.get(view));
}
public void removeAllAndActivate(View view) {
parents.clear();
add(view);
activate(view);
}
}
Если у вас есть ресурсы всего приложения, вы можете поместить их в класс приложения и добавить методы получения / установки так,ваши контроллеры могут получить к ним доступ.Вот пример класса контроллера:
public final class Login implements Initializable {
MyApp app = MyApp.getSingleton();
// Some @FXML variables here..
@FXML private void login() {
// Authenticate..
app.removeAllAndActivate(View.USER_HOME);
}
@FXML private void createAccount() {
app.add(View.NEW_USER);
app.activate(View.NEW_USER);
}
@Override
public void initialize(URL url, ResourceBundle rb) {}
}