首页 文章

尽管使用了fx:ids,FXML变量显示为null

提问于
浏览
0

我是初学者,我正在尝试构建一个简单的字典应用程序 .

我有一个控制器类,它有一个按钮来打开一个新的对话框来输入各种细节 .

该对话框由一个单独的控制器控制,这是我遇到问题的地方,我的FXML元素被赋予null值,因此当我运行代码时,我得到一个nullpointerexception . 我用@FXML注释了FXML vaiables并检查了fxml文件中的fx:id是否与java文件的fx:id相匹配 .

Here is the Controller.java code:

package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.BorderPane;
import javafx.scene.control.Dialog;

import java.io.IOException;
import java.util.Optional;

public class Controller {

@FXML
private BorderPane mainBorderPane;
@FXML
private DialogController controller = new DialogController();
@FXML
public void initialize(){

}

@FXML
public void newItemDialog(){
    Dialog <ButtonType> dialog = new Dialog<>();
    dialog.initOwner(mainBorderPane.getScene().getWindow());
    dialog.setTitle("Insert Word");
    FXMLLoader fxmlLoader = new FXMLLoader();
    fxmlLoader.setLocation(getClass().getResource("newDialog.fxml"));
    try{
        dialog.getDialogPane().setContent(fxmlLoader.load());
    }catch(IOException e) {
        e.printStackTrace();
        return;
    }
    dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
    dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
    Optional<ButtonType> result = dialog.showAndWait();
    if(result.isPresent() && result.get() == ButtonType.OK){
        boolean results = controller.processResults();

    }else{
        System.out.println("Cancelled");
        return;
    }
}
}

Here is the DialogController.java code:

package sample;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import sample.control.Data;

import java.io.IOException;
import java.util.Optional;

public class DialogController {
@FXML
private TextField nameField;
@FXML
private TextField descriptionField;
@FXML
private TextField typeField;
@FXML
private TextField sentenceField;


@FXML
public boolean processResults() {

    String name = nameField.getText();
    String description = descriptionField.getText();
    String type = typeField.getText();
    String sentence = sentenceField.getText();

    return Data.getInstance().addWord(name,type,description,sentence);
    }    
}

Here is the sample.fxml code:

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.ListView?>
<?import java.lang.String?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>
<BorderPane fx:controller="sample.Controller"
        xmlns:fx="http://javafx.com/fxml"
        fx:id ="mainBorderPane">

<top>
    <MenuBar>

        <Menu fx:id="fileButton" text="File">
            <MenuItem fx:id="newButton" onAction="#newItemDialog" text="New"/>
            <MenuItem fx:id="updateButton" text="Update"/>
            <MenuItem fx:id="deleteButton" text="Delete"/>
            <MenuItem fx:id="saveButton" text="Save"/>
        </Menu>
        <Menu fx:id="viewButton" text="View">
            <MenuItem text="Dark Mode"/>
        </Menu>
    </MenuBar>
</top>
<left>
    <ListView fx:id="wordListView" BorderPane.alignment="TOP_LEFT" prefHeight="Infinity" prefWidth="250">

    </ListView>
</left>
<center>
    <VBox>
        <TextArea fx:id = "wordDetails" prefWidth="Infinity" prefHeight="400">

        </TextArea>
        <TextArea prefWidth="Infinity" prefHeight="200">

        </TextArea>
    </VBox>
</center>

</BorderPane>

Here is the newDialog.fxml code:

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

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

<?import javafx.scene.text.Text?>
<?import javafx.scene.control.DialogPane?>
<DialogPane xmlns="http://javafx.com/javafx"
        xmlns:fx="http://javafx.com/fxml"
        fx:controller="sample.DialogController"
        prefHeight="400.0" prefWidth="600.0">
<headerText>
    Enter A Word
</headerText>
<content>
    <VBox>
        <TextField fx:id="nameField" promptText="Enter the word"/>
        <TextField fx:id="typeField" promptText="Enter the type"/>
        <TextField fx:id="descriptionField" promptText="Enter a description"/>
        <TextField fx:id="sentenceField" promptText="Enter a sentence"/>
    </VBox>
</content>

提前致谢!

1 回答

  • 0

    @FXML 注释表示当加载FXML文件时,应由 FXMLLoader 初始化的字段,以引用与FXML文件中的元素相对应创建的引用对象 . 所以:

    • 如果它们对应于FXML文件中的元素,则只注释字段 @FXML 是有意义的

    • 如果字段被注释 @FXML (因为 FXMLLoader 应该初始化它),那么 never 初始化字段是有意义的

    你的 DialogController 字段

    @FXML
    private DialogController controller = new DialogController();
    

    由于以上两个原因没有意义: sample.fxml 中没有 DialogController 元素,如果存在,则初始化字段没有意义 .

    控制器是与从FXML文件加载的UI相关联的特定对象 . 当加载FXML文件时, FXMLLoader 会 Build 关联 . 如果您多次加载FXML文件(因为您在此处执行此操作,因为您在事件处理程序中加载 newDialog.fxml ),那么(当然)每次都会获得FXML中所有元素的新实例,因此新的每次控制器类的实例 .

    您创建的对象

    @FXML private DialogController controller = new DialogController();
    

    不是任何加载的任何UI加载的控制器 newDialog.fxml ;它只是同一类的另一个对象 . 目前尚不清楚你是否希望这个字段以某种方式引用用户第一次从菜单中选择 "New" 时创建的控制器,或者第二次选择该菜单项时创建的控制器,等等 . 或者,当然,你会怎么期望它在您加载 newDialog.fxml 之前初始化时引用任何控制器 .

    加载FXML后,您将从 FXMLLoader 获得控制器 . 所以你只需要:

    public class Controller {
    
        @FXML
        private BorderPane mainBorderPane;
        @FXML
        public void initialize(){
    
        }
    
        @FXML
        public void newItemDialog(){
            Dialog <ButtonType> dialog = new Dialog<>();
            dialog.initOwner(mainBorderPane.getScene().getWindow());
            dialog.setTitle("Insert Word");
            FXMLLoader fxmlLoader = new FXMLLoader();
            fxmlLoader.setLocation(getClass().getResource("newDialog.fxml"));
            try{
                dialog.getDialogPane().setContent(fxmlLoader.load());
            }catch(IOException e) {
                e.printStackTrace();
                return;
            }
            dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
            dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
            Optional<ButtonType> result = dialog.showAndWait();
    
            DialogController controller = fxmlLoader.getController();
    
            if(result.isPresent() && result.get() == ButtonType.OK){
                boolean results = controller.processResults();
    
            }else{
                System.out.println("Cancelled");
                return;
            }
        }
    
    }
    

相关问题