【问题标题】:Fxml needs to get same controller as fxml that it is inFxml 需要获得与它所在的 fxml 相同的控制器
【发布时间】:2019-02-15 07:25:56
【问题描述】:

我有一个用 fxml 编写的边框窗格,它的左侧和中间窗格的布局可以互换。

边框 fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane fx:id="mainBorderPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Program.gui.MainSceneController">
   <left>
      <ScrollPane fitToWidth="true" BorderPane.alignment="CENTER">
         <content>
            <VBox id="sideMenu" spacing="10.0" styleClass="side-menu">
               <children>
                   <Button fx:id="buttonCash" contentDisplay="TOP" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonCashPress" styleClass="side-menu-button" text="Cash">
                     <cursor>
                        <Cursor fx:constant="HAND" />
                     </cursor>
                     <graphic>
                        <ImageView fitHeight="50.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true">
                           <image>
                              <Image url="@../../Libraries/Icons/pos.png" />
                           </image>
                        </ImageView>
                     </graphic></Button>
                   <Button fx:id="buttonUsers" contentDisplay="TOP" layoutX="10.0" layoutY="10.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonUsersPress" styleClass="side-menu-button" text="Users">
                     <cursor>
                        <Cursor fx:constant="HAND" />
                     </cursor>
                     <graphic>
                        <ImageView fitHeight="50.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true">
                           <image>
                              <Image url="@../../Libraries/Icons/users.png" />
                           </image>
                        </ImageView>
                     </graphic></Button>
                   <Button fx:id="buttonInventory" contentDisplay="TOP" layoutX="10.0" layoutY="35.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonInventoryPress" styleClass="side-menu-button" text="Inventory">
                     <cursor>
                        <Cursor fx:constant="HAND" />
                     </cursor>
                     <graphic>
                        <ImageView fitHeight="50.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true">
                           <image>
                              <Image url="@../../Libraries/Icons/inventory.png" />
                           </image>
                        </ImageView>
                     </graphic></Button>
                   <Button fx:id="buttonCustomers" contentDisplay="TOP" layoutX="10.0" layoutY="60.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonCustomersPress" styleClass="side-menu-button" text="customers">
                     <cursor>
                        <Cursor fx:constant="HAND" />
                     </cursor>
                     <graphic>
                        <ImageView fitHeight="50.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true">
                           <image>
                              <Image url="@../../Libraries/Icons/customers.png" />
                           </image>
                        </ImageView>
                     </graphic></Button>
                  <Button fx:id="buttonLogout" contentDisplay="TOP" layoutX="31.0" layoutY="232.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonLogoutPress" styleClass="side-menu-button" text="Log out">
                     <cursor>
                        <Cursor fx:constant="HAND" />
                     </cursor>
                     <graphic>
                        <ImageView fitHeight="50.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true">
                           <image>
                              <Image url="@../../Libraries/Icons/log_out.png" />
                           </image>
                        </ImageView>
                     </graphic>
                  </Button>
               </children>
            </VBox>
         </content>
         <BorderPane.margin>
            <Insets />
         </BorderPane.margin>
         <padding>
            <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
         </padding>
      </ScrollPane>
   </left>
   <bottom>
      <HBox BorderPane.alignment="CENTER">
         <children>
            <Label fx:id="currentUserLabel" styleClass="current-user-label" text="Current user: name here">
               <font>
                  <Font size="15.0" />
               </font>
            </Label>
            <AnchorPane HBox.hgrow="ALWAYS" />
            <Label fx:id="currentTimeLabel" layoutX="10.0" layoutY="10.0" styleClass="current-time-label" text="TIME">
               <font>
                  <Font size="15.0" />
               </font>
            </Label>
            <AnchorPane layoutX="170.0" layoutY="10.0" HBox.hgrow="ALWAYS" />
            <Label fx:id="currentDateLabel" layoutX="170.0" layoutY="10.0" styleClass="current-date-label" text="DATE">
               <font>
                  <Font size="15.0" />
               </font>
            </Label>
         </children>
         <padding>
            <Insets left="10.0" right="10.0" />
         </padding>
      </HBox>
   </bottom>
   <stylesheets>
      <URL value="@ScreenStylesheet.css" />
   </stylesheets>
</BorderPane>

在 fxml 文件中找到的一个按钮将在控制器中运行一些代码,以使用从另一个 fxml 文件加载的 VBox 更改边框的右侧。

现在要问的是如何告诉右窗格的 fxml 使用与主边框窗格相同的控制器?也就是说我想继承控制器。

