异步控制BusyIndicator

问题描述 投票:0回答:4

显然 Eclipse/SWT 管理繁忙鼠标指示器的所有方法是

BusyIndicator.showWhile(Runnable synchronousStuffToDo)

但是,我有一个基本上面向事件的项目,其中“要做的事情”不会在连续的执行行中发生:对操作进行排序并向执行管理器提供连续回调。因此,我没有任何有意义的东西可以放入那个

synchronousStuffToDo
可运行中。

是否还有另一种方法,虽然低级且笨拙,但独立于平台异步操作繁忙指示器,这意味着两个单独的方法调用,“激活它”和“停用它”?

我应该在这个问题上添加

ProgressMonitorDialog
,因为它似乎遇到了同样的问题。是的,在
ProgressMonitorDialog#run
方法中,内部事件循环将被旋转,但 SWT 事件循环只是我的执行管理器之一,因此链仍然会被破坏。显然,如果没有这个类,我什至无法显示进度监视器,除非我从较低级别的原语重新实现。

java swt eclipse-rcp
4个回答
6
投票

您无法使用

Cursor
类来操作
BusyIndicator
。 您可以在后台运行作业时调用下面的 util 方法来显示忙碌图标
Thread

public static void imBusy(final boolean busy){

    Display.getDefault().asyncExec(new Runnable()
    {
        @Override
        public void run()
        {
            Shell shell = Display.getDefault().getActiveShell();
            if(busy){ //show Busy Cursor
                Cursor cursor = Display.getDefault().getSystemCursor(SWT.CURSOR_WAIT);          
                shell.setCursor(cursor);
            }else{  
                shell.setCursor(null);
            }   
        }
    });

}

0
投票

您的可运行程序应该等待任务完成。例如。 (在浏览器中编写的代码将无法编译 - 我忽略异常):

final Object condition = new Object();
BusyIndicator.showWhile(new Runnable() {
    public void run() {
        synchronized(condition) {
            while (!isMyTaskDoneFlag()) {
                condition.wait();
            }
        }
    }
});
doTask(new MyTask() {
    public void perform() {
        try {
            // Task logic
            ...
        } finally {
            // When done
            setMyTaskDoneFlag();
            synchronized(condition) {
                condition.notify();
            }
        }
    }
});

确保任务中的所有代码路径不要忘记解锁可运行的块。几乎相同的方法可以用于进度监视器 - 您可以唤醒您的可运行程序来更新进度监视器值。

注意:您需要确保等待的可运行程序不在 SWT 线程上执行(例如,如果在进度监视器中运行,请将

fork
设置为
true
),否则您的应用程序将变得无响应。


0
投票

我在我现在正在开发的一个较旧的 SWT 应用程序中找到了一个解决方案(我不是特别喜欢,但它有效)。它使用

BusyIndicator#showWhile
,它内部所做的同步事情是:

  1. 在后台线程中启动异步任务
  2. 循环等待后台线程完成,同时旋转 显式 SWT 事件循环:
while (!taskDone){
    if (!display.readAndDispatch() && !shell.isDisposed()) {
        display.sleep();
    }
    taskDone = //check for task progress
    //update something on the main window status bar
}

我正在尝试将其转换为更干净的东西(按照 Marko 建议的方式):

  1. 设置忙碌图标
  2. 提交后台任务
  3. 取消忙碌图标

但我不确定什么最适合更新状态栏(后台任务实际上是远程调用,因此它们的线程被阻塞,直到完成为止)。我正在考虑有一个专用线程来检测后台作业何时运行并相应地更新状态栏(更新只是一条展开的虚线,没有特定于任务的内容),但仅为此使用线程似乎有点浪费。


0
投票

11 年后(并使用更新版本的 Java),您可能会考虑使用 [Eclipse 4.33 (Q3 2024)]:

增强型期货 BusyIndicator API

BusyIndicator
类定义了以下新方法:

 static void showWhile(Future> future)

如果从

Display
线程调用,它将等待给定的
Future
完成并使用繁忙指示器提供繁忙反馈。

等待完成时,将处理待处理的 UI 事件以防止 UI 冻结。

如果当前线程没有 Display,则会调用

Future.get()
,忽略任何
ExecutionException
,并且不会显示繁忙反馈。

您的情况:

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    // assynchronousStuffToDo 
});

BusyIndicator.showWhile(future);
© www.soinside.com 2019 - 2024. All rights reserved.