如何使用不同的fxml文件创建多个javafx控制器?

时间:2013-10-13 05:38:16

标签: java controller javafx-2 javafx fxml

我一直在查看一些博客和其他stackoverflow问题,我没有看到我的问题的直接答案。我正在创建一个javafx gui客户端,我希望我的菜单栏是一个fxml中的一个控制器,然后我希望内容区域是附加的fxml文件。登录屏幕将是一个fxml,登录屏幕将是应用程序的主要内容,并将在一个fxml中。我该怎么做呢?

我只是不想在同一个文件中拥有我的登录,菜单栏和主要内容的所有代码。这是我正在做的工作的图像:

enter image description here

4 个答案:

答案 0 :(得分:28)

使用FXML作为组件,使用自定义java类作为fx:root和FXML文件的fx:controller:http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm

为此,您需要调用自定义java类FXMLLoader的构造函数,它将加载您的FXML。 优点是改变FXML加载组件的方式。

通过FXMLLoader与嵌套控制器实现组件实例化的经典方法是:首先是FXML,然后是每个部件的控制器。

使用这种技术,首先是:控制器,然后是每个组件的FXML。并且您不会直接在FXML中加载FXML,您将在FXML中导入自定义Java类。

这是一个更好的抽象(无需知道在FXML中导入组件时如何实现组件)并帮助重用代码,就像实现具有FXML支持的自定义窗口小部件一样。要使组件可重用,请确保您的实现没有与其他部分紧密耦合,或使用IOC这样做(例如,使用Spring与JavaFX集成)。这样,您就可以在应用程序的任何部分导入组件(就像DateInput小部件一样)而不用担心,您也不会重复代码。

在您的情况下,您将拥有:

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);
    }
}

您将在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和profiles.fxml只包含基本组件。

答案 1 :(得分:5)

  1. 你可以在另一个范围内include FXML documents - 这可以帮助你分离设计逻辑

  2. 这意味着您可以拥有Nested Controllers - 每个文档一个。

  3. 从文档中,您现在可以设置代码,以便逻辑可以分离,也可以从根控制器调用(如果需要)。

    希望有所帮助。

答案 2 :(得分:1)

我需要一个具有类似要求的弹出窗口(对节点和布​​局的更多控制)。

在完成建议之后,我找到了一个可能有用的解决方案。

首先,我创建了第二个fxml文档和第二个控制器(在NetBeans中,New - &gt; Empty FXML ... - &gt; Use Java Controller - &gt; Create New ...)。

有一点挑战在于弄清楚如何在主控制器中构建舞台并将其连接到弹出控制器。

链接Passing Parameters JavaFX FXML提供了一些真正有用的见解和技巧。

最终代码看起来像这样(我希望它可以帮助某人):

// 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();        
}

答案 3 :(得分:0)

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
           } 
               }