0

I am struggling with the following problem: I have something like a popup in my javafx application, that should block the application, until the user made some input. It is NOT a seperate stage, where i can call showAndWait() and then return the input of the stage. The popup is realized as a pane, that is placed over the other components. And now i do something like this:

PopupPane pp = new PopupPane()
stackPane.add(new PopupPane()); //show pane
//... waiting until user terminates popup
return pp.getInput(); //returns input when user terminates popup

So i want pp.getInput() to wait, until the user presses the OK/CANCEL/APPLY/... button in my popup. How can i realize something like showAndWait() in this situation?

Yan_Yan
  • 67
  • 7
  • 3
    For javafx 9+ take a look at this thread: https://stackoverflow.com/questions/46369046/how-to-wait-for-user-input-on-javafx-application-thread-without-using-showandwai – fabian Aug 25 '19 at 00:24
  • 3
    curious: why? there are dialogs/alerts that would do the heavy lifting for you – kleopatra Aug 25 '19 at 10:19
  • Because sometimes there appear issues, that the dialog is shown UNDER the main window. And especially when i need more than one dialog at the same time, it would be better, when they are "simulated" in the same window. – Yan_Yan Aug 25 '19 at 10:57
  • 1
    If you are having issues with a standard dialog not appearing on top of the main window, then that might be because you do not [initialize the owner](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Dialog.html#initOwner-javafx.stage.Window-) of the dialog before you show it. – jewelsea Aug 26 '19 at 17:33
  • then provide a [mcve] that demonstrates the issue (of showing under main) vs. rolling your own (which you don't show) that doesn't work as well ;) – kleopatra Aug 28 '19 at 08:09

2 Answers2

3

One possible way to do this would be to utilize an additional pane that can be disabled while the "popup" is being displayed.

For example, say the root layout pane of your Scene is a StackPane. You could wrap all the rest of your interface in another Pane that you'll disable or enable as needed.

When the "popup" needs to be displayed, add it to your StackPane and disable the "content" pane. When the popup closes, just remove it from your StackPane and re-enable the "content" pane.

Here's a quick and admittedly unattractive example of the concept:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class SimulatedPopupExample extends Application {

    private static StackPane root;
    private static BorderPane content;

    public static void main(String[] args) {
        launch(args);
    }

    private static void showPopup() {

        // Disable the main layout pain
        content.setDisable(true);

        VBox popup = new VBox();
        popup.setPadding(new Insets(10));
        popup.setAlignment(Pos.CENTER);
        popup.setStyle("-fx-border-color: black; -fx-background-color: -fx-base;");
        popup.setMaxSize(200, 200);

        popup.getChildren().add(
                new Button("Close Popup") {{
                    setOnAction(event -> {
                        // Re-enable the pane
                        content.setDisable(false);

                        // Remove popup from root layout
                        root.getChildren().remove(popup);

                    });
                }}
        );

        // Add popup to root layout
        root.getChildren().add(popup);
    }

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        root = new StackPane();
        content = new BorderPane(
                new Button("Show \"Popup\"") {{
                    setOnAction(e -> showPopup());
                }},
                new Button("Top Button"),
                new Button("Right Button"),
                new Button("Bottom Button"),
                new Button("Left Button")
        );

        root.getChildren().add(content);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setWidth(500);
        primaryStage.setHeight(400);
        primaryStage.setTitle("SimulatedPopupExample Sample");
        primaryStage.show();

    }
}

The Result:

screencast

Zephyr
  • 9,885
  • 4
  • 28
  • 63
  • I already figured that out but zhank you anyway. But my problem is, that i need a way to wait for some input (like a textfield). And i need this in some kind of blocking method, so that i only need to call getInput() (in another another class) and it waits for the input – Yan_Yan Aug 25 '19 at 10:52
-1

Here is a Custom Dialog that can not be closed or accepted until the user enter data in the TextField

    private void showInputTextDialog(){

            Label lblAmt = new Label("Enter Amount");
            Button btnOK = new Button("OK");
            TextField txtAmt = new TextField();

            AnchorPane customDialog = new AnchorPane();
            customDialog.setStyle("-fx-border-color:red;-fx-border-width:10px; -fx-background-color: lightblue;");
            customDialog.getChildren().addAll(lblAmt,btnOK,txtAmt);
            lblAmt.setLayoutX(30);
            lblAmt.setLayoutY(30);
            txtAmt.setLayoutX(164);
            txtAmt.setLayoutY(25);
            txtAmt.setMaxWidth(116);
            btnOK.setLayoutX(190);
            btnOK.setLayoutY(100);
            btnOK.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
            lblAmt.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
            txtAmt.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");

            Scene secondScene = new Scene(customDialog, 300, 180);

            EventHandler<ActionEvent> filter = event -> {
            if(txtAmt.getText().isEmpty()) {
    event.consume();
            }
            };

            // New window (Stage)
            Stage newWindow = new Stage();
            //newWindow.initStyle(StageStyle.UNDECORATED);
            newWindow.initModality(Modality.APPLICATION_MODAL);
            newWindow.setResizable(false);
            //newWindow.setTitle("Custom Dialog");
            newWindow.setScene(secondScene);
            btnOK.addEventHandler(ActionEvent.ACTION,filter);
            btnOK.setOnAction(evt -> {
            String str = txtAmt.getText();
            System.out.println("@@@@@@@@@@@@@@@@ str "+str);
            if(txtAmt.getText().trim().equals("")) {
                evt.consume();
                txtAmt.clear();
                txtAmt.requestFocus();
            }else{
                txAMT = Double.valueOf(str);
                newWindow.close();  
            }
            });

            newWindow.setOnCloseRequest(event -> {
                if(txtAmt.getText().isEmpty()) {
                event.consume();
            }
            });
            txtAmt.requestFocus();
            newWindow.showAndWait();
}
Vector
  • 3,066
  • 5
  • 27
  • 54