如何使用不同的 fxml 文件创建多个 javafx 控制器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19342259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create multiple javafx controllers with different fxml files?
提问by j will
I've been looking at some blogs and other stackoverflow questions, and I'm not seeing a direct answer to my question. I am creating a javafx gui client and I want to have my menubar be one controller in one fxml and then i want the content area to be additional fxml files. The login screen will be one fxml, after the login screen will be the main content of the application and that will be in one fxml. How do i go about doing this?
我一直在查看一些博客和其他 stackoverflow 问题,但没有看到我的问题的直接答案。我正在创建一个 javafx gui 客户端,我想让我的菜单栏成为一个 fxml 中的一个控制器,然后我想让内容区域成为额外的 fxml 文件。登录屏幕将是一个 fxml,在登录屏幕之后将是应用程序的主要内容,这将在一个 fxml 中。我该怎么做?
I just don't want to have all of my code for my login, menubar, and main content in the same file. This is an image of what i am working on:
我只是不想将我的登录、菜单栏和主要内容的所有代码都放在同一个文件中。这是我正在处理的图像:
采纳答案by zenbeni
Use FXML as components by using a custom java class as fx:root and as fx:controller of your FXML file: http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm
通过将自定义 Java 类用作 FXML 文件的 fx:root 和 fx:controller,将 FXML 用作组件:http: //docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm
To do so, you need to call in the constructor of your custom java class FXMLLoader which will load your FXML. The advantage is to change the way FXML load components.
为此,您需要调用自定义 Java 类 FXMLLoader 的构造函数,它将加载您的 FXML。好处是改变了 FXML 加载组件的方式。
The classic way to instanciate components via FXMLLoader with nested controllers is: FXML first, then controller for each part.
通过带有嵌套控制器的 FXMLLoader 实例化组件的经典方法是:首先 FXML,然后是每个部分的控制器。
With this technique this is: controller first, then FXML for each component. And you won't load FXML in FXML directly, you will import your custom java classes in the FXML.
使用这种技术是:首先是控制器,然后是每个组件的 FXML。并且您不会直接在 FXML 中加载 FXML,您将在 FXML 中导入您的自定义 java 类。
This is a better abstraction (no need to know how a component is implemented when you import them in FXML) and helps reusing code as it is like implementing a custom widget with FXML support. To make your component reusable, make sure your implementation doesn't have tight coupling with other parts, or use IOC to do so (for instance, with Spring integration with JavaFX). This way, you will be able to import your component in any part of your application (just like a DateInput widget) without worry and you won't duplicate code.
这是一个更好的抽象(在 FXML 中导入组件时无需知道组件是如何实现的)并且有助于重用代码,因为它就像实现具有 FXML 支持的自定义小部件一样。为了使您的组件可重用,请确保您的实现与其他部分没有紧密耦合,或者使用 IOC 来做到这一点(例如,使用 Spring 与 JavaFX 的集成)。这样,您将能够在应用程序的任何部分(就像 DateInput 小部件一样)导入您的组件而无需担心,并且不会重复代码。
In your case you will have:
在您的情况下,您将拥有:
public class MenuBox extends VBox {
@FXML
private LoginBox loginBox;
@FXML
private ProfilesBox profilesBox;
public MenuBox() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("menu.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public class LoginBox extends VBox {
public LoginBox() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("login.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public class ProfilesBox extends VBox {
public ProfilesBox() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("profiles.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
And you will import LoginBox and ProfilesBox in menu.fxml that manages the global layout for your page:
您将在管理页面全局布局的 menu.fxml 中导入 LoginBox 和 ProfilesBox:
<?import com.foo.bar.LoginBox ?>
<?import com.foo.bar.ProfilesBox ?>
<fx:root type="javafx.scene.layout.VBox"
xmlns:fx="http://javafx.com/fxml">
<!-- Stuff here to declare the menu bar-->
<HBox>
<ProfilesBox fx:id="profilesBox"/>
<LoginBox fx:id="loginBox"/>
</HBox>
</fx:root>
login.fxml and profiles.fxml contain just basic components.
login.fxml 和profiles.fxml 只包含基本组件。
回答by Harsha R
You can include FXML documentsone within the other - this should help you with separating the design logic
This means you can have Nested Controllers- one for each document.
您可以在另一个中包含 FXML 文档- 这应该有助于分离设计逻辑
这意味着您可以拥有嵌套控制器- 每个文档一个。
From the documentation, you can now setup your code such that logic can be separated as well as invoked from the root controller (if need be).
从文档中,您现在可以设置代码,以便可以分离逻辑以及从根控制器调用(如果需要)。
Hope that helps.
希望有帮助。
回答by rainer
I needed a popup window with similar requirements (more control over the nodes and the layout).
我需要一个具有类似要求的弹出窗口(对节点和布局的更多控制)。
Having worked my way through the recommendations, I found a solution that might be useful.
在按照我的方式完成建议后,我找到了一个可能有用的解决方案。
First, I created a second fxml document and second controller (in NetBeans, New -> Empty FXML ... -> Use Java Controller -> Create New ...).
首先,我创建了第二个 fxml 文档和第二个控制器(在 NetBeans 中,New -> Empty FXML ... -> Use Java Controller -> Create New ...)。
A little challenging was to figure out how to build the stage in the main controller and connect it to the popup controller.
一个小小的挑战是弄清楚如何在主控制器中构建舞台并将其连接到弹出控制器。
The link Passing Parameters JavaFX FXMLgives some real good insights and techniques.
链接传递参数 JavaFX FXML提供了一些非常好的见解和技术。
The final code looks like this (I hope it can help someone):
最终代码如下所示(我希望它可以帮助某人):
// Anchor Pane from the popup
@FXML
AnchorPane anchorPanePopup;
@FXML
private void soneButtonAction(ActionEvent event) throws IOException {
Stage newStage = new Stage();
AnchorPane anchorPanePopup = (AnchorPane) FXMLLoader.load(getClass().getResource("Popup_FXML.fxml"));
Scene scene = new Scene(anchorPanePopup);
newStage.setScene(scene);
newStage.initModality(Modality.APPLICATION_MODAL);
newStage.setTitle("Dialog Window");
newStage.showAndWait();
}
回答by Laxmi
package javafxapplication11;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.stage.Stage;
public class FXMLDocumentController implements Initializable {
@FXML
private CheckBox c1;
@FXML
private CheckBox c2;
public void clicked1(ActionEvent e) throws IOException {
Parent home_page_parent
=FXMLLoader.load(getClass().getResource("AddDcuFXML.fxml"));
Scene home_page_scene = new Scene(home_page_parent);
Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
app_stage.hide(); //optional
app_stage.setScene(home_page_scene);
app_stage.show();
}
public void clicked2(ActionEvent e) throws IOException {
Parent home_page_parent
=FXMLLoader.load(getClass().getResource("ViewDCU.fxml"));
Scene home_page_scene = new Scene(home_page_parent);
Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
app_stage.hide(); //optional
app_stage.setScene(home_page_scene);
app_stage.show();
}
public void clicked3(ActionEvent e) throws IOException {
Parent home_page_parent
=FXMLLoader.load(getClass().getResource("ViewDCU.fxml"));
Scene home_page_scene = new Scene(home_page_parent);
Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
app_stage.hide(); //optional
app_stage.setScene(home_page_scene);
app_stage.show();
}
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
}
}