Подтвердить что ты не робот

Загрузка нового fxml в ту же сцену

У меня есть 2 файла fxml:

  • Макет (заголовок, меню и содержимое)
  • Anchorpane (предполагается, что он помещается внутри содержимого из другого файла fxml)

Я хотел бы знать, как загрузить второй файл внутри пространства содержимого из сцены "Мастер". И хорошо ли работать в javaFX или лучше загружать новую сцену?

Я пытаюсь сделать что-то подобное, но это не работает:

@FXML
private AnchorPane content;

@FXML
private void handleButtonAction(ActionEvent event) {        
    content = (AnchorPane) FXMLLoader.load("vista2.fxml");
}

Спасибо за помощь.

4b9b3361

Ответ 1

Почему ваш код не работает

Загружатель создает новую AnchorPane, но вы никогда не добавляете новую панель родительскому графу сцены.

Быстрое исправление

Вместо:

content = (AnchorPane) FXMLLoader.load("vista2.fxml");

Запись:

content.getChildren().setAll(FXMLLoader.load("vista2.fxml"));

Замена дочерних элементов содержимого вашей новой перспективой. Сам контент остается в графе сцены, поэтому, когда вы устанавливаете его дочерние элементы, вы также прикрепляете их к графику сцены.

Возможно, вам придется поиграть с макетом (например, работать с макетами автоматического изменения размера, такими как StackPanes, а не AnchorPanes), чтобы получить точное поведение, которое вы хотите.

Вместо того, чтобы просто принять быстрое исправление, я бы посоветовал рассмотреть простую фреймворк, связанную ниже, поскольку это может предоставить вам более универсальный механизм для получения желаемого поведения.

Справочная инфраструктура навигации FXML

Я создал небольшую структуру для замены панелей контента, контролируемых с помощью fxml, внутри и вне части основной сцены.

Механизм структуры такой же, как и в ответе кифрила.

  • Основное поле для внешнего fxml действует как держатель для дочерних окон.
  • Основной контроллер внешнего fxml предоставляет общедоступный метод, который можно использовать для замены дочерних окон.
  • Класс удобного навигатора статически инициализируется основным контроллером для внешнего макета.
  • Навигатор предоставляет публичный статический метод для загрузки новой дочерней панели в основной контейнер (путем вызова метода на основном контроллере).
  • В навигаторе создаются дочерние панели со своими соответствующими загрузчиками fxml.

Почему Framework

Структура кажется излишней для ответа на ваш вопрос, и, возможно, это так. Тем не менее, я обнаружил, что две наиболее часто задаваемые темы, связанные с FXML:

Таким образом, я чувствовал, что для этого случая была гарантирована небольшая демонстрационная структура.

Образец Framework Framework

На первом экране отображается макет приложения, отображающий первую перспективу. Содержимое представляет собой заголовок, который определяется в макете основного приложения и цветной цветной интерактивной дочерней контентной панели aliceblue.

vista1

На следующем экране пользователь перешел на вторую перспективу, которая сохраняет заголовок константы из основного макета и заменяет исходную дочернюю панель новой дочерней панелью с цветным цветом. Новый ребенок загружен из нового файла fxml.

vista2

Ищете что-то более существенное?

Легкая структура, которая более обширна и лучше поддерживается, чем структура выборки из этого вопроса, afterburner.fx.

Ищете что-то еще более упрощенное?

Просто замените корень сцены: Изменение сцен в JavaFX.

Другие параметры?

Анимированные переходы и другие: Переключение между панелями в JavaFX

Ответ 2

Я не уверен, насколько это эффективно, но кажется, что это прекрасно, и что еще, гораздо проще для методов выше.

https://www.youtube.com/watch?v=LDVztNtJWOo

Насколько я понял, что происходит здесь, это (его очень похоже на то, что происходит в методе Start() в классе приложения):

private void buttonGoToWindow3Action(ActionEvent event) throws IOException{
    Parent window3; //we need to load the layout that we want to swap
    window3 = (StackPane)FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow3"));

    Scene newScene; //then we create a new scene with our new layout
    newScene = new Scene(window3);

    Stage mainWindow; //Here is the magic. We get the reference to main Stage.
    mainWindow = (Stage)  ((Node)event.getSource()).getScene().getWindow();

    mainWindow.setScene(newScene); //here we simply set the new scene
}

Однако я не эксперт по java и совершенно новый для программирования, поэтому было бы хорошо, если бы кто-то испытал его.

