I'm trying to open multiple windows with JavaFX, I have an eventlistener that opens a new window when a button is clicked it looks like this:
@FXML
private void joinAction() {
Parent root;
try {
Stage stage = (Stage) joinButton.getScene().getWindow();
stage.close();
root = FXMLLoader.load(getClass().getResource("main.fxml"));
stage = new Stage();
stage.setTitle("TuneUs");
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) {e.printStackTrace();}
}
the first window opens and the new one opens, but my problem is getting events to work with my second window
in main.fxml I have this line:
Then in my controller class I have this method:
@FXML
private void sendChat() {
System.out.println("test");
}
but Intellij is telling me that; no controller specified for top level element
So, my question is: Do I need to create multiple controller classes or can I use just one for multiple windows if so how?
解决方案
The recommended approach is to define a controller for each FXML. Since controllers are very lightweight this shouldn't add much overhead. The controller for your main.fxml file might be as simple as
import javafx.fxml.FXML ;
public class MainController {
@FXML
private void sendChat() {
// ...
}
}
I have used this approach with fairly large numbers of FXML files and corresponding controllers in a single project, and have had no issues with managing the code etc. I recommend using a naming convention of the form Main.fxml MainController.
If your controllers need to share data, use the techniques outlined in Passing Parameters JavaFX FXML
As @Vertex points out in the comments, there is an alternative approach provided by the FXMLLoader.setController(...) method. So in your example above, you could do
@FXML
private void joinAction() {
Parent root;
try {
Stage stage = (Stage) joinButton.getScene().getWindow();
stage.close();
FXMLLoader loader = new FXMLLoader (getClass().getResource("main.fxml"));
loader.setController(this);
root = loader.load();
stage = new Stage();
stage.setTitle("TuneUs");
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) {e.printStackTrace();}
}
@FXML
private void sendChat() {
// ...
}
This approach is fine if you are not setting any fields (controls) via FXML injection (i.e. with an fx:id attribute in the fxml and a corresponding @FXML annotation in the controller). If you are, it will be very difficult to keep track of when those fields have been set. Moreover, if your joinAction handler is invoked multiple times, you will have multiple instances of the node created by main.fxml, but all sharing a single controller instance (and consequently overwriting the same injected fields). Also note that with this approach, your initialize() method will be invoked both when the original fxml file is loaded, and when the main.fxml file is loaded, which will almost certainly cause undesired effects.
One last note: if you have many FXML files, and corresponding controllers, you might want to look at the afterburner.fx framework. This is a very lightweight framework that mandates a naming convention on FXML files and their corresponding controllers, and also provides a (very) easy mechanism for sharing data between them.
本文围绕JavaFX打开多个窗口展开,作者在实现多窗口时遇到第二个窗口事件处理问题,如Intellij提示顶级元素未指定控制器。文中给出解决方案,推荐为每个FXML定义控制器,也介绍了FXMLLoader.setController(...)方法,还提及可使用afterburner.fx框架管理大量FXML文件和控制器。
4183

被折叠的 条评论
为什么被折叠?



