Cargando nuevo fxml en la misma escena

Tengo 2 archivos de fxml:

  • Diseño (encabezado, menús y contenido)
  • Anchorpane (se supone que debe colocarse dentro del contenido del otro archivo fxml)

Me gustaría saber cómo puedo cargar el segundo archivo dentro del espacio de contenido de la escena “Principal”. ¿Y eso es bueno para trabajar en javaFX o es mejor cargar una nueva escena?

Intento hacer algo como esto, pero no funciona:

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

Gracias por la ayuda.

Por qué tu código no funciona

El cargador crea un nuevo AnchorPane, pero nunca agrega el nuevo panel a un elemento primario en el gráfico de escena.

Arreglo rapido

En lugar de:

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

Escribir:

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

Reemplazar el contenido de los niños con su nueva vista. El contenido en sí permanece en el gráfico de escena, por lo que cuando configuras sus elementos secundarios, también los adjuntas al gráfico de escena al mismo tiempo.

Es posible que deba jugar con el diseño (por ejemplo, trabajar con diseños de cambio de tamaño automático como StackPanes en lugar de AnchorPanes) para obtener el comportamiento exacto que desee.

En lugar de solo adoptar la solución rápida, recomendaría revisar el marco simple vinculado a continuación, ya que podría proporcionarle un mecanismo más general para obtener el comportamiento que desea.

Referencia FXML Navigation Framework

Creé un pequeño marco para intercambiar paneles de contenido controlado con fxml dentro y fuera de una parte de la escena principal.

El mecanismo del marco es el mismo que el sugerido en la respuesta de Kithril.

  1. Un panel principal para el fxml externo actúa como un titular para paneles secundarios.
  2. El controlador principal para el fxml externo proporciona un método público que se puede usar para intercambiar los paneles secundarios.
  3. Una clase de navegador de conveniencia se inicializa estáticamente con el controlador principal para el diseño externo.
  4. El navegador proporciona un método público estático para cargar un nuevo panel secundario en el contenedor principal (invocando un método en el controlador principal).
  5. Los paneles secundarios se generan en el navegador mediante sus cargadores de archivos fxml respectivos.

Por qué un Framework

El marco parece excesivo para responder a su pregunta, y tal vez lo es. Sin embargo, he encontrado que los dos temas más solicitados relacionados con FXML son:

  1. Navegación entre paneles generados por FXML (esta pregunta).
  2. Cómo pasar datos entre los controladores FXML .

Así que sentí que se justificaba un pequeño marco de demostración para este caso.

Muestra del resultado del marco

La primera pantalla muestra el diseño de la aplicación que muestra la primera vista. Los contenidos son un encabezado que se define en el diseño de la aplicación principal y un panel de contenido infantil intercambiable de color aliceblue.

vista1

En la siguiente pantalla, el usuario ha navegado a la segunda vista, que conserva el encabezado constante del diseño principal y reemplaza el panel secundario original con un nuevo panel de contenido infantil de color coral. El nuevo hijo ha sido cargado desde un nuevo archivo fxml.

vista2

¿Estás buscando algo más sustancial?

Un marco ligero que es más extenso y mejor soportado que el marco de ejemplo de esta pregunta es afterburner.fx .

¿Estás buscando algo aún más simple?

Simplemente cambie la raíz de escena: Cambiando Escenas en JavaFX .

¿Otras opciones?

Transiciones animadas y otras: cambiar entre paneles en JavaFX

No estoy seguro de cuán efectivo es esto, pero parece estar bien y, lo que es más, mucho más simple que los métodos anteriores.

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

Por lo que yo entendí, lo que está sucediendo aquí es esto (es muy similar a lo que está sucediendo en el método Start () en la clase de aplicación):

 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 } 

Sin embargo, no soy un experto en Java y soy bastante nuevo en la progtwigción, por lo que sería bueno si alguien con experiencia lo evaluara.

EDITAR: He encontrado un método aún más simple;

Vaya a la clase MainApplication y cree static Stage parentWindow.

 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(); } 

Ahora tienes acceso a tu Escenario principal así que en cualquier lugar de un progtwig puedes hacer algo como eso para cambiar la escena:

  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. 

Otros pueden tener una mejor solución, pero mi solución ha sido tener un contenedor simple como VBox en el fxml externo, luego cargar el nuevo contenido y agregarlo como elemento secundario del contenedor. Si solo está cargando uno o dos formularios, este podría ser el camino a seguir. Sin embargo, para un marco más completo, encontré útil esta publicación en el blog: https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1 Tiene un código fuente para su framework que incluye transiciones sofisticadas. Aunque está destinado a gestionar escenas de primer nivel, también me resultó fácil adaptarme para gestionar regiones de contenido interno.

Mi ejemplo de la máscara

Utilizando:

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

En este caso, le recomiendo que use un componente personalizado en su lugar. Primero crea un componente personalizado para tu contenido:

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

Reemplace el marcado AnchorPane en la raíz de su archivo vista2.fxml con fx:root :

  ...  

Luego, puede hacer esto simplemente utilizando el enlace de evento personalizado y la función de flecha. Agregue la propiedad del controlador de eventos a su clase de Content :

 private final ObjectProperty> propertyOnPreviousButtonClick = new SimpleObjectProperty>(); @FXML private void onPreviousButtonClick(ActionEvent event) { propertyOnPreviousButtonClick.get().handle(event) } public void setOnPreviousButtonClick(EventHandler handler) { propertyOnPreviousButtonClick.set(handler); } 

Finalmente, vincula tu controlador de eventos personalizado en tu código java o 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); } 

Si no desea agregar contenido dinámicamente, simplemente setVisible() en true o false

Me metí en esto también Probé la mayoría de las respuestas, no era lo que quería, así que usé los ideales que se me dieron para hacer esto:

 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); } } 

esta es mi clase principal Main.java con la ventana de aterrizaje / página mainView.fxml. Usé un poco de la idea de @Tomasz, aunque me confundí un lil antes de hacerlo en mi clase 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(); } } 

creó una nueva ventana principal llamada ‘ventana1’ que cargó el segundo archivo fxml llamado ‘displayView.fxml’ en el directorio src. creó un objeto de la etapa de vista principal y configuró la escena para la escena recién creada cuya raíz es window1. Espero que esto ayude a los que entran en #JavaFX ahora.

Si está buscando una forma de hacer que el botón llame al nuevo archivo fxml, esto funcionó para mí.

 @FXML private void mainBClicked(ActionEvent event) throws IOException { Stage stage; Parent root; stage=(Stage) ((Button)(event.getSource())).getScene().getWindow(); root = FXMLLoader.load(getClass().getResource("MainMenu.fxml")); Scene scene = new Scene(root); stage.setScene(scene); stage.show(); } 
Intereting Posts