尽管使用了fx:ids

时间:2018-05-01 13:18:46

标签: java javafx javafx-8

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

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

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

这是Controller.java代码:

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

这是DialogController.java代码:

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

以下是sample.fxml代码:

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

以下是newDialog.fxml代码:

<?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 :(得分:0)

@FXML注释表示一个字段,应该由FXMLLoader初始化,以便在加载FXML文件时引用与FXML文件中的元素相对应创建的对象。因此:

  1. 如果字段@FXML与FXML文件中的元素相对应,则只注释它们是有意义的
  2. 从不有意义初始化字段如果注释@FXML(因为FXMLLoader应该初始化它)
  3. 您的DialogController字段

    @FXML
    private DialogController controller = new DialogController();
    

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

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

    使用

    创建的对象
    @FXML private DialogController controller = new DialogController();
    

    不是任何加载newDialog.fxml时加载的UI的控制器;它只是同一类的另一个对象。目前尚不清楚您是否希望此字段以某种方式引用用户第一次从菜单中选择"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;
            }
        }
    
    }