Home > Back-end >  JavaFX: How to show an Alert Confirmation before a property value is changed?
JavaFX: How to show an Alert Confirmation before a property value is changed?

Time:02-06

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?

CodePudding user response:

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();
    }
}
  • Related