尝试关闭时在自己的对话框中出现 JavaFX NullpointerException 和 FXML window
JavaFX NullpointerException with FXML in own dialogbox when trying to close window
我是 JavaFX 的新手。我编写了一个带有地址的人员列表的表格视图。一切正常。然后我想用 MVC 或更好的 MVP 设计模式编写它。
我正在使用 FXML 和 scenebuilder 来布置场景。
现在有了 MVC,我遇到了一个问题,即当我想关闭确认对话框时,我得到了一个 NUllpointerException。
而且我也无法更改 confirmdialog window 场景的标签文本。
我想我知道问题出在哪里,但不知道如何正确解决。控制器被实例化两次,因此形成 fxml 的变量的第一个值为 NUll。
这就是我编写我的小应用程序的方式:
MiniTest.java - 我的主要应用程序
package AddressBook;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MiniTest extends Application {
private static Stage window;
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Adresslist of Clients");
Model model = new Model();
try {
FXMLLoader mainViewloader = new FXMLLoader(getClass().getResource("View.fxml"));
Parent root = (Parent) mainViewloader.load();
MainController mainController = mainViewloader.<MainController>getController();
window.setScene(new Scene(root));
window.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Stage getPrimaryStage() {
return window;
}
public static void main(String[] args) {
launch(args);
}
}
Model.java - 这是我的模型,不确定内容是否必须在这里。对于下一步,我想从 mysql 数据库中收集数据并将其保存到数据库中。目前我有这样的人
package AddressBook;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Model {
public ObservableList<Person> getPerson() {
ObservableList<Person> personList = FXCollections.observableArrayList();
Address addressPerson1 = new Address("Jaguarweg 12", "23454", "Bensheim");
Address addressPerson2 = new Address("Friedrich-Ebert-Str. 134", "82635", "Berlin");
Address addressPerson3 = new Address("Adam-Opel-Str. 1", "92364", "Bamberg");
Address addressPerson4 = new Address("Power-Shell-Pfad 21", "10083", "Hamburg");
Address addressPerson5 = new Address("Schwertstr. 76", "749236", "Stuttgart");
Address addressPerson6 = new Address("Hans-Jacob-Weg 4", "66396", "Wiesbaden");
Address addressPerson7 = new Address("Georg-Lucas-Str. 110", "53421", "Wien");
Address addressPerson8 = new Address("Andalusienweg 17", "723612", "Ostfildern");
Address addressPerson9 = new Address("Mercedes-Benz-Str. 9", "883621", "Wolfsburg");
Address addressPerson10 = new Address("Heinrich-Schwein-Str. 43", "134923", "Frankfurt");
Address addressPerson11 = new Address("Engel-Teufel-Str. 66", "083273", "Hildesheim");
personList.add(new Person("Georg Sorresto", addressPerson1));
personList.add(new Person("Flynn Bozzen", addressPerson2));
personList.add(new Person("Bill Klang", addressPerson3));
personList.add(new Person("Wilhelm Busch", addressPerson4));
personList.add(new Person("Gertrud Raven", addressPerson5));
personList.add(new Person("Markus Berg", addressPerson6));
personList.add(new Person("Juergen Schmidt", addressPerson7));
personList.add(new Person("Fritz Titz", addressPerson8));
personList.add(new Person("Bodo Bambino", addressPerson9));
personList.add(new Person("Ortrun Giner", addressPerson10));
personList.add(new Person("Jakob Huber", addressPerson11));
return personList;
}
}
Person.java - 我的人 class
package AddressBook;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty name;
private Address address;
public Person() {
this.name = new SimpleStringProperty("");
this.address = new Address("", "", "");
}
public Person(String name, Address address) {
this.name = new SimpleStringProperty(name);
;
this.address = address;
}
public String getName() {
return name.get();
}
public void setName(String name2) {
name.set(name2);
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
在 MainController.java 中 - 对于某些事情,例如关闭 window 或删除一个人,我将这样的方法称为我自己的 confirmdialogwindow 并使用相应的字符串作为标签。
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
这是完整的 MainController.java - 这是 mainView 的 mainController(View.fxml)
package AddressBook;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
@FXML
private MenuItem exitMenu;
@FXML
private TableView<Person> personTable;
@FXML
private TextField zipInput;
@FXML
private TextField cityInput;
@FXML
private TextField streetInput;
@FXML
private TextField nameInput;
@FXML
private TableColumn<Person, String> cityColumn;
@FXML
private TableColumn<Person, String> zipColumn;
@FXML
private TableColumn<Person, String> streetColumn;
@FXML
private TableColumn<Person, String> nameColumn;
@FXML
private Button addButton;
@FXML
private Button deleteButton;
@FXML
private SimpleStringProperty message;
private Stage window;
private ConfirmDialogBoxController confirmDialogBoxController;
private AlertEmptyNameController alertEmptyNameController;
private Model model;
public MainController(){
model = new Model();
System.out.println("+1 MainController()");
}
public MainController(Model model){
this.model = model;
System.out.println("+1 MainController(model)");
}
@Override
public void initialize(URL location, ResourceBundle resources) {
Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory = (TableColumn<Person, String> p) -> new MainController.EditingCell();
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
nameColumn.setCellFactory(cellFactory);
nameColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setName(t.getNewValue());
}
);
streetColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getStreet()));
streetColumn.setCellFactory(cellFactory);
streetColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setStreet(t.getNewValue());
});
zipColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getZip()));
zipColumn.setCellFactory(cellFactory);
zipColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setZip(t.getNewValue());
});
cityColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getCity()));
cityColumn.setCellFactory(cellFactory);
cityColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setCity(t.getNewValue());
});
personTable.setItems(model.getPerson());
personTable.setEditable(true);
MiniTest.getPrimaryStage().setOnCloseRequest(e -> {
try {
e.consume();
closeWindow(e);
} catch (IOException ex) {
ex.printStackTrace();
}
});
}
public SimpleStringProperty getMessageProperty(){
return message;
}
public void setMessage(String message) {
this.message.setValue(message);
}
public String getMessage() {
return this.message.getValue();
}
@FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
@FXML
public void closeWindowFromMenu(ActionEvent e) throws IOException {
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
public Stage getPrimaryStage() {
return window;
}
@FXML
public void addNewPerson() throws IOException {
alertEmptyNameController = new AlertEmptyNameController();
Person person = new Person();
person.setName(nameInput.getText());
if(nameInput.getText().isEmpty()){
alertEmptyNameController.alertEmptyName();
}else{
person.getAddress().setStreet(streetInput.getText());
person.getAddress().setZip(zipInput.getText());
person.getAddress().setCity(cityInput.getText());
personTable.getItems().add(person);
}
nameInput.clear();
streetInput.clear();
zipInput.clear();
cityInput.clear();
}
@FXML
public void deletePerson() throws IOException {
boolean answer = confirmDialogBoxController.display("Deleting Entry", "Are you sure you want to delete this entry?");
if (answer) {
ObservableList<Person> personSelected, allPersons;
allPersons = personTable.getItems();
personSelected = personTable.getSelectionModel().getSelectedItems();
personSelected.forEach(allPersons::remove);
}
}
static class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.focusedProperty().addListener((ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) -> {
if (!arg2) {
commitEdit(textField.getText());
}
});
}
private String getString() {
return getItem() == null ? "" : getItem();
}
}
}
View.fxml - 这是主视图
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.MainController">
<bottom>
<HBox fx:id="bottomLayout" alignment="CENTER" style="-fx-background-color: #292929;" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<children>
<TextField fx:id="nameInput" promptText="Name" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="8.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="streetInput" layoutX="15.0" layoutY="15.0" promptText="Street" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="zipInput" layoutX="163.0" layoutY="15.0" promptText="Zip" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="cityInput" layoutX="312.0" layoutY="15.0" promptText="City" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<Button fx:id="addButton" mnemonicParsing="false" onAction="#addNewPerson" style="-fx-background-color: #5ebcff; -fx-background-radius: 0; -fx-text-fill: white;" text="Add">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</Button>
<Button fx:id="deleteButton" layoutX="474.0" layoutY="15.0" mnemonicParsing="false" onAction="#deletePerson" style="-fx-background-radius: 0; -fx-background-color: #5ebcff; -fx-text-fill: white;" text="Delete">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="8.0" top="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
<center>
<TableView fx:id="personTable" editable="true" style="-fx-background-color: #5e5e5e;" stylesheets="@MyStyle.css" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="nameColumn" prefWidth="152.0" text="Name" />
<TableColumn fx:id="streetColumn" prefWidth="196.0" text="Street" />
<TableColumn fx:id="zipColumn" prefWidth="88.0" text="Zip" />
<TableColumn fx:id="cityColumn" prefWidth="163.0" text="City" />
</columns>
</TableView>
</center>
<top>
<HBox fx:id="menuLayout" style="-fx-background-color: #292929;" stylesheets="@MyStyle.css" BorderPane.alignment="CENTER">
<children>
<MenuBar fx:id="menuBar" stylesheets="@MyStyle.css">
<menus>
<Menu fx:id="fileMenu" mnemonicParsing="false" text="File">
<items>
<MenuItem fx:id="exitMenu" mnemonicParsing="false" onAction="#closeWindowFromMenu" text="Exit" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</HBox>
</top>
</BorderPane>
ConfirmDialogBoxController.java - 这是确认对话框的控制器,用于使用 "X" 或在菜单文件->退出中关闭 window 并询问用户是否真的想删除表视图中的条目
package AddressBook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class ConfirmDialogBoxController implements Initializable {
private static Boolean answer;
@FXML
private Button yesButton;
@FXML
private Button noButton;
@FXML
private Label confirmLabel;
@FXML
private Stage stage;
@FXML
private Model model;
public ConfirmDialogBoxController(){
System.out.println("+1 ConfirmDialogBoxController() object instantiated");
}
public ConfirmDialogBoxController(Model model){
this.model = model;
System.out.println("+1 ConfirmDialogBoxController(model) object instantiated");
}
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.confirmLabel.setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
public Label getLabel(){
return confirmLabel;
}
@FXML
public boolean yesButtonClicked(ActionEvent actionEvent) {
answer = true;
stage = (Stage) yesButton.getScene().getWindow();
stage.close();
return answer;
}
@FXML
public boolean noButtonClicked(ActionEvent actionEvent) {
answer = false;
Stage confirmWindow = (Stage) noButton.getScene().getWindow();
confirmWindow.close();
return answer;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
// confirmLabel.textProperty().bindBidirectional(messageProperty);
// System.out.println("messageProperty.getValue(): "+ messageProperty.getValue());
// System.out.println("DEBUG: message is = " + messageProperty.get());
}
}
ConfirmDialogBoxView.fxml - 这是 ConfirmDialogBox 视图
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefWidth="450.0" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.ConfirmDialogBoxController">
<children>
<VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="confirmLabel" textAlignment="CENTER" />
<HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
<children>
<Button fx:id="yesButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#yesButtonClicked" text="Yes" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
<Button fx:id="noButton" alignment="CENTER" contentDisplay="CENTER" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#noButtonClicked" text="No" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="50.0" top="30.0" />
</padding>
</VBox>
</children>
</AnchorPane>
AlertEmptyNameController.java - 这是当名称字段为空并且您单击添加人员时视图的控制器
package AddressBook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
public class AlertEmptyNameController {
@FXML
private Button okButton;
@FXML
private Label emptyNameLabel;
private Stage alertEmptyNamestage;
private Model model;
private AlertEmptyNameController alertEmptyNameController;
public AlertEmptyNameController() {
System.out.println("+1 AlertEmptyNameControlle() object instantiated");
}
public AlertEmptyNameController(Model model){
this.model = model;
System.out.println("+1 AlertEmptyNameController(model) object instantiated");
}
public void alertEmptyName() throws IOException {
FXMLLoader alertEmptyNameLoader = new FXMLLoader(getClass().getResource("AlertEmptyNameView.fxml"));
alertEmptyNameLoader.load();
AlertEmptyNameController alertEmptyNameController = alertEmptyNameLoader.getController();
Parent root = alertEmptyNameLoader.getRoot();
alertEmptyNamestage = new Stage();
alertEmptyNamestage.setScene(new Scene(root));
alertEmptyNamestage.setTitle("The Namefield is empty!");
alertEmptyNamestage.initModality(Modality.APPLICATION_MODAL);
alertEmptyNamestage.showAndWait();
}
@FXML
public boolean okButtonClicked(ActionEvent actionEvent) {
boolean answer = true;
alertEmptyNamestage = (Stage) okButton.getScene().getWindow();
alertEmptyNamestage.close();
return answer;
}
}
AlertEmptyNameView.fxml - AlertEmptyName 的视图
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<AnchorPane prefHeight="250.0" prefWidth="450.0" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.AlertEmptyNameController">
<children>
<VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="emptyNameLabel" text="The Namefield cannot be empty!" textAlignment="CENTER" />
<HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
<children>
<Button fx:id="okButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#okButtonClicked" text="Ok" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="50.0" top="30.0" />
</padding>
</VBox>
</children>
</AnchorPane>
例如,当我想关闭 window:
时的 NullPointerException
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at AddressBook.MainController.closeWindow(MainController.java:163)
at AddressBook.MainController.lambda$initialize(MainController.java:137)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at com.sun.javafx.stage.WindowPeerListener.closing(WindowPeerListener.java:88)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:122)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent(GlassWindowEventHandler.java:151)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:149)
at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1273)
at com.sun.glass.ui.Window.notifyClose(Window.java:1177)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null(WinApplication.java:186)
at java.lang.Thread.run(Thread.java:748)
希望有人能帮助我。
干杯
我现在删除了 confirmDialogBoxController.java 中的 display() 方法并将其放在 mainController.java
中
...
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.getLabel().setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
@FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
...
您在主控制器中的 confirmDialogBoxController
为空:它从未被初始化。您设置它的方式有问题: ConfirmDialogBoxController
仅在加载相应的 FXML 时才初始化(对任何 FXML 控制器对都是通用的),但是加载 FXML 的代码在 ConfirmDialogBoxController
class,因此在拥有控制器实例之前无法加载 FXML。
显示由其 FXML 定义的 UI 并不是 ConfirmDialogBoxController
的真正职责。您应该将 display()
方法移动到您的 MainController
class:
public class MainController implements Initializable {
// Existing code omitted...
// updated close method:
@FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
public boolean displayConfirmDialog(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.setConfirmMessage(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
// Get the user response (true = Yes button clicked) from controller:
return confirmDialogBoxController.getResponse() ;
}
}
然后更新ConfirmDialogBoxController
:
public class ConfirmDialogBoxController implements Initializable {
// existing code omitted...
// This should not be static, and should be a primitive type:
// private static Boolean answer ;
private boolean answer ;
// this method removed:
/*
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.confirmLabel.setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
*/
// This added for convenience:
public void setConfirmMessage(String message) {
confirmLabel.setText(message);
}
// This added to return the response (answer):
public boolean getResponse() {
return answer ;
}
// Note also your event handlers should be void:
@FXML
public void yesButtonClicked(ActionEvent actionEvent) {
answer = true;
stage = (Stage) yesButton.getScene().getWindow();
stage.close();
// return answer;
}
@FXML
public void noButtonClicked(ActionEvent actionEvent) {
answer = false;
Stage confirmWindow = (Stage) noButton.getScene().getWindow();
confirmWindow.close();
// return answer;
}
}
您可能希望对其他对话框进行类似的重构。
我是 JavaFX 的新手。我编写了一个带有地址的人员列表的表格视图。一切正常。然后我想用 MVC 或更好的 MVP 设计模式编写它。 我正在使用 FXML 和 scenebuilder 来布置场景。 现在有了 MVC,我遇到了一个问题,即当我想关闭确认对话框时,我得到了一个 NUllpointerException。 而且我也无法更改 confirmdialog window 场景的标签文本。 我想我知道问题出在哪里,但不知道如何正确解决。控制器被实例化两次,因此形成 fxml 的变量的第一个值为 NUll。
这就是我编写我的小应用程序的方式:
MiniTest.java - 我的主要应用程序
package AddressBook;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MiniTest extends Application {
private static Stage window;
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Adresslist of Clients");
Model model = new Model();
try {
FXMLLoader mainViewloader = new FXMLLoader(getClass().getResource("View.fxml"));
Parent root = (Parent) mainViewloader.load();
MainController mainController = mainViewloader.<MainController>getController();
window.setScene(new Scene(root));
window.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Stage getPrimaryStage() {
return window;
}
public static void main(String[] args) {
launch(args);
}
}
Model.java - 这是我的模型,不确定内容是否必须在这里。对于下一步,我想从 mysql 数据库中收集数据并将其保存到数据库中。目前我有这样的人
package AddressBook;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Model {
public ObservableList<Person> getPerson() {
ObservableList<Person> personList = FXCollections.observableArrayList();
Address addressPerson1 = new Address("Jaguarweg 12", "23454", "Bensheim");
Address addressPerson2 = new Address("Friedrich-Ebert-Str. 134", "82635", "Berlin");
Address addressPerson3 = new Address("Adam-Opel-Str. 1", "92364", "Bamberg");
Address addressPerson4 = new Address("Power-Shell-Pfad 21", "10083", "Hamburg");
Address addressPerson5 = new Address("Schwertstr. 76", "749236", "Stuttgart");
Address addressPerson6 = new Address("Hans-Jacob-Weg 4", "66396", "Wiesbaden");
Address addressPerson7 = new Address("Georg-Lucas-Str. 110", "53421", "Wien");
Address addressPerson8 = new Address("Andalusienweg 17", "723612", "Ostfildern");
Address addressPerson9 = new Address("Mercedes-Benz-Str. 9", "883621", "Wolfsburg");
Address addressPerson10 = new Address("Heinrich-Schwein-Str. 43", "134923", "Frankfurt");
Address addressPerson11 = new Address("Engel-Teufel-Str. 66", "083273", "Hildesheim");
personList.add(new Person("Georg Sorresto", addressPerson1));
personList.add(new Person("Flynn Bozzen", addressPerson2));
personList.add(new Person("Bill Klang", addressPerson3));
personList.add(new Person("Wilhelm Busch", addressPerson4));
personList.add(new Person("Gertrud Raven", addressPerson5));
personList.add(new Person("Markus Berg", addressPerson6));
personList.add(new Person("Juergen Schmidt", addressPerson7));
personList.add(new Person("Fritz Titz", addressPerson8));
personList.add(new Person("Bodo Bambino", addressPerson9));
personList.add(new Person("Ortrun Giner", addressPerson10));
personList.add(new Person("Jakob Huber", addressPerson11));
return personList;
}
}
Person.java - 我的人 class
package AddressBook;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty name;
private Address address;
public Person() {
this.name = new SimpleStringProperty("");
this.address = new Address("", "", "");
}
public Person(String name, Address address) {
this.name = new SimpleStringProperty(name);
;
this.address = address;
}
public String getName() {
return name.get();
}
public void setName(String name2) {
name.set(name2);
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
在 MainController.java 中 - 对于某些事情,例如关闭 window 或删除一个人,我将这样的方法称为我自己的 confirmdialogwindow 并使用相应的字符串作为标签。
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
这是完整的 MainController.java - 这是 mainView 的 mainController(View.fxml)
package AddressBook;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
@FXML
private MenuItem exitMenu;
@FXML
private TableView<Person> personTable;
@FXML
private TextField zipInput;
@FXML
private TextField cityInput;
@FXML
private TextField streetInput;
@FXML
private TextField nameInput;
@FXML
private TableColumn<Person, String> cityColumn;
@FXML
private TableColumn<Person, String> zipColumn;
@FXML
private TableColumn<Person, String> streetColumn;
@FXML
private TableColumn<Person, String> nameColumn;
@FXML
private Button addButton;
@FXML
private Button deleteButton;
@FXML
private SimpleStringProperty message;
private Stage window;
private ConfirmDialogBoxController confirmDialogBoxController;
private AlertEmptyNameController alertEmptyNameController;
private Model model;
public MainController(){
model = new Model();
System.out.println("+1 MainController()");
}
public MainController(Model model){
this.model = model;
System.out.println("+1 MainController(model)");
}
@Override
public void initialize(URL location, ResourceBundle resources) {
Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory = (TableColumn<Person, String> p) -> new MainController.EditingCell();
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
nameColumn.setCellFactory(cellFactory);
nameColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setName(t.getNewValue());
}
);
streetColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getStreet()));
streetColumn.setCellFactory(cellFactory);
streetColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setStreet(t.getNewValue());
});
zipColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getZip()));
zipColumn.setCellFactory(cellFactory);
zipColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setZip(t.getNewValue());
});
cityColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getCity()));
cityColumn.setCellFactory(cellFactory);
cityColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setCity(t.getNewValue());
});
personTable.setItems(model.getPerson());
personTable.setEditable(true);
MiniTest.getPrimaryStage().setOnCloseRequest(e -> {
try {
e.consume();
closeWindow(e);
} catch (IOException ex) {
ex.printStackTrace();
}
});
}
public SimpleStringProperty getMessageProperty(){
return message;
}
public void setMessage(String message) {
this.message.setValue(message);
}
public String getMessage() {
return this.message.getValue();
}
@FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
@FXML
public void closeWindowFromMenu(ActionEvent e) throws IOException {
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
public Stage getPrimaryStage() {
return window;
}
@FXML
public void addNewPerson() throws IOException {
alertEmptyNameController = new AlertEmptyNameController();
Person person = new Person();
person.setName(nameInput.getText());
if(nameInput.getText().isEmpty()){
alertEmptyNameController.alertEmptyName();
}else{
person.getAddress().setStreet(streetInput.getText());
person.getAddress().setZip(zipInput.getText());
person.getAddress().setCity(cityInput.getText());
personTable.getItems().add(person);
}
nameInput.clear();
streetInput.clear();
zipInput.clear();
cityInput.clear();
}
@FXML
public void deletePerson() throws IOException {
boolean answer = confirmDialogBoxController.display("Deleting Entry", "Are you sure you want to delete this entry?");
if (answer) {
ObservableList<Person> personSelected, allPersons;
allPersons = personTable.getItems();
personSelected = personTable.getSelectionModel().getSelectedItems();
personSelected.forEach(allPersons::remove);
}
}
static class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.focusedProperty().addListener((ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) -> {
if (!arg2) {
commitEdit(textField.getText());
}
});
}
private String getString() {
return getItem() == null ? "" : getItem();
}
}
}
View.fxml - 这是主视图
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.MainController">
<bottom>
<HBox fx:id="bottomLayout" alignment="CENTER" style="-fx-background-color: #292929;" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<children>
<TextField fx:id="nameInput" promptText="Name" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="8.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="streetInput" layoutX="15.0" layoutY="15.0" promptText="Street" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="zipInput" layoutX="163.0" layoutY="15.0" promptText="Zip" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="cityInput" layoutX="312.0" layoutY="15.0" promptText="City" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<Button fx:id="addButton" mnemonicParsing="false" onAction="#addNewPerson" style="-fx-background-color: #5ebcff; -fx-background-radius: 0; -fx-text-fill: white;" text="Add">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</Button>
<Button fx:id="deleteButton" layoutX="474.0" layoutY="15.0" mnemonicParsing="false" onAction="#deletePerson" style="-fx-background-radius: 0; -fx-background-color: #5ebcff; -fx-text-fill: white;" text="Delete">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="8.0" top="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
<center>
<TableView fx:id="personTable" editable="true" style="-fx-background-color: #5e5e5e;" stylesheets="@MyStyle.css" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="nameColumn" prefWidth="152.0" text="Name" />
<TableColumn fx:id="streetColumn" prefWidth="196.0" text="Street" />
<TableColumn fx:id="zipColumn" prefWidth="88.0" text="Zip" />
<TableColumn fx:id="cityColumn" prefWidth="163.0" text="City" />
</columns>
</TableView>
</center>
<top>
<HBox fx:id="menuLayout" style="-fx-background-color: #292929;" stylesheets="@MyStyle.css" BorderPane.alignment="CENTER">
<children>
<MenuBar fx:id="menuBar" stylesheets="@MyStyle.css">
<menus>
<Menu fx:id="fileMenu" mnemonicParsing="false" text="File">
<items>
<MenuItem fx:id="exitMenu" mnemonicParsing="false" onAction="#closeWindowFromMenu" text="Exit" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</HBox>
</top>
</BorderPane>
ConfirmDialogBoxController.java - 这是确认对话框的控制器,用于使用 "X" 或在菜单文件->退出中关闭 window 并询问用户是否真的想删除表视图中的条目
package AddressBook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class ConfirmDialogBoxController implements Initializable {
private static Boolean answer;
@FXML
private Button yesButton;
@FXML
private Button noButton;
@FXML
private Label confirmLabel;
@FXML
private Stage stage;
@FXML
private Model model;
public ConfirmDialogBoxController(){
System.out.println("+1 ConfirmDialogBoxController() object instantiated");
}
public ConfirmDialogBoxController(Model model){
this.model = model;
System.out.println("+1 ConfirmDialogBoxController(model) object instantiated");
}
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.confirmLabel.setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
public Label getLabel(){
return confirmLabel;
}
@FXML
public boolean yesButtonClicked(ActionEvent actionEvent) {
answer = true;
stage = (Stage) yesButton.getScene().getWindow();
stage.close();
return answer;
}
@FXML
public boolean noButtonClicked(ActionEvent actionEvent) {
answer = false;
Stage confirmWindow = (Stage) noButton.getScene().getWindow();
confirmWindow.close();
return answer;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
// confirmLabel.textProperty().bindBidirectional(messageProperty);
// System.out.println("messageProperty.getValue(): "+ messageProperty.getValue());
// System.out.println("DEBUG: message is = " + messageProperty.get());
}
}
ConfirmDialogBoxView.fxml - 这是 ConfirmDialogBox 视图
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefWidth="450.0" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.ConfirmDialogBoxController">
<children>
<VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="confirmLabel" textAlignment="CENTER" />
<HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
<children>
<Button fx:id="yesButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#yesButtonClicked" text="Yes" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
<Button fx:id="noButton" alignment="CENTER" contentDisplay="CENTER" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#noButtonClicked" text="No" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="50.0" top="30.0" />
</padding>
</VBox>
</children>
</AnchorPane>
AlertEmptyNameController.java - 这是当名称字段为空并且您单击添加人员时视图的控制器
package AddressBook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
public class AlertEmptyNameController {
@FXML
private Button okButton;
@FXML
private Label emptyNameLabel;
private Stage alertEmptyNamestage;
private Model model;
private AlertEmptyNameController alertEmptyNameController;
public AlertEmptyNameController() {
System.out.println("+1 AlertEmptyNameControlle() object instantiated");
}
public AlertEmptyNameController(Model model){
this.model = model;
System.out.println("+1 AlertEmptyNameController(model) object instantiated");
}
public void alertEmptyName() throws IOException {
FXMLLoader alertEmptyNameLoader = new FXMLLoader(getClass().getResource("AlertEmptyNameView.fxml"));
alertEmptyNameLoader.load();
AlertEmptyNameController alertEmptyNameController = alertEmptyNameLoader.getController();
Parent root = alertEmptyNameLoader.getRoot();
alertEmptyNamestage = new Stage();
alertEmptyNamestage.setScene(new Scene(root));
alertEmptyNamestage.setTitle("The Namefield is empty!");
alertEmptyNamestage.initModality(Modality.APPLICATION_MODAL);
alertEmptyNamestage.showAndWait();
}
@FXML
public boolean okButtonClicked(ActionEvent actionEvent) {
boolean answer = true;
alertEmptyNamestage = (Stage) okButton.getScene().getWindow();
alertEmptyNamestage.close();
return answer;
}
}
AlertEmptyNameView.fxml - AlertEmptyName 的视图
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<AnchorPane prefHeight="250.0" prefWidth="450.0" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.AlertEmptyNameController">
<children>
<VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="emptyNameLabel" text="The Namefield cannot be empty!" textAlignment="CENTER" />
<HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
<children>
<Button fx:id="okButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#okButtonClicked" text="Ok" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="50.0" top="30.0" />
</padding>
</VBox>
</children>
</AnchorPane>
例如,当我想关闭 window:
时的 NullPointerExceptionException in thread "JavaFX Application Thread" java.lang.NullPointerException
at AddressBook.MainController.closeWindow(MainController.java:163)
at AddressBook.MainController.lambda$initialize(MainController.java:137)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at com.sun.javafx.stage.WindowPeerListener.closing(WindowPeerListener.java:88)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:122)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent(GlassWindowEventHandler.java:151)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:149)
at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1273)
at com.sun.glass.ui.Window.notifyClose(Window.java:1177)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null(WinApplication.java:186)
at java.lang.Thread.run(Thread.java:748)
希望有人能帮助我。
干杯
我现在删除了 confirmDialogBoxController.java 中的 display() 方法并将其放在 mainController.java
中...
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.getLabel().setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
@FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
...
您在主控制器中的 confirmDialogBoxController
为空:它从未被初始化。您设置它的方式有问题: ConfirmDialogBoxController
仅在加载相应的 FXML 时才初始化(对任何 FXML 控制器对都是通用的),但是加载 FXML 的代码在 ConfirmDialogBoxController
class,因此在拥有控制器实例之前无法加载 FXML。
显示由其 FXML 定义的 UI 并不是 ConfirmDialogBoxController
的真正职责。您应该将 display()
方法移动到您的 MainController
class:
public class MainController implements Initializable {
// Existing code omitted...
// updated close method:
@FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
public boolean displayConfirmDialog(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.setConfirmMessage(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
// Get the user response (true = Yes button clicked) from controller:
return confirmDialogBoxController.getResponse() ;
}
}
然后更新ConfirmDialogBoxController
:
public class ConfirmDialogBoxController implements Initializable {
// existing code omitted...
// This should not be static, and should be a primitive type:
// private static Boolean answer ;
private boolean answer ;
// this method removed:
/*
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.confirmLabel.setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
*/
// This added for convenience:
public void setConfirmMessage(String message) {
confirmLabel.setText(message);
}
// This added to return the response (answer):
public boolean getResponse() {
return answer ;
}
// Note also your event handlers should be void:
@FXML
public void yesButtonClicked(ActionEvent actionEvent) {
answer = true;
stage = (Stage) yesButton.getScene().getWindow();
stage.close();
// return answer;
}
@FXML
public void noButtonClicked(ActionEvent actionEvent) {
answer = false;
Stage confirmWindow = (Stage) noButton.getScene().getWindow();
confirmWindow.close();
// return answer;
}
}
您可能希望对其他对话框进行类似的重构。