Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I would understand why

 scene.setCursor(Cursor.WAIT);
 long task...
 scene.setCursor(Cursor.DEFAULT);

needs new threads; it works with:

private void set_cursore_attesa(final Scene scene)
{
    Runnable r=new Runnable() {

        @Override
        public void run() {
             scene.setCursor(Cursor.WAIT);
        }
    };
    Thread t=new Thread(r);
    t.start();
}
private void set_cursore_normale(final Scene scene)
{
        Runnable r=new Runnable() {

        @Override
        public void run() {
             scene.setCursor(Cursor.DEFAULT);
        }
    };
    Thread t=new Thread(r);
    t.start();
}

in my function:
set_cursore_attesa(scene);
long task...
set_cursore_normale(scene);

why I can't use the same thread? I:

  1. set my cursor to WAIT (it goes in GUI queue)
  2. do my long task... (it goes in GUI queue but I expected that cursor changing, that is up in queue, it is executed before this)
  3. reset my cursor to DEFAULT (after my task has finished)

So, my long task doesn't go in MAIN queue? because, if it goes in main queue, I expected it's executed after my WAIT cursor that is inserted in queue first. Why this behavior?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
402 views
Welcome To Ask or Share your Answers For Others

1 Answer

Without the threads, your code is being executed on the FX Application Thread. This is the thread that is (effectively) responsible for rendering the UI to the screen and for processing user input. If you execute a long-running task on this thread, then you prevent any of the normal functionality of the FX Application Thread from occurring until your long-running task is complete. In particular, if you do

scene.setCursor(Cursor.WAIT);
longRunningTask();
scene.setCursor(Cursor.DEFAULT);

then the settings take place in the order you specify, but the scene does not get rerendered until all lines of code are complete. Hence you never actually see any changes to the UI - including the change to the cursor - until after your code is complete. The next time the FX Application Thread has an opportunity to render the scene, the cursor is set to Cursor.DEFAULT, and you never see the wait cursor.

There are two basic rules for multithreading and JavaFX (and the same rules generally apply to most UI toolkits):

  1. Any changes to the UI must be performed on the FX Application Thread
  2. Long-running processes should not be performed on the FX Application Thread (as they make the UI unresponsive)

So your solution is not actually correct, because you violate both of those rules. You should

  1. Set the cursor to WAIT on the FX Application Thread
  2. Start your long running task on a background thread
  3. When the task is complete, set the cursor back to DEFAULT, on the FX Application Thread.

You can do this using a Task:

scene.setCursor(Cursor.WAIT);
Task<Void> task = new Task<Void>() {
    @Override
    public Void call() {
        // long running task here...
        return null ;
    }
};
task.setOnSucceeded(e -> scene.setCursor(Cursor.DEFAULT));
new Thread(task).start();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...