JAVAFX:为什么等待游标需要一个新线程?
JAVAFX : why wait cursor needs a new thread?
我会明白为什么
scene.setCursor(Cursor.WAIT);
long task...
scene.setCursor(Cursor.DEFAULT);
需要新线程;它适用于:
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);
为什么我不能使用同一个线程?
我:
- 将我的光标设置为等待(它进入 GUI 队列)
- 做我的长任务...(它进入 GUI 队列,但我预计光标会改变,在队列中,它在此之前执行)
- 将我的光标重置为默认值(在我的任务完成后)
所以,我的长任务没有进入 MAIN 队列?因为,如果它进入主队列,我希望它在我的 WAIT 游标首先插入队列之后执行。
为什么会出现这种行为?
没有线程,您的代码将在 FX 应用程序线程上执行。这是(有效地)负责将 UI 渲染到屏幕并处理用户输入的线程。如果您在此线程上执行一个 long-运行 任务,那么在您的 long-运行 任务完成之前,您将阻止 FX 应用程序线程的任何正常功能发生。特别是,如果你这样做
scene.setCursor(Cursor.WAIT);
longRunningTask();
scene.setCursor(Cursor.DEFAULT);
然后设置将按照您指定的顺序进行,但是在所有代码行完成之前场景不会重新渲染。因此,在您的代码完成之前,您永远不会真正看到对 UI 的任何更改 - 包括对光标的更改。下次 FX 应用程序线程有机会渲染场景时,光标设置为 Cursor.DEFAULT
,您永远不会看到等待光标。
多线程和 JavaFX 有两条基本规则(同样的规则通常适用于大多数 UI 工具包):
- 对 UI 的任何更改都必须 在 FX 应用线程
上执行
- Long-运行 进程不应 在 FX 应用程序线程上执行(因为它们会使 UI 无响应)
所以你的解决方案实际上并不正确,因为你违反了这两条规则。你应该
- 在 FX 应用程序线程上将光标设置为
WAIT
- 在后台线程上开始您的长 运行 任务
- 任务完成后,将光标设置回 FX 应用程序线程上的
DEFAULT
。
您可以使用 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();
我会明白为什么
scene.setCursor(Cursor.WAIT);
long task...
scene.setCursor(Cursor.DEFAULT);
需要新线程;它适用于:
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);
为什么我不能使用同一个线程? 我:
- 将我的光标设置为等待(它进入 GUI 队列)
- 做我的长任务...(它进入 GUI 队列,但我预计光标会改变,在队列中,它在此之前执行)
- 将我的光标重置为默认值(在我的任务完成后)
所以,我的长任务没有进入 MAIN 队列?因为,如果它进入主队列,我希望它在我的 WAIT 游标首先插入队列之后执行。 为什么会出现这种行为?
没有线程,您的代码将在 FX 应用程序线程上执行。这是(有效地)负责将 UI 渲染到屏幕并处理用户输入的线程。如果您在此线程上执行一个 long-运行 任务,那么在您的 long-运行 任务完成之前,您将阻止 FX 应用程序线程的任何正常功能发生。特别是,如果你这样做
scene.setCursor(Cursor.WAIT);
longRunningTask();
scene.setCursor(Cursor.DEFAULT);
然后设置将按照您指定的顺序进行,但是在所有代码行完成之前场景不会重新渲染。因此,在您的代码完成之前,您永远不会真正看到对 UI 的任何更改 - 包括对光标的更改。下次 FX 应用程序线程有机会渲染场景时,光标设置为 Cursor.DEFAULT
,您永远不会看到等待光标。
多线程和 JavaFX 有两条基本规则(同样的规则通常适用于大多数 UI 工具包):
- 对 UI 的任何更改都必须 在 FX 应用线程 上执行
- Long-运行 进程不应 在 FX 应用程序线程上执行(因为它们会使 UI 无响应)
所以你的解决方案实际上并不正确,因为你违反了这两条规则。你应该
- 在 FX 应用程序线程上将光标设置为
WAIT
- 在后台线程上开始您的长 运行 任务
- 任务完成后,将光标设置回 FX 应用程序线程上的
DEFAULT
。
您可以使用 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();