在主 fxml 文件中包含嵌套控制器的位置

问题描述 投票:0回答:1

我不确定我应该把我的

<fx:include fx:id="NTB" source="NTB.fxml" />
放在我的主.fxml文件中的什么地方。我将在底部包含相关文件。

文件结构:

  • 驱动类:Test.java
  • 驱动程序的
  • fxml:Test.fxml
  • 驱动程序 fxml 的控制器:Controller.java
  • fxml 用于辅助窗口:NTB.fxml
  • 辅助窗口控制器:NTB.java

Test.java 显示一个 TableView 以及一个包含一些按钮的工具栏。单击 newTask 按钮时,我试图让它从 NTB.java 调用

display()
方法,这将显示一个新窗口,该窗口接受用户的一些输入并将其存储在该类可见的列表中。一旦用户单击新窗口中的完成按钮,窗口将关闭并更新表格内容。

目前这些文件是如何设置的,程序将编译和运行,当单击 newTask 按钮时,它会产生错误但不会崩溃,这是预期的,因为 NTBController 默认情况下为空,因为

<fx:include />
标签不存在还没有。

我遇到的主要问题是,到目前为止,无论我将

<fx:include />
标记放在 Test.fxml 中的什么位置,该程序都不会启动 产生一个错误,该错误指向测试中包含标记所在的行.fxml,NTB.fxml中BorderPane定义的最后一行,Test.java中的loadFXML&start函数

相关文件:

测试.fxml:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>


<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" fx:controller="com.test.Controller" xmlns="http://javafx.com/javafx/13" xmlns:fx="http://javafx.com/fxml/1">
   <fx:include fx:id="nTB" source="NTB.fxml" />
   <center>
      <TableView fx:id="table" prefHeight="352.0" prefWidth="543.0">
        <columns>
          <TableColumn fx:id="orderCol" prefWidth="75.0" text="Order" />
          <TableColumn fx:id="nameCol" prefWidth="75.0" text="Name" />
            <TableColumn fx:id="xCol" prefWidth="75.0" text="X" />
            <TableColumn fx:id="yCol" prefWidth="75.0" text="Y" />
            <TableColumn fx:id="buttonCol" prefWidth="75.0" text="Button" />
            <TableColumn fx:id="keyCol" prefWidth="75.0" text="Key Code" />
            <TableColumn fx:id="descriptionCol" prefWidth="75.0" text="Description" />
            <TableColumn fx:id="delayCol" prefWidth="75.0" text="Delay" />
        </columns>
         <columnResizePolicy>
            <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
         </columnResizePolicy>
      </TableView>
   </center>
   <top>
      <HBox alignment="CENTER" prefHeight="34.0" prefWidth="600.0">
         <children>
            <Button fx:id="newTask" mnemonicParsing="false" onAction="#newTaskDisplay" text="New"  />
            <Button fx:id="editTask" mnemonicParsing="false" onAction="#editTasksOnA" text="Edit" />
            <Button fx:id="deleteTask" mnemonicParsing="false" onAction="#deleteTasksOnA" text="Delete" />
            <Button fx:id="runTasks" mnemonicParsing="false" onAction="#runTasksOnA" text="Run" />
            <Label fx:id="numRunsLab" text="Iterations:" />
            <TextField fx:id="numRuns" prefHeight="39.0" prefWidth="90.0" promptText="1" />
            <Button fx:id="clearTasks" mnemonicParsing="false" onAction="#clearTasksOnA" text="Clear Tasks" />
            <Button fx:id="saveTasks" mnemonicParsing="false" onAction="#saveTasksOnA" text="Save" />
            <Button fx:id="openTasks" mnemonicParsing="false" onAction="#openTasksOnA" text="Open" />
         </children>
      </HBox>
   </top>
   <right>
      <VBox alignment="CENTER" prefHeight="945.0" prefWidth="89.0">
         <children>
            <Button fx:id="moveToTop" mnemonicParsing="false" text="Move Top" />
            <Button fx:id="moveUp" mnemonicParsing="false" text="Move Up" />
            <Button fx:id="moveDown" mnemonicParsing="false" text="Move Down" />
            <Button fx:id="moveToBottom" mnemonicParsing="false" text="Move Bottom" />
         </children>
      </VBox>
   </right>
</BorderPane>

NTB.fxml:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.stage.Stage?>

