javafx - 如何从主控制器类将动作侦听器设置为对话框确定按钮
问题描述
我实际上想让 OK 按钮仅在对话框中的所有字段都填满时才响应。而且我也不喜欢禁用确定按钮。
这是 MainController 中设置 Dialog 的方法:
public void showItemDialog(){
Dialog<ButtonType> dialog = new Dialog<>();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("todoItemDialog.fxml"));
try {
dialog.getDialogPane().setContent(fxmlLoader.load());
} catch (IOException e){
System.out.println("Couldn't load Dialog");
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if(result.isPresent() && result.get() == ButtonType.OK){
DialogController controller = fxmlLoader.getController();
controller.processResults();
}
}
这是我的 DialogController 类:
public class DialogController {
@FXML
private TextField descriptionTextField;
@FXML
private TextArea detailsTextArea;
@FXML
private DatePicker deadlinePicker;
@FXML
private DialogPane dialogPaneId;
public void processResults(){
String description = descriptionTextField.getText();
String details = detailsTextArea.getText();
LocalDate date = deadlinePicker.getValue();
TodoData.getInstance().addTodoItem(new TodoItem(description, details, date));
}
public boolean areFieldsEmpty(){
//checks if fields are empty...
return (descriptionTextField.getText().trim().isEmpty() || detailsTextArea.getText().trim().isEmpty() ||
deadlinePicker.getValue() == null);
}
}
现在,我认为 OK 按钮的 EventHandler 应该是这样的:
Button okButton = (Button) dialogPaneId.lookupButton(ButtonType.OK);
okButton.addEventFilter(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("was here");
if(areFieldsEmpty()){
event.consume();
}
}
});
但这在 MainController 类或 DialogController 类中不起作用(显示 NullPointerException)。我对 JavaFX 很陌生,我也在这里搜索了很多,但找不到任何具体的结果。提前致谢。
解决方案
我认为在这种情况下,您不应该使用 Dialog 功能。这是一个如何完成的小例子:
主控制器类:
package sample;
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.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
//...
}
@FXML
public void handleShowDialogBtnClick(ActionEvent event) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("ToDoItem.fxml"));
Parent root = null;
try {
root = loader.load();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
if (root == null) return;
Stage toDoItemStage = new Stage();
toDoItemStage.setTitle("My Dialog Title");
toDoItemStage.setAlwaysOnTop(true);
ToDoItemController toDoItemController = loader.getController();
toDoItemStage.setScene(new Scene(root));
toDoItemStage.initOwner((((Button) event.getSource()).getScene().getWindow()));
toDoItemController.setStage(toDoItemStage);
toDoItemStage.setOnCloseRequest(e -> toDoItemController.removeController());
toDoItemStage.show();
}
}
主要 FXML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<Button onAction="#handleShowDialogBtnClick" text="Show Dialog" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.MainController"/>
ToDoItemController 类:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.LoadException;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class ToDoItemController {
@FXML
private TextField
descriptionTextField;
@FXML
private DatePicker
deadlineDatePicker;
@FXML
private TextArea
detailsTextArea;
private Stage toDoItemStage;
private static ToDoItemController toDoItemController;
public ToDoItemController() throws LoadException {
if (toDoItemController == null) toDoItemController = this;
else throw new LoadException("Singleton FXML");
}
@FXML
public void handleOkayBtnClick() {
if (descriptionTextField.getText().trim().isEmpty()
|| detailsTextArea.getText().trim().isEmpty()
|| deadlineDatePicker.getValue() == null) {
Alert alert = new Alert(Alert.AlertType.ERROR, "Some information is missing.", ButtonType.OK);
alert.initOwner(toDoItemStage);
alert.showAndWait();
} else {
TodoData.getInstance().addTodoItem(new TodoItem(description.get(), details.get(), deadline.get()));
closeStage();
}
}
@FXML
public void handleCancelBtnClick() {
closeStage();
}
void setStage(Stage toDoItemStage) {
this.toDoItemStage = toDoItemStage;
}
void removeController() {
toDoItemController = null;
}
private void closeStage() {
removeController();
toDoItemStage.close();
}
}
ToDoItem FXML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane fx:id="rootGridPane" hgap="3.0" vgap="3.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="sample.ToDoItemController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="NEVER" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<HBox GridPane.columnSpan="2">
<children>
<Label text="My Custom Dialog">
<font>
<Font size="24.0" />
</font>
</Label>
</children>
</HBox>
<Label text="Description:" GridPane.rowIndex="1" />
<TextField fx:id="descriptionTextField" GridPane.rowIndex="2" />
<Label text="Details:" GridPane.rowIndex="3" />
<TextArea fx:id="detailsTextArea" GridPane.columnSpan="2" GridPane.rowIndex="4" />
<Label text="Deadline:" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<DatePicker fx:id="deadlineDatePicker" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<HBox alignment="CENTER_RIGHT" spacing="10.0" GridPane.columnSpan="2" GridPane.rowIndex="5">
<children>
<Button defaultButton="true" onAction="#handleOkayBtnClick" prefWidth="70.0" text="OK" />
<Button cancelButton="true" onAction="#handleCancelBtnClick" prefWidth="70.0" text="Cancel" />
</children>
</HBox>
</children>
<padding>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</padding>
</GridPane>
主应用类:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
推荐阅读
- three.js - ThreeJS翻转反转X轴(左手坐标系)
- kubernetes - 如何从注解对象中提取 Kubernestes PODS mac 地址
- big-o - 如何计算 Karatsuba 算法的 O(n)?
- excel - 比较两个单元格与Excel中的If子句
- javascript - 使用 AsyncStorage 的 react-native 身份验证应用程序
- android - Flutter apk 构建、安装但随后无法打开
- rust - 通过在 self 中查找键来替换 HashSet 值
- javascript - ReactNative recyclerlistview 项目之间的空间增加或重叠
- c# - Blazor - 将参数传递给父级
- python - 如何使用 zorder 在 matplotlib 中的框架/边框上绘制饼图?