Abordagem recomendada
Esta resposta enumera diferentes mecanismos para passar parâmetros para controladores FXML.
Para pequenas aplicações, eu recomendo passar parâmetros diretamente do chamador para o controlador - é simples, direto e não requer estruturas extras.
Para aplicativos maiores e mais complicados, vale a pena investigar se você deseja usar os mecanismos de Injeção de Dependência ou Barramento de Eventos em seu aplicativo.
Passando parâmetros diretamente do chamador para o controlador
Passe dados customizados para um controlador FXML, recuperando o controlador da instância do carregador FXML e chamando um método no controlador para inicializá-lo com os valores de dados necessários.
Algo como o seguinte código:
public Stage showCustomerDialog(Customer customer) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(
new Scene(
(Pane) loader.load()
)
);
CustomerDialogController controller =
loader.<CustomerDialogController>getController();
controller.initData(customer);
stage.show();
return stage;
}
...
class CustomerDialogController {
@FXML private Label customerName;
void initialize() {}
void initData(Customer customer) {
customerName.setText(customer.getName());
}
}
Um novo FXMLLoader é construído como mostrado no código de exemplo, ie new FXMLLoader(location)
. O local é um URL e você pode gerar esse URL a partir de um recurso FXML:
new FXMLLoader(getClass().getResource("sample.fxml"));
Cuidado para NÃO usar uma função de carga estática no FXMLLoader, ou você não poderá obter seu controlador da instância do carregador.
As instâncias FXMLLoader nunca sabem nada sobre objetos de domínio. Você não passa diretamente objetos de domínio específicos do aplicativo para o construtor FXMLLoader; em vez disso, você:
- Construa um FXMLLoader com base na marcação fxml em um local especificado
- Obtenha um controlador da instância FXMLLoader.
- Invoque métodos no controlador recuperado para fornecer ao controlador referências aos objetos de domínio.
Este blog (por outro escritor) fornece uma alternativa, mas semelhante, exemplo .
Configurando um controlador no FXMLLoader
CustomerDialogController dialogController =
new CustomerDialogController(param1, param2);
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
loader.setController(dialogController);
Pane mainPane = (Pane) loader.load();
Você pode construir um novo controlador no código, passando os parâmetros desejados do seu chamador para o construtor do controlador. Depois de criar um controlador, você pode configurá-lo em uma instância FXMLLoader antes de chamar o método de load()
instância .
Para definir um controlador em um carregador (no JavaFX 2.x), você NÃO PODE definir um fx:controller
atributo no seu arquivo fxml.
Devido à limitação da fx:controller
definição no FXML, eu pessoalmente prefiro obter o controlador do FXMLLoader do que configurá-lo no FXMLLoader.
Como o controlador recuperar parâmetros de um método estático externo
Este método é exemplificado pela resposta de Sergey ao Javafx 2.0 How-to Application.getParameters () em um arquivo Controller.java .
Usar injeção de dependência
O FXMLLoader suporta sistemas de injeção de dependência como Guice, Spring ou Java EE CDI, permitindo que você defina uma fábrica de controladores personalizados no FXMLLoader. Isso fornece um retorno de chamada que você pode usar para criar a instância do controlador com valores dependentes injetados pelo respectivo sistema de injeção de dependência.
Um exemplo de injeção de dependência de aplicativo e controlador JavaFX com Spring é fornecido na resposta para:
Uma abordagem realmente agradável e limpa de injeção de dependência é exemplificada pela estrutura afterburner.fx com um exemplo de aplicativo de air-hacks que a utiliza. O afterburner.fx depende do JEE6 javax.inject para executar a injeção de dependência.
Use um barramento de eventos
Greg Brown, o criador e implementador original da especificação FXML, geralmente sugere considerar o uso de um barramento de eventos, como o Guava EventBus , para comunicação entre controladores instanciados FXML e outra lógica de aplicativo.
O EventBus é uma API de publicação / assinatura simples, porém poderosa, com anotações que permite que os POJOs se comuniquem entre si em qualquer lugar da JVM sem precisar se referir.
Perguntas e Respostas de acompanhamento
No primeiro método, por que você retorna o Stage? O método também pode ser nulo porque você já está dando o comando show (); pouco antes do estágio de retorno; Como você planeja o uso retornando o Stage
É uma solução funcional para um problema. Um estágio é retornado da showCustomerDialog
função para que uma referência a ele possa ser armazenada por uma classe externa que deseje fazer algo, como ocultar o estágio com base em um clique no botão na janela principal, posteriormente. Uma solução alternativa orientada a objeto pode encapsular a funcionalidade e a referência de estágio dentro de um objeto CustomerDialog ou fazer com que um CustomerDialog estenda o Stage. Um exemplo completo de uma interface orientada a objetos para uma caixa de diálogo personalizada que encapsula dados de FXML, controlador e modelo está além do escopo desta resposta, mas pode fazer uma publicação interessante no blog para qualquer pessoa que queira criar uma.
Informações adicionais fornecidas pelo usuário StackOverflow chamado @dzim
Exemplo de injeção de dependência de inicialização de primavera
A questão de como fazê-lo "The Spring Boot Way", houve uma discussão sobre JavaFX 2, que eu respondi no link permanente em anexo. A abordagem ainda é válida e testada em março de 2016, no Spring Boot v1.3.3.RELEASE:
https://stackoverflow.com/a/36310391/1281217
Às vezes, convém passar os resultados de volta para o chamador, nesse caso, você pode conferir a resposta para a pergunta relacionada: