英文:
JavaFX: How to show an Alert Confirmation before a property value is changed?
问题
ChangeListener<Object> listener = (observable, oldValue, newValue) -> {
if (!changeConfirmed()) {
// Reset the value of the property to its old value
if (observable instanceof Slider) {
((Slider) observable).setValue((Double) oldValue);
} else if (observable instanceof TextField) {
((TextField) observable).setText((String) oldValue);
}
// Add similar checks for other UI elements if needed
}
};
slider.valueProperty().addListener(listener);
textField.textProperty().addListener(listener);
// Add similar listeners for other UI elements if needed
英文:
I have a JavaFX Application with many UI-Elements like Buttons, Sliders, TextFields and so on. I have a certain group of UI-Elements that I want the user to be able to change but only after he confirmed once, that he is sure he wants to change them. Any attempted change to any of those elements should be discarded, if the user does not confirm that he knows what he's doing.
I've made a very simple mockup.
public class App extends Application {
private Label label;
boolean changeConfirmed = false;
@Override
public void start(Stage stage) {
BorderPane pane = new BorderPane();
VBox container = new VBox();
Button button = new Button("Something");
Slider slider = new Slider(0,1,0.5);
TextField textField = new TextField();
label = new Label("Empty");
// Here should be the code I'm asking for
container.getChildren().addAll(button,slider,textField);
pane.setRight(container);
pane.setCenter(label);
Scene scene = new Scene(pane,400,300);
stage.setTitle("Alert Test");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
private void handle(String string) {
label.setText(string);
}
private boolean changeConfirmed(){
if(changeConfirmed) {
return true;
}
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm Change");
alert.setHeaderText("A change occurred.");
alert.setContentText("Do you really want to change the value?");
Optional<ButtonType> buttonType = alert.showAndWait();
if(buttonType.isPresent() && buttonType.get().equals(ButtonType.OK)) {
changeConfirmed = true;
return true;
}
return false;
}
}
I want that, as long as the boolean changeConfirmed is false, any attempted change to any of the UI elements is interrupted by the changeConfirmed()-Method. Once the method returned true, the boolean is true and no further confirmation is needed (it would otherwise become very tiresome to confirm all changes for every UI-Element). The boolean changeConfirmed is made false again at a later time in the program and not relevant here.
What is absolut important to me is that the value of the property doesn't change before the confirmation has been passed.
I've tried using ChangeListeners (obviously) but to my knowledge, the value of the property has already been changed when the listener is executed. So the Alert comes to late (I might be wrong here, it's my current understanding)
I've also tried InvalidationListeners. Those seem to be processed before a change to the property is actually made, but I don't know how to make sure that the property's value doesn't change if the change-Alert is not confirmed.
How can I solve this problem?
答案1
得分: 2
只需在控件的处理程序中检查`changeConfirmed`是否为false;如果是,则显示确认对话框。然后,在事件处理程序中再次检查`changeConfirmed`是否为true;如果是,则更改值。如果要在用户拒绝确认时恢复控件中的值,则编写相应的代码。
以下是基于您的示例的快速示例:
```java
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Optional;
public class HelloApplication extends Application {
private boolean changeConfirmed = false;
@Override
public void start(Stage stage) throws IOException {
VBox root = new VBox(5);
HBox nameBox = new HBox(5);
HBox ageBox = new HBox(5);
Label nameLabel = new Label();
Label ageLabel = new Label();
Slider slider = new Slider();
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMin(0);
slider.setMax(120);
TextField nameTF = new TextField();
slider.valueChangingProperty().addListener((obs, isFinishedChanging, isNowChanging) -> {
if (isFinishedChanging) {
if (!changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
ageLabel.setText(String.valueOf((int)slider.getValue()));
} else {
// revert to current value:
String ageStr = ageLabel.getText();
int age = ageStr.isEmpty() ? 0 : Integer.parseInt(ageStr);
slider.setValue(age);
}
}
});
nameTF.setOnAction(e -> {
if (!changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
nameLabel.setText(nameTF.getText());
} else {
nameTF.setText(nameLabel.getText());
}
});
nameBox.getChildren().addAll(new Label("Name:"), nameLabel);
ageBox.getChildren().addAll(new Label("Age:"), ageLabel);
Button clearConfirm = new Button("Request to confirm changes");
clearConfirm.setOnAction(e -> changeConfirmed = false);
root.getChildren().addAll(nameBox, ageBox, nameTF, slider, clearConfirm);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
}
private void showConfirmDialog() {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm Change");
alert.setHeaderText("A change occurred.");
alert.setContentText("Do you really want to change the value?");
Optional<ButtonType> buttonType = alert.showAndWait();
if(buttonType.isPresent() && buttonType.get().equals(ButtonType.OK)) {
changeConfirmed = true;
}
}
public static void main(String[] args) {
launch();
}
}
英文:
Just check in the handlers for the controls if changeConfirmed
is false; if it is show the confirm dialog. Then, still in the event handler, check again if changeConfirmed
is true; if it is, change the value. If you want to revert the value in the control if the users denies confirmation, then write the code for that.
Here is a quick example based loosely on your example:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Optional;
public class HelloApplication extends Application {
private boolean changeConfirmed = false ;
@Override
public void start(Stage stage) throws IOException {
VBox root = new VBox(5);
HBox nameBox = new HBox(5);
HBox ageBox = new HBox(5);
Label nameLabel = new Label();
Label ageLabel = new Label();
Slider slider = new Slider();
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMin(0);
slider.setMax(120);
TextField nameTF = new TextField();
slider.valueChangingProperty().addListener((obs, isFinishedChanging, isNowChanging) -> {
if (isFinishedChanging) {
if (!changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
ageLabel.setText(String.valueOf((int)slider.getValue()));
} else {
// revert to current value:
String ageStr = ageLabel.getText();
int age = ageStr.isEmpty() ? 0 : Integer.parseInt(ageStr);
slider.setValue(age);
}
}
});
nameTF.setOnAction(e -> {
if (! changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
nameLabel.setText(nameTF.getText());
} else {
nameTF.setText(nameLabel.getText());
}
});
nameBox.getChildren().addAll(new Label("Name:"), nameLabel);
ageBox.getChildren().addAll(new Label("Age:"), ageLabel);
Button clearConfirm = new Button("Request to confirm changes");
clearConfirm.setOnAction(e -> changeConfirmed = false);
root.getChildren().addAll(nameBox, ageBox, nameTF, slider, clearConfirm);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
}
private void showConfirmDialog() {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm Change");
alert.setHeaderText("A change occurred.");
alert.setContentText("Do you really want to change the value?");
Optional<ButtonType> buttonType = alert.showAndWait();
if(buttonType.isPresent() && buttonType.get().equals(ButtonType.OK)) {
changeConfirmed = true;
}
}
public static void main(String[] args) {
launch();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论