JavaFX: 如何在更改属性值之前显示确认提示框?

huangapple go评论63阅读模式
英文:

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(&quot;Something&quot;);
        Slider slider = new Slider(0,1,0.5);
        TextField textField = new TextField();
        label = new Label(&quot;Empty&quot;);

        // Here should be the code I&#39;m asking for

        container.getChildren().addAll(button,slider,textField);
        pane.setRight(container);
        pane.setCenter(label);

        Scene scene = new Scene(pane,400,300);
        stage.setTitle(&quot;Alert Test&quot;);
        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(&quot;Confirm Change&quot;);
        alert.setHeaderText(&quot;A change occurred.&quot;);
        alert.setContentText(&quot;Do you really want to change the value?&quot;);
        Optional&lt;ButtonType&gt; buttonType = alert.showAndWait();
        if(buttonType.isPresent() &amp;&amp; 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) -&gt; {
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 -&gt; {
if (! changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
nameLabel.setText(nameTF.getText());
} else {
nameTF.setText(nameLabel.getText());
}
});
nameBox.getChildren().addAll(new Label(&quot;Name:&quot;), nameLabel);
ageBox.getChildren().addAll(new Label(&quot;Age:&quot;), ageLabel);
Button clearConfirm = new Button(&quot;Request to confirm changes&quot;);
clearConfirm.setOnAction(e -&gt; 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(&quot;Confirm Change&quot;);
alert.setHeaderText(&quot;A change occurred.&quot;);
alert.setContentText(&quot;Do you really want to change the value?&quot;);
Optional&lt;ButtonType&gt; buttonType = alert.showAndWait();
if(buttonType.isPresent() &amp;&amp; buttonType.get().equals(ButtonType.OK)) {
changeConfirmed = true;
}
}
public static void main(String[] args) {
launch();
}
}

huangapple
  • 本文由 发表于 2023年2月6日 09:02:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75356559.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定