如果我在其 fxml 中使用fx:controller="Program.gui.MainSceneController" 定义控制器,它只会创建一个新实例,如果我不定义它,它只会给出错误,因为其中的按钮没有可引用的控制器。

编辑: 有人要求更改屏幕右侧的代码,它是: (注意:这是在控制器中找到的)

//mainBorderPane is gotten from the main fxml file.
FXMLLoader loader = new FXMLLoader(getClass().getResource("cashRightArea.fxml"));
            mainBorderPane.setRight(loader.load());

【问题讨论】:

  • "在控制器中运行一些代码,使用从另一个 fxml 文件加载的 VBox 更改边框的右侧" 你能用这段代码更新你的问题吗?
  • @bakcsa83 完成!
  • 请提供一个minimal reproducible example 来说明问题。

标签: java javafx fxml


【解决方案1】:

如果您想将特定控制器分配给视图,您可以这样做:

Main.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane minHeight="400.0" minWidth="400.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
   <children>
      <Label fx:id="myLabel" layoutX="28.0" layoutY="53.0" text="Label" />
      <Accordion layoutX="42.0" layoutY="158.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
      <AnchorPane fx:id="childContainer" layoutX="56.0" layoutY="177.0" maxHeight="200.0" minHeight="200.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
      <Button fx:id="loadChild" layoutX="135.0" layoutY="43.0" mnemonicParsing="false" text="Load child panel" />
   </children>
</AnchorPane>

MainController.java:

public class MainController implements Initializable{
    @FXML
    protected Label     myLabel;

    @FXML
    private Button loadChild;

    @FXML
    private AnchorPane  childContainer;

    @FXML
    protected Button    updateButton;

    StringProperty myStringProp=new SimpleStringProperty();


    private void loadChildpanel() {
        System.out.println(this.hashCode());
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Child.fxml"));
        Node childNode;
        try {
            loader.setController(this);
            childNode = (Node) loader.load();
            childContainer.getChildren().add(childNode);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    private void updateLabel() {
        myStringProp.setValue("updated text");
        System.out.println(this.hashCode());
    }


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        myStringProp.set("Initial text");
        loadChild.setOnAction(e->loadChildpanel());
        myLabel.textProperty().bind(myStringProp);

        if(updateButton!=null)updateButton.setOnAction(e->updateLabel());
    }

}

Child.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="100.0" prefWidth="180.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
   <children>
      <Button fx:id="updateButton" layoutX="10.0" layoutY="18.0" mnemonicParsing="false" prefHeight="65.0" prefWidth="161.0" text="Update" />
   </children>
</AnchorPane>

确保您没有在 Child.fxml 文件中指定控制器。 此方案有效,子视图中的按钮可以更新主视图上的标签。

但是,这是一个讨厌的解决方案,对不同的视图使用相同的控制器并不是一个好习惯。拥有视图控制器对更干净。当您需要显示另一个视图时,您可以从父控制器执行以下操作:

FXMLLoader loader = new 
FXMLLoader(getClass().getResource(InterfaceToNetworkController.UI_PATH));
Node rootNode = (Parent) loader.load();
InterfaceToNetworkController childController = loader.getController();
mainBorderPane.setRight(rootNode);

希望对你有帮助

【讨论】:

  • 数字1的问题是在fxml文件已经在FXMLLoader之后设置控制器会直接在fxml文件中导致OnAction()语句出错,我不想直接设置在代码中button1.setOnAction();button2.setOnAction()... 同样对于第二个,主控制器实际上被拆分为每个视图的内部类,我将它们保留在一个类中,因为它们需要使用所有相同的变量
  • “直接在 fxml 文件中使用 OnAction() 语句”我也不这样做。在 FXML 文件中,我只是将 UI 放在一起,仅此而已。我从不在那里定义功能,我将功能分配给控制器中的按钮,因为所有其他 UI 元素访问或操作也将在那里实现。我知道使用 SceneBuilder 将功能分配给按钮更容易,但从长远来看,它只会引起头痛,就像现在一样。
  • 那么解决这个问题的唯一方法就是手动设置按钮动作一个一个?
  • @wayne1512 使用setController 并不能阻止onAction="#..." 之类的问题得到解决。除了您负责创建和设置控制器实例而不是 FXMLLoader 之外,所有功能都完全相同。
  • 好吧,我想最好的选择是设置不同的控制器。
猜你喜欢
  • 2014-11-07
  • 2014-02-25
  • 2015-05-29
  • 1970-01-01
  • 2013-07-22
  • 2013-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多