¿Cómo puedo pasar parámetros a una ventana secundaria en javafx? ¿Hay alguna manera de comunicarse con el controlador correspondiente?
Por ejemplo: el usuario elige un cliente de TableView
ay se abre una nueva ventana que muestra la información del cliente.
Stage newStage = new Stage();
try
{
AnchorPane page = (AnchorPane) FXMLLoader.load(HectorGestion.class.getResource(fxmlResource));
Scene scene = new Scene(page);
newStage.setScene(scene);
newStage.setTitle(windowTitle);
newStage.setResizable(isResizable);
if(showRightAway)
{
newStage.show();
}
}
newStage
Sería la nueva ventana. El problema es que no puedo encontrar una manera de decirle al controlador dónde buscar la información del cliente (pasando el id como parámetro).
¿Algunas ideas?
Respuestas:
Enfoque recomendado
Esta respuesta enumera diferentes mecanismos para pasar parámetros a los controladores FXML.
Para aplicaciones pequeñas, recomiendo pasar parámetros directamente de la persona que llama al controlador: es simple, directo y no requiere marcos adicionales.
Para aplicaciones más grandes y complicadas, valdría la pena investigar si desea utilizar mecanismos de inyección de dependencia o bus de eventos dentro de su aplicación.
Pasando parámetros directamente de la persona que llama al controlador
Pase datos personalizados a un controlador FXML recuperando el controlador de la instancia del cargador FXML y llamando a un método en el controlador para inicializarlo con los valores de datos requeridos.
Algo así como el siguiente código:
Se construye un nuevo FXMLLoader como se muestra en el código de ejemplo, es decir
new FXMLLoader(location)
. La ubicación es una URL y puede generar dicha URL a partir de un recurso FXML al:Tenga cuidado de NO usar una función de carga estática en el FXMLLoader, o no podrá obtener su controlador desde la instancia del cargador.
Las instancias de FXMLLoader nunca saben nada sobre los objetos de dominio. No pasa directamente objetos de dominio específicos de la aplicación al constructor FXMLLoader, sino que:
Este blog (de otro escritor) proporciona un ejemplo alternativo, pero similar .
Configuración de un controlador en el FXMLLoader
Puede construir un nuevo controlador en código, pasando los parámetros que desee de su llamante al constructor del controlador. Una vez que haya construido un controlador, puede configurarlo en una instancia de FXMLLoader antes de invocar la
load()
instancia método de .Para configurar un controlador en un cargador (en JavaFX 2.x) NO PUEDE definir un
fx:controller
atributo en su archivo fxml.Debido a la limitación en la
fx:controller
definición en FXML, personalmente prefiero obtener el controlador del FXMLLoader en lugar de configurar el controlador en el FXMLLoader.Hacer que el controlador recupere los parámetros de un método estático externo
Este método se ejemplifica con la respuesta de Sergey a Javafx 2.0 How-to Application.getParameters () en un archivo Controller.java .
Usar inyección de dependencia
FXMLLoader admite sistemas de inyección de dependencias como Guice, Spring o Java EE CDI al permitirle configurar una fábrica de controladores personalizados en FXMLLoader. Esto proporciona una devolución de llamada que puede usar para crear la instancia del controlador con valores dependientes inyectados por el sistema de inyección de dependencia respectivo.
Un ejemplo de aplicación JavaFX y la inyección de dependencia del controlador con Spring se proporciona en la respuesta a:
Un marco de inyección de dependencia realmente agradable y limpio se ejemplifica en el marco afterburner.fx con una aplicación de muestra de ataques de aire que lo utiliza. afterburner.fx se basa en JEE6 javax.inject para realizar la inyección de dependencia.
Use un bus de eventos
Greg Brown, el creador e implementador de la especificación FXML original, a menudo sugiere considerar el uso de un bus de eventos, como el EventBus de Guava , para la comunicación entre controladores instanciados FXML y otra lógica de aplicación.
Preguntas y respuestas de seguimiento
Es una solución funcional a un problema. Se devuelve una etapa de la
showCustomerDialog
función para que una clase externa pueda almacenar una referencia a ella que tal vez desee hacer algo, como ocultar la etapa con un clic de botón en la ventana principal, más adelante. Una solución alternativa orientada a objetos podría encapsular la funcionalidad y la referencia de etapa dentro de un objeto CustomerDialog o hacer que CustomerDialog extienda Stage. Un ejemplo completo de una interfaz orientada a objetos para un cuadro de diálogo personalizado que encapsula FXML, el controlador y los datos del modelo está más allá del alcance de esta respuesta, pero puede ser una publicación de blog que valga la pena para cualquiera que esté dispuesto a crear una.Información adicional proporcionada por el usuario de StackOverflow llamado @dzim
Ejemplo de inyección de dependencia de arranque de resorte
La pregunta de cómo hacerlo "The Spring Boot Way", hubo una discusión sobre JavaFX 2, que respondí en el enlace permanente adjunto. El enfoque aún es válido y se probó en marzo de 2016, en Spring Boot v1.3.3. PUBLICACIÓN: https://stackoverflow.com/a/36310391/1281217
A veces, es posible que desee pasar los resultados a la persona que llama, en cuyo caso puede consultar la respuesta a la pregunta relacionada:
fuente
En este ejemplo, utilizaremos 5 archivos:
Todos los archivos se enumeran en su totalidad al final de esta publicación.
La meta: Para demostrar que pasa los valores de
Controller1
aController2
y viceversa.El flujo del programa:
TextField
, aButton
y aLabel
. CuandoButton
se hace clic en, se carga y muestra la segunda ventana, incluido el texto ingresado en elTextField
.TextField
, aButton
y aLabel
. ElLabel
mostrará el texto ingresado en elTextField
en la primera escena.TextField
y hacer clic en élButton
, la primera escenaLabel
se actualiza para mostrar el texto ingresado.Esta es una demostración muy simple y seguramente podría representar alguna mejora, pero debería dejar el concepto muy claro.
El código en sí también se comenta con algunos detalles de lo que está sucediendo y cómo.
Main.java:
Controller1.java:
Controller2.java:
Layout1.fxml:
Layout2.fxml:
fuente
loader.setController(this)
y agregar el controlador en el archivo FXML bloquea la aplicaciónloader.getController()
La clase javafx.scene.Node tiene un par de métodos setUserData (Object) y Object getUserData ()
Que podría usar para agregar su información al Nodo.
Por lo tanto, puede llamar a page.setUserData (info);
Y el controlador puede verificar, si la información está configurada. Además, puede usar ObjectProperty para la transferencia de datos hacia atrás, si es necesario.
Observe una documentación aquí: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Antes de la frase "En la primera versión, handleButtonAction () está etiquetado con @FXML para permitir el marcado definido en el documento del controlador para invocarlo. En el segundo ejemplo, el campo del botón se anota para permitir que el cargador establezca su valor. El método initialize () se anota de manera similar ".
Por lo tanto, debe asociar un controlador con un nodo y establecer los datos de un usuario en el nodo.
fuente
Aquí hay un ejemplo para pasar parámetros a un documento fxml a través del espacio de nombres.
Defina el valor
External Text
para la variable de espacio de nombreslabelText
:fuente
FXMLLoader.CONTROLLER_KEYWORD
,FXMLLoader.LOCATION_KEY
,FXMLLoader.RESOURCES_KEY
y cualquier cadena que se utiliza como valor para elfx:id
atributo.Esto funciona ..
Recuerde que la primera vez que imprima el valor de aprobación obtendrá un valor nulo. Puede usarlo después de cargar sus ventanas, lo mismo para todo lo que desee codificar para cualquier otro componente.
fuente
Tienes que crear una clase de contexto.
Solo tiene que configurar la instancia del controlador en la inicialización usando
y puedes usarlo desde toda tu aplicación simplemente usando
Ahora puede pasar parámetros a cualquier controlador desde toda la aplicación.
fuente
Sí tu puedes.
Necesita agregar en el primer controlador:
Luego, en el segundo, declare un cliente, luego en la parte inferior de su controlador:
fuente
Aquí hay un ejemplo para usar un controlador inyectado por Guice.
Aquí hay una implementación concreta del cargador:
Tenga en cuenta que este ejemplo carga la vista en el centro de un BoarderPane que es la raíz de la escena en el escenario. Esto es irrelevante para el ejemplo (detalle de implementación de mi caso de uso específico) pero decidí dejarlo puesto, ya que algunos pueden encontrarlo útil.
fuente
Puede decidir usar una lista pública observable para almacenar datos públicos, o simplemente crear un método de establecimiento público para almacenar datos y recuperarlos del controlador correspondiente
fuente
¿Por qué responder una pregunta de 6 años?
Uno de los conceptos más fundamentales para trabajar con cualquier lenguaje de programación es cómo navegar de uno (ventana, formulario o página) a otro. Además, mientras realiza esta navegación, el desarrollador a menudo quiere pasar datos de uno (ventana, formulario o página) y mostrar o usar los datos pasados.
Si bien la mayoría de las respuestas aquí proporcionan ejemplos de buenos a excelentes cómo lograr esto, pensamos que lo pondríamos en práctica. una muesca o dos o tres
Dijimos tres porque navegaremos entre tres (ventana, formulario o página) y usaremos el concepto de variables estáticas para pasar datos alrededor de la (ventana, formulario o página)
También incluiremos un código de toma de decisiones mientras navegamos
Iniciar controlador
Controlador de página uno
Controlador de página dos
Debajo están todos los archivos FXML
fuente