/ / Javafx - A classe do aplicativo pode ser a classe do controlador - javafx, fxml

Javafx - A classe do aplicativo pode ser a classe do controlador - javafx, fxml

Atualmente estou ensinando a mim mesmo o JavaFX epeguei um programa de exemplo simples que codificou a visão e a transformei em uma que usa FXML (principalmente para que eu possa usar o SceneBuilder para construir interfaces de usuário). Em vez de escrever uma classe de controlador separada, estou usando a classe de aplicativo "s 1 arquivo Java e 1 arquivo FXML). Eu não estou usando um initialize() método como é um fluxo linear (exibir a interface do usuário,preencha os campos, aguarde a entrada). A exibição aparece, mas o aplicativo erra quando nenhum dos controles é mapeado para as variáveis ​​apropriadas (assim, para @FXML TableView<...> table, table é null).

No entanto, eu coloquei em um initialize() método de depuração, os controles são injetados durante a initialize()e, em seguida, retornar para null quando initialize() sai.

Então a questão é: o JavaFX instancia um novoinstância da classe de aplicativo como uma classe de controlador separada? Isso explicaria porque as variáveis ​​estão saindo do escopo. Ou é outra coisa (por exemplo, os controles são injetados apenas quando são chamados de volta das ações do JavaFX)?

Respostas:

7 para resposta № 1

O comportamento padrão do FXMLLoader é criar uma nova instância da classe do controlador e usar essa instância como o controlador.

Especificamente, o FXMLLoader faz algo como:

  • Leia o elemento FXML raiz.
    • Se o elemento FXML raiz tiver um fx:controller atributo, então
      • Se um controlador já existir, lance uma exceção, caso contrário, crie uma instância da classe especificada1 e definir isso como o controlador
  • Continue analisando o arquivo FXML. Se os elementos tiverem um fx:id atributo, e um controlador existe (por qualquer mecanismo), injetar esses campos no controlador. Da mesma forma, registre os manipuladores de eventos como chamadas para métodos na instância do controlador.
  • Invocar initialize() no controlador, se existir um controlador e ele tiver esse método.

Então, a pergunta que você fez:

A classe de aplicativo pode ser a classe do controlador

Sim, mas provavelmente é uma idéia terrível. Se você simplesmente especificar o Application subclasse como a classe do controlador usando fx:controller, então uma segunda instância do Application subclasse é criada, @FXMLcampos anotados são injetados nessa segunda instância, e os initialize() método é invocado nessa segunda instância. Obviamente, o @FXML-fields nunca são inicializados na instância em que start(...) é invocado e o initialize() método nunca é invocado nessa instância.

A pergunta que você provavelmente quis dizer é:

A instância da classe de aplicativo criada na inicialização pode ser usada como o controlador?

A resposta para isso também é sim, e, além de programas de demonstração muito pequenos que você pretende descartar imediatamente, também é uma idéia muito ruim. Você faria isso

public class MyApp extends Application {

@FXML
private Node someNode ;

public void initialize() {
// do something with someNode
}

@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml"));
loader.setController(this);
Parent root = loader.load();
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}

Note que para usar este código, seu arquivo FXML Não deve tenha um fx:controller atributo.

O problema é que você não tem separação nem flexibilidade. (Por exemplo, se você criar uma segunda instância da exibição definida em seu arquivo FXML em algum lugar, acabará com uma segunda Application subclasse, que é no melhor dos casos contra-intuitivo (uma aplicação com dois Application instâncias ...).)

Então eu defendo o uso de uma classe separada para o controlador em basicamente todos os casos. o Application subclasse deve conter código mínimo e deve ser usado apenas para iniciar o aplicativo.

1 Este passo é na verdade um pouco mais complexo. Se uma classe é especificada no fx:controller atributo, e nenhum controlador já existe, o FXMLLoader verifica por um controllerFactory. Se existir um, o controlador é definido como o resultado da passagem do Class ao controllerFactory"s call() método, caso contrário, é criado chamando newInstance() na classe especificada (chamando efetivamente seu construtor sem argumento).


0 para resposta № 2

Se você definiu sua classe de aplicativo comoo controlador no arquivo FXML, o JavaFX, se bem me lembro, cria uma nova instância de sua classe de aplicativo e usa a nova instância como um controlador. Assim, sua classe de aplicativo existente ainda tem nulo para a tabela.

No entanto, você pode definir o controlador programaticamente em sua classe de aplicativo para usar sua própria instância:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("example.fxml"));
fxmlLoader.setController(this);
Parent root = (Parent)fxmlLoader.load();