EDIT: Ive нашел еще более простой метод;

Перейдите в класс MainApplication и создайте статический родительский этап Stage.

public static Stage parentWindow;
@Override
public void start(Stage stage) throws Exception {
    parentWindow = stage;

    Parent root = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLMainScene.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);
    stage.show();
}

Теперь вы получаете доступ к своей основной сцене, поэтому где угодно в программе вы можете сделать что-то подобное, чтобы изменить сцену:

    Parent window1;
    window1 = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow1.fxml"));

    //Scene newSceneWindow1 = new Scene(window1);

    Stage mainStage;
    //mainStage = (Stage)  ((Node)event.getSource()).getScene().getWindow();
    mainStage = MainApplication.parentWindow;
    mainStage.getScene().setRoot(newSceneWindow1); //we dont need to change whole sceene, only set new root.

Ответ 3

Другие могут иметь лучшее решение, но мое решение состояло в том, чтобы иметь простой контейнер, такой как VBox во внешнем fxml, затем загружать новый контент и добавлять его в качестве дочернего элемента контейнера. Если вы загружаете только одну или две формы, это может пойти по пути. Однако для более полной структуры я нашел эту статью полезной: https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1 У нее есть исходный код для ее фреймворка, который включает в себя причудливые переходы. Хотя это и предназначалось для управления сценами верхнего уровня, мне было легко адаптироваться для управления областями внутреннего контента.

Ответ 4

Мой пример маски .

Использование:

Main.getNavigation().load(View2.URL_FXML).Show();
Main.getNavigation().GoBack();

Ответ 5

В этом случае я рекомендую вместо настраиваемый компонент. Сначала создайте пользовательский компонент для вашего контента:

class Content2 extends AnchorPane {
    Content() {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("vista2.fxml");
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    }
}

Замените разметку AnchorPane в корневом каталоге вашего файла vista2.fxml на fx:root:

<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
    ...
</fx:root>

Затем вы можете сделать это, просто используя специальную привязку событий и функцию стрелки. Добавьте свойство обработчика события в класс Content:

private final ObjectProperty<EventHandler<ActionEvent>> propertyOnPreviousButtonClick = new SimpleObjectProperty<EventHandler<ActionEvent>>();

@FXML
private void onPreviousButtonClick(ActionEvent event) {
    propertyOnPreviousButtonClick.get().handle(event)
}

public void setOnPreviousButtonClick(EventHandler<ActionEvent> handler) {
    propertyOnPreviousButtonClick.set(handler);
}

Наконец, привяжите свой пользовательский обработчик событий в своем java-коде или fxml:

@FXML
onNextButtonClick() {
    Content2 content2 = new Content2();
    content2.setOnPreviousButtonClick((event) -> {
        Content1 content1 = new Content1();

        layout.getChildren().clear();
        layout.getChildren().add(content1);
    });

    layout.getChildren().clear();
    layout.getChildren().add(content2);    
}

Если вы не хотите динамически добавлять контент, просто setVisible() - true или false

Ответ 6

В этом тоже Пробовал большинство ответов, не был тем, чего я хотел, поэтому я просто использовал идеалы, данные для этого:

public class Main extends Application {
public static Stage homeStage;
@Override
public void start(Stage primaryStage) throws Exception{
    homeStage = primaryStage;
    Parent root = FXMLLoader.load(getClass().getResource("mainView.fxml"));
    root.getStylesheets().add(getClass().getResource("stylesheet/custom.css").toExternalForm());
    homeStage.setTitle("Classification of Living Organisms");
    homeStage.setScene(new Scene(root, 600, 500));
    homeStage.show();
}


public static void main(String[] args) {
    launch(args);
  }
}

это мой основной класс. Main.java с окном/страницей mainView.fxml. Использовал немного идеи @Tomasz, хотя меня смутил лил, прежде чем я сделал это в своем классе mainController.java:

public void gotoSubMenu(Event event) {
    Parent window1;
    try {
        window1 = FXMLLoader.load(getClass().getResource("src/displayView.fxml"));
        Stage window1Stage;
        Scene window1Scene = new Scene(window1, 600, 500);
        window1Stage = Main.homeStage;
        window1Stage.setScene(window1Scene);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

создано новое родительское окно под названием 'window1', которое загрузило второй файл fxml с именем displayView.fxml в каталог src. создал объект основного этапа представления и установил сцену для вновь созданной сцены, корнем которой является window1. Надеюсь, это поможет тем, кто входит в #JavaFX сейчас.