This discussion is archived
4 Replies Latest reply: Jan 28, 2013 8:09 AM by shakir.gusaroff RSS

Locking the GUI, spinning dial (simillar to JXLayer)

805439 Newbie
Currently Being Moderated
Hello,

I am looking for a way to lock the GUI (and display a spinning dial) when a long running thread is running.
How would one do this with JavaFX?

Thanks in advance
  • 1. Re: Locking the GUI, spinning dial (simillar to JXLayer)
    jsmith Guru
    Currently Being Moderated
    scene.getRoot().setMouseTransparent(true);
    scene.setCursor(Cursor.WAIT);
  • 2. Re: Locking the GUI, spinning dial (simillar to JXLayer)
    shakir.gusaroff Expert
    Currently Being Moderated
    Hi.Here is an example:
     
    
    import javafx.application.Application;
    import javafx.beans.binding.When;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.concurrent.Task;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.scene.Cursor;
    
    
    public class TaskProgrs extends Application {
        
        @Override
        public void start(Stage primaryStage) {
            Button btn = new Button();
            btn.setText("Submit");
            btn.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println("Hello World!");
                }
            });
            
            StackPane root = new StackPane();
            root.getChildren().add(btn);
            
           final Scene scene = new Scene(root, 300, 250);
            
            primaryStage.setTitle("Hello World!");
            primaryStage.setScene(scene);
            primaryStage.show();
            
             Task<Integer> task = new Task<Integer>() {
             @Override protected Integer call() throws Exception {
                 int iterations;
                 for (iterations = 0; iterations < 10000000; iterations++) {
                     if (isCancelled()) {
                         updateMessage("Cancelled");
                        
                         break;
                     }
                     updateMessage("Iteration " + iterations);
                     updateProgress(iterations, 10000000);
                 }
                 return iterations;
             }
         };
            
           
            scene.getRoot().mouseTransparentProperty().bind(task.runningProperty()); 
            scene.cursorProperty().bind(new When(task.runningProperty()).
                     then(new SimpleObjectProperty(Cursor.WAIT)).otherwise(new SimpleObjectProperty(Cursor.DEFAULT)));
             Thread th = new Thread(task);
             
             th.start();
            
        }
    
        /**
         * The main() method is ignored in correctly deployed JavaFX application.
         * main() serves only as fallback in case the application can not be
         * launched through deployment artifacts, e.g., in IDEs with limited FX
         * support. NetBeans ignores main().
         *
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            launch(args);
        }
    }
    This works fine, except the cursor is not updated immediately because there is a bug:
    http://javafx-jira.kenai.com/browse/RT-21272
    Only when the mouse is moved for the first time after that, the change becomes visible.
  • 3. Re: Locking the GUI, spinning dial (simillar to JXLayer)
    984080 Explorer
    Currently Being Moderated
    Hey,

    Your example seems correct, but I wouldn't bind anything to your cursor..
    I guess you are binding for a 'waiting' cursor.

    You can use a ProgressIndicator instead!
    private final ProgressIndicator pi = new ProgressIndicator();
    pi.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);  // a waiting sign --> not value specific
    --> add the ProgressIndicator when starting the Task
    --> remove the ProgressIndicator when ending the Task.


    Add a listener on the Task like this
    myTask.stateProperty().addListener(chlTask);
    Start the task like this:
    new Thread(myTask).start();
    Your listener will look like this:
    ChangeListener chlTask = new ChangeListener<Worker.State>() {
    @Override
    public void changed(ObservableValue<? extends State> ov, State t, State newState) {
    if (newState == Worker.State.SUCCEEDED) {
    //task succeeded
    //remove your ProgressIndicator
    }
    else{...}
    }
    Good luck!

    Edited by: FXdude on 28-jan-2013 2:10
  • 4. Re: Locking the GUI, spinning dial (simillar to JXLayer)
    shakir.gusaroff Expert
    Currently Being Moderated
    Yes. Using a progress indicator instead of a cursor is a good idea.
      
       import javafx.application.Application;
    import javafx.beans.binding.When;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.concurrent.Task;
    import javafx.concurrent.Worker.State;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.scene.Cursor;
    import javafx.scene.control.ProgressIndicator;
    
    public class TaskProgs extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            Button btn = new Button();
            btn.setText("Submit");
            btn.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println("click...");
                }
            });
    
            final StackPane root = new StackPane();
            root.getChildren().add(btn);
    
            final Scene scene = new Scene(root, 300, 250);
    
            primaryStage.setTitle("Hello World!");
            primaryStage.setScene(scene);
            primaryStage.show();
    
            Task<Integer> task = new Task<Integer>() {
                @Override
                protected Integer call() throws Exception {
                    int iterations;
                    for (iterations = 0; iterations < 10000000; iterations++) {
                        if (isCancelled()) {
                            updateMessage("Cancelled");
                            break;
                        }
                        updateMessage("Iteration " + iterations);
                        updateProgress(iterations, 10000000);
                    }
                    return iterations;
                }
            };
    
    
            final ProgressIndicator pi = new ProgressIndicator();
            pi.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);  
            scene.getRoot().mouseTransparentProperty().bind(task.runningProperty());
            Thread th = new Thread(task);
            th.start();
            
            task.stateProperty().addListener(new ChangeListener<State>() {
                public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
                    if (newValue == State.SUCCEEDED) {
                        root.getChildren().remove(pi);
                    } else if (newValue == State.RUNNING) {
                        root.getChildren().add(pi);
    
                    }
    
                }
            });
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
       

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points