1

I'm trying to create my own implementation for an overlay dialog that opens up when the user clicks a button. The code you see below works perfectly fine but is not that pretty. I'm searching for an implementation where I don't have to create a Thread for each dialog I create. Is there any way to acchieve this?

I've been browsing through various Java source files like JOptionPane and JDialog to figure out what they do in order to block the thread until the user closes the dialog, but I didn't manage to understand it. Additionally I tried various code snippets including the EventQueue like for example EventQueue.invokeLater or EventQueue.invokeAndWait.

// MainViewController.java

@FXML
private void handleServerButton(ActionEvent evt){
    Thread t = new Thread(() -> {
        if (serverD.showDialog(overlay) == Dialog.OK_OPTION){
            System.out.println("OK");
        } else {
            System.out.println("ABORT");
        }
    });
    t.start();
}

// Dialog.java

public int showDialog(Pane parent) {
    latch = new CountDownLatch(1);
    this.result.set(NONE);

    approveButton.setDefaultButton(true);
    abortButton.setCancelButton(true);
    container.setVisible(true);
    parent.setVisible(true);

    try {
        latch.await();
    } catch (InterruptedException ex){ }

    approveButton.setDefaultButton(false);
    abortButton.setCancelButton(false);
    container.setVisible(false);
    parent.setVisible(false);

    return result.get();
}

@Override
public void changed(ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) {
    if (newValue != NONE)
        latch.countDown();
}

This is what it looks like (please note: the overlay dialog is not a window itself but rather a pane within the main window):

Final Result

enter image description here

c0der
  • 18,467
  • 6
  • 33
  • 65
Thomas Thaler
  • 55
  • 1
  • 5
  • 1
    Not sure what you are doing, but why not use a second `Stage` or `PopupWindow` for this purpose? They all inherit the `Window` class which defines the `showAndWait()` method, which is exactually what you are trying to achieve. – n247s Jul 28 '19 at 14:32
  • Does that work for a pane used as a "window"? Because I would like to integrate the dialogs into the main window (I will add a screenshot to the description above). – Thomas Thaler Jul 28 '19 at 14:38
  • The `PopupWindow` can be configured to act as a tooltip. In fact the `Tooltip` class uses the `PopuoWindow` class (check the source codes if you want to see the example). – n247s Jul 28 '19 at 14:42
  • Thank you very much n247s, I will try it out. I also added screenshot as I mentioned before. – Thomas Thaler Jul 28 '19 at 14:54
  • I am unsure as to why you need a thread at all. – SedJ601 Jul 28 '19 at 15:02
  • @Sedrick because otherwise my UI freezes (the latch is there to block the thread until the changed method is invoked outside and the latch is counted down) – Thomas Thaler Jul 28 '19 at 15:03
  • Either I am not understanding your problem or you have complicated something that should be pretty straight forward. [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). – SedJ601 Jul 28 '19 at 15:06
  • Possible duplicate of [How to create a modal window in JavaFX 2.1](https://stackoverflow.com/questions/10486731/how-to-create-a-modal-window-in-javafx-2-1) – SedJ601 Jul 28 '19 at 15:08
  • @Sedrick maybe I left out too much of the information needed. Please have a look at the [final result](https://i.stack.imgur.com/bvThf.png) that should make everything clearer :) – Thomas Thaler Jul 28 '19 at 15:09
  • 1
    Have a look at the possible duplicate. – SedJ601 Jul 28 '19 at 15:11
  • Have you seen the [JFoenix](https://github.com/jfoenixadmin/JFoenix) library? Specifically, its [JFXDialog component](https://github.com/jfoenixadmin/JFoenix#components)? Anyway, `JOptionPane` and `JDialog` are Swing objects, you should be looking at JavaFX objects such as `Dialog` and `Window` (note they can't be embedded in a scene). And you don't need to use another thread to wait for user input; what you need is a nested event loop. See [this question](https://stackoverflow.com/questions/46369046/how-to-wait-for-user-input-on-javafx-application-thread-without-using-showandwai). – Slaw Jul 28 '19 at 21:26

2 Answers2

0

Look at the Alert and Dialog documentation. Both provide functionality similar to what you want, and both can be customised if they don't quite match your use case.

Quick example:

Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("title");
alert.setContent("content");
...
// More customisation available, read the docs
alert.show();. // Or showAndWait()
cameron1024
  • 9,083
  • 2
  • 16
  • 36
0

I solved the problem by deriving a Dialog class from Stage and implementing the logic there. The only thing that is left, is to extract the values from the controls of the view controller. But I already noticed that the dialog is passed as a Window through the ActionEvent - so that should be a minor issue.

public class Dialog extends Stage {

    public static int OK_OPTION = 0;

    public static int ABORT_OPTION = -1;

    private int result;

    public Dialog(Scene parent, String url) throws IOException{
        super(StageStyle.TRANSPARENT);

        Parent root = FXMLLoader.load(getClass().getResource(url));
        Scene scene = new Scene(root);

        if (System.getProperty("os.name").equals("Mac OS X")){
            root.setStyle("-fx-background-radius: 0 0 3px 3px;");
        }
        scene.setFill(Color.TRANSPARENT);
        setScene(scene);

        initOwner(parent.getWindow());

        double titlebar = parent.getWindow().getHeight() - parent.getHeight();
        setX(parent.getWindow().getX());
        setY(parent.getWindow().getY() + titlebar + 50);
    }

    public int showDialog(){
        showAndWait();
        return result;
    }
}
Thomas Thaler
  • 55
  • 1
  • 5
  • 1
    This would be a better solution, you might want to call `initModality(Modality.WINDOW_MODAL)` to get the 'event blocking behavior' of the parent window, if that is what you are going for. Another option is to listen to the focused property of your `Dialog` class, and autohide the window when it is unfocused. – n247s Jul 28 '19 at 20:00