Home > Enterprise >  Java - custom dialogs with background threads
Java - custom dialogs with background threads

Time:07-07

I am trying to raise a custom loading dialog in java and then execute some synchronous function which takes a few seconds.

I would like the dialog to be present as long as the function executes and once it finishes I would close the dialog.

My Dialog looks as follows:

public abstract class LoaderControl extends Control implements SimpleDialogInfo {
    private static final StyleablePropertyFactory<LoaderControl> FACTORY = new StyleablePropertyFactory<>(Control.getClassCssMetaData());

    private LoaderDialogResponse response;
    private final DialogInfo dialogInfo;
    private final SimpleStringProperty text = new SimpleStringProperty("");
    private final SimpleBooleanProperty spinnerVisible = new SimpleBooleanProperty(true);
    private UpdaterStates state;
    private CloseDialogFunction onClose;

    @Override
    public void closeDialog(){
        onClose.closeDialog();
    }
    @Override
    public void setCloseDialog(CloseDialogFunction onClose){
        this.onClose = onClose;
    }
}

This is how I create it and show it:

public void createIndependentDialog(SimpleDialogInfo content, EventHandler<MouseEvent> onClose) {
        Platform.runLater(() -> {
            Stage stage = new Stage();
            Parent p = new StackPane();
            Scene s = new Scene(p);
            stage.setScene(s);
            MFXGenericDialog dialogContent = MFXGenericDialogBuilder.build()
                    .makeScrollable(true)
                    .setShowAlwaysOnTop(false)
                    .get();
            MFXStageDialog dialog = MFXGenericDialogBuilder.build(dialogContent)
                    .toStageDialogBuilder()
                    .initModality(Modality.APPLICATION_MODAL)
                    .setDraggable(true)
                    .initOwner(stage)
                    .setTitle("Dialogs Preview")
                    .setOwnerNode(grid)
                    .setScrimPriority(ScrimPriority.WINDOW)
                    .setScrimOwner(true)
                    .get();
            dialogContent.setMinSize(350, 200);
            MFXFontIcon infoIcon = new MFXFontIcon(content.getDialogInfo().getIcon(), 18);
            dialogContent.setHeaderIcon(infoIcon);
            dialogContent.setHeaderText(content.getDialogInfo().getHeader());
            dialogContent.setContent((Node) content);
            MFXGenericDialog finalDialogContent = dialogContent;
            MFXStageDialog finalDialog = dialog;
            content.setCloseDialog(dialog::close);
            convertDialogTo(String.format("mfx-%s-dialog", content.getDialogInfo().getDialogType()));
            if(onClose != null)
                dialogContent.setOnClose(onClose);
            dialog.showAndWait();
        });
    }

This is how it looks like in the calling class:

DialogLoaderControlImpl preloader = new DialogLoaderControlImpl(new LoaderDialogInfo("Searching For New Versions"));
DialogsController.getInstance().createIndependentDialog(preloader);
someSynchronousMethod();
preloader.closeDialog();

The issue is that when I get to the "preloader.closeDialog()" line, the closeDialog function which should close the dialog is null (the onClose field is null).

In short:

The createIndependentDialog() method should raise a dialog and I would like to proceed to execute the method "someSynchronousMethod()" while the dialog is still shown and close it once the method finishes.

Please note that I use a Skin for the dialog which is not shown here but it works if I remove the Platform.runLater, but then it is stuck in the showAndWait() without advancing which is expected

Is there a way or a known design of some sort that will help to run tasks/methods with custom dialogs?

CodePudding user response:

This can be done, but as pointed out in the comments, it is probably better to use some type of progress node. I used Alert in this example but Dialog should be very similar.

The key is closing the Alert/Dialog after the task is complete using the task's setOnSucceeded.

longRunningTask.setOnSucceeded((t) -> {
    System.out.println("Task Done!");            
    alert.close();
});

Full Code

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class App extends Application
{

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

    @Override
    public void start(Stage stage)
    {
        Scene scene = new Scene(new StackPane(new Label("Hello World!")), 320, 240);
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
        
        Task<Integer> longRunningTask = new Task<Integer>() {
            @Override protected Integer call() throws Exception {
                int iterations;
                for (iterations = 0; iterations < 100000; iterations  ) {
                    if (isCancelled()) {
                       break;
                    }
                    System.out.println("Iteration "   iterations);
                }
                return iterations;
            }
        };        
        
        Alert alert = new Alert(Alert.AlertType.INFORMATION);        
        Button okButton = (Button)alert.getDialogPane().lookupButton(ButtonType.OK);
        okButton.setDisable(true);
        
        longRunningTask.setOnSucceeded((t) -> {
            System.out.println("Task Done!");            
            alert.close();
        });
        
        new Thread(longRunningTask).start();
        
        alert.setTitle("Hello World");
        alert.setHeaderText("Hello");
        alert.setContentText("I will close when the long running task ends!");
        alert.showAndWait();
    }
}

Altered code from https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm.

One pitfall I can see is someone closing the Alert/Dialog before the task finishes.

  • Related