异步控制BusyIndi​​cator

时间:2013-06-14 19:55:49

标签: java swt eclipse-rcp

显然,所有Eclipse / SWT都在管理繁忙的鼠标指示器

BusyIndicator.showWhile(Runnable synchronousStuffToDo)

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

是否存在另一种低级且笨拙,但平台无关的异步操作繁忙指示符的方式,这意味着两个单独的方法调用,“激活它”和“停用它”?

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

3 个答案:

答案 0 :(得分: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);
            }   
        }
    });

}

答案 1 :(得分:0)

您的runnable应该等待任务完成。例如。 (用浏览器编写的代码,不会编译 - 我忽略了异常):

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();
            }
        }
    }
});

确保任务中的所有代码路径都不会忘记取消阻止runnable。几乎相同的方法可以与进度监视器一起使用 - 您可以唤醒可运行的更新进度监视器值。

注意:您需要确保在SWT线程上不执行等待runnable(例如,如果正在运行监视器,则将fork设置为true),否则您的应用程序将无响应。

答案 2 :(得分:0)

我找到了一个解决方案(我不是特别喜欢,但它有效),我现在正在研究一个较旧的SWT应用程序。它使用BusyIndicator#showWhile,其内部的同步内容是:

  1. 在后台线程中启动异步任务
  2. 循环等待后台线程完成,同时旋转 SWT事件循环显式:
  3. 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. 取消设置忙碌图标
    4. 但是我不确定更新状态栏最好的是什么(后台任务实际上是远程调用,所以他们的线程在完成之前就会被阻塞)。我想有一个专门的线程来检测后台作业何时运行并相应地更新状态栏(更新只是一个展开的虚线,没有任何特定的任务),但是使用一个线程只是为了这个似乎有点浪费。