<Stage fx:id="window" fx:controller="com.test.NTB" xmlns="http://javafx.com/javafx/13" xmlns:fx="http://javafx.com/fxml/1" >
    <BorderPane >
        <center>
            <VBox alignment="CENTER">
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="nameLabel" text="Name: " />
                        </children>
                    </VBox>
                    <VBox alignment ="CENTER">
                        <children>
                            <TextField fx:id="nameField" promptText="Name..." />
                        </children>
                    </VBox>
                </HBox>
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="xLabel" text="X Coord: " />
                        </children>
                    </VBox>
                    <VBox>
                        <children>
                            <TextField fx:id="xField" promptText="0.0" />
                        </children>
                    </VBox>
                </HBox>
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="yLabel" text="Y Coord: " />
                        </children>
                    </VBox>
                    <VBox>
                        <children>
                            <TextField fx:id="yField" promptText="0.0" />
                        </children>
                    </VBox>
                </HBox>
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="buttonLabel" text="Button: " />
                        </children>
                    </VBox>
                    <VBox>
                        <children>
                            <ChoiceBox fx:id="buttonBox" value="MouseButton.PRIMARY" />
                        </children>
                    </VBox>
                </HBox>
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="keyLabel" text="Key: " />
                        </children>
                    </VBox>
                    <VBox>
                        <children>
                            <TextField fx:id="keyField" maxWidth="25.0" promptText="A" />
                        </children>
                    </VBox>
                </HBox>
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="descriptionLabel" text="Description: " />
                        </children>
                    </VBox>
                    <VBox>
                        <children>
                            <TextArea fx:id="descriptionArea" promptText="Enter description..." maxWidth="150" maxHeight="100" />
                        </children>
                    </VBox>
                </HBox>
                <HBox alignment="CENTER">
                    <padding>
                        <Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
                    </padding>
                    <VBox alignment="CENTER">
                        <children>
                            <Label fx:id="delayLabel" text="Delay: " />
                        </children>
                    </VBox>
                    <VBox>
                        <children>
                            <TextField fx:id="delayField" promptText="0" />
                        </children>
                    </VBox>
                </HBox>
            </VBox>
        </center>
        <bottom>
            <HBox alignment="CENTER">
                <Button fx:id="doneButton" onAction="#doneButtonOnA" text="Done" />
                <Button fx:id="cancelButton" onAction="#cancelButtonOnA" text="Cancel" />
            </HBox>
        </bottom>
    </BorderPane>
</Stage>

Controller.java:

package com.test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Scanner;

import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.stage.FileChooser;
import javafx.stage.Window;

public class Controller extends Test implements Initializable
{
    @FXML private TableView<Task> table;
    @FXML private TableColumn<Task, Integer> orderCol;
    @FXML private TableColumn<Task, String> nameCol;
    @FXML private TableColumn<Task, Double> xCol;
    @FXML private TableColumn<Task, Double> yCol;
    @FXML private TableColumn<Task, MouseButton> buttonCol;
    @FXML private TableColumn<Task, String> keyCol;
    @FXML private TableColumn<Task, String> descriptionCol;
    @FXML private TableColumn<Task, Long> delayCol;
    @FXML private TextField numRuns;
    @FXML private Window nTB;
    @FXML private NTB nTBController;
    
    @Override
    public void initialize(URL url, ResourceBundle resources)
    {   
        numRuns.textProperty().addListener((observable, oldValue, newValue) -> {
            if(newValue.matches("\\d*")) return;
            numRuns.setText(newValue.replaceAll("[^\\d]", ""));
        });
        orderCol.setCellValueFactory(column-> new ReadOnlyObjectWrapper<Integer>(table.getItems().indexOf(column.getValue()) + 1));
        nameCol.setCellValueFactory(new PropertyValueFactory<Task, String>("name"));
        xCol.setCellValueFactory(new PropertyValueFactory<Task, Double>("x"));
        yCol.setCellValueFactory(new PropertyValueFactory<Task, Double>("y"));
        buttonCol.setCellValueFactory(new PropertyValueFactory<Task, MouseButton>("button"));
        keyCol.setCellValueFactory(new PropertyValueFactory<Task, String>("keyCode"));
        descriptionCol.setCellValueFactory((new PropertyValueFactory<Task, String>("description")));
        delayCol.setCellValueFactory(new PropertyValueFactory<Task, Long>("delay"));

        table.getItems().setAll(list);
    }

    @FXML private void newTaskDisplay()
    {
        nTBController.display();
        table.getItems().setAll(list);
    }

测试.java:

package com.test;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class Test extends Application {

    private static Scene scene;
    protected static Stage stage;

    protected static ObservableList<Task> list = FXCollections.observableArrayList();

    @Override
    public void start(Stage primStage) throws IOException {
        stage = primStage;
        scene = new Scene(loadFXML("Test"), 640, 480);
        scene.getStylesheets().add(getClass().getResource("Test.css").toExternalForm());

        stage.setScene(scene);
        stage.show();
    }

    static void setRoot(String fxml) throws IOException {
        scene.setRoot(loadFXML(fxml));
    }

    private static Parent loadFXML(String fxml) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(Test.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

    public static void main(String[] args) {
        launch();
    }

}

运行错误:

Exception in Application start method
java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)   
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1081)
Caused by: java.lang.RuntimeException: Exception in Application start method
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)     
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javafx.fxml.LoadException: Element does not define a default property.
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/NTB.fxml:133
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/Test.fxml:15

        at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2621)
        at javafx.fxml/javafx.fxml.FXMLLoader$Element.set(FXMLLoader.java:187)
        at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:798)
        at javafx.fxml/javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2838)
        at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2557)
        at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
        at javafx.fxml/javafx.fxml.FXMLLoader$IncludeElement.constructValue(FXMLLoader.java:1154)
        at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:754)
        at javafx.fxml/javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
        at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
        at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
        at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
        at com.test/com.test.Test.loadFXML(Test.java:36)
        at com.test/com.test.Test.start(Test.java:23)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)    
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
        ... 1 more
Exception running application com.test.Test

要包含在 Test.fxml 中的标签:

<fx:include fx:id="NTB" source="NTB.fxml" />

如果有任何其他信息对此有帮助,请询问,我很乐意提供。

我也不会死心塌地地让这成为这个程序的最终结构,所以如果这做起来不必要地困难,并且有更简单的方法来完成同样的事情,请告诉我。我是将 fxml 与 JavaFX 结合使用的新手,所以我还不确定最好的方法。

javafx fxml
1个回答
0
投票

这里是错误:

Caused by: javafx.fxml.LoadException: Element does not define a default property.
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/NTB.fxml:133
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/Test.fxml:15

此错误(具体而言)与

fx:include
元素的位置无关。问题是
NTB.fxml
文件中的元素没有定义 default 属性。它说错误发生在 FXML 文件的
133
行。该行是结束
</BorderPane>
标签。这是有道理的,因为父元素定义了一个
Stage
,它确实没有定义默认属性。

当你遇到这样的事情时:

<VBox>
    <Label/>
</VBox>

这将

Label
放入
VBox
的子列表中。之所以可行,是因为
Pane
被注释为
@DefaultProperty("children")
那个注释
@Inherited
,所以
VBox
有相同的注释。因此,直接位于
<VBox>
元素内的元素将应用于
children
属性。如果该注释不存在,那么您需要执行以下操作:

<VBox>
    <children>
        <Label/>
    </children>
</VBox>

Stage
类没有
@DefaultProperty
注释。它的任何超类也没有。这意味着您不能直接将元素放置在
<Stage>
元素内。您必须告诉 FXML 您要设置哪个属性。

这会导致另一个问题。您不能将

BorderPane
放在
Stage
中。您需要先将其包装为
Scene
的根。像这样的东西:

<Stage>
    <scene>
        <Scene width="-1" height="-1">
            <!-- The Scene class is annotated with DefaultProperty("root") -->
            <BorderPane>
                <!-- your stuff -->
            </BorderPane>
        </Scene>
    </scene>
</Stage>

不幸的是,这导致了另一个问题。您正在尝试将

NBT.fxml
嵌入到另一个 FXML 文件中。您不能将
Stage
放在另一个
Stage
中(更不用说另一个
Node
了)。您要么需要重新考虑您的设计,要么需要将
NBT.fxml
的根元素定义为某种
Node
而不是
Stage

如果您决定在这里继续使用

fx:include
(意味着您将根元素更改为
Node
的一种),请记住
BorderPane
@DefaultProperty
继承了它的
Pane
注释。这意味着它的默认属性是
children
。不应将节点直接添加到边框窗格的子节点;那个孩子不会得到妥善管理。确保将
fx:include
元素移动到
<top>
<left>
<bottom>
<right>
<center>
元素内。

© www.soinside.com 2019 - 2024. All rights reserved.