如何检测SWT对话框是否已打开且可见?

时间:2011-09-12 12:26:01

标签: java eclipse swt rcp

我有一个包含许多页面的SWT WizardDialog。当这个对话框第一次打开时,我必须检查一些条件,如果满足这些条件,我需要在刚打开的对话框上显示一个弹出窗口。

所以我有这个代码来监听SWT.Show事件。事件监听器响应SWT.Show进行测试并显示一个消息框:

  final WizardDialog dialog = new WizardDialog(shell, wizard);
  dialog.setTitle("New Wizard");
  dialog.create();
  dialog.getShell().addListener(SWT.Show, new Listener()
  {
     private boolean firstShowing = true;

     @Override
     public void handleEvent(Event event)
     {
        if (firstShowing && someConditionExists())
        {
          MessageBox messageBox = new MessageBox(dialog.getShell(), SWT.OK
                 | SWT.ICON_WARNING);
          messageBox.setMessage("Test");
          messageBox.open();
          firstShowing = false;
        }
     }
  });
  dialog.open();

除了它太快了!调用处理程序时,该对话框不可见。在对话框可见之前出现我的消息框,只有当我关闭消息框时才会出现对话框。

很明显SWT.Show是不可靠的,至少在我运行它的Windows上。我也尝试在激活时将此代码放入ShellListener中,但这种情况甚至发生在上面的SWT.Show示例之前。

那么当对话框可见时,如何可靠地显示消息框?

Plan B是一个基于脏计时器的hack,其中一个计时器被设置为在未来200ms触发,并希望它在对话框可见时触发,但显然这可能会引入它自己的问题。

6 个答案:

答案 0 :(得分:4)

我在类似情况下使用(需要在应用程序窗口可见后调用appStarted()),如下所示。

public class App extends ApplicationWindow {

    @Override
    protected Control createContents(Composite parent) {
        // ...

        getShell().addShellListener(new ShellAdapter() {

            @Override
            public void shellActivated(ShellEvent shellevent) {
                if (!started) {
                    Shell s = (Shell) shellevent.getSource();
                    s.setVisible(true);
                    appStarted();
                    started = true;
                }
            }
        });
    }
}

也许您可以使用如下所示:

final WizardDialog dialog = new WizardDialog(shell, wizard);
dialog.setTitle("New Wizard");
dialog.create();
dialog.getShell().addShellListener(new ShellAdapter() {

    @Override
    public void shellActivated(ShellEvent shellevent) {

        if (firstShowing && someConditionExists()) {
            Shell s = (Shell) shellevent.getSource();
            s.setVisible(true);

            MessageBox messageBox = new MessageBox(dialog.getShell(), SWT.OK | SWT.ICON_WARNING);
            messageBox.setMessage("Test");
            messageBox.open();
            firstShowing = false;
        }

    }
});
dialog.open();

答案 1 :(得分:2)

您可以将SWT.Show挂钩到对话框的PaintListener,而不是挂钩Composite事件。 (你可能想在第一次执行时取消它。)

答案 2 :(得分:1)

dialog.open()课程中覆盖WizardDialog方法怎么样?重写方法的第一行将调用super.open(),这将使其可见。只需在.open()方法中添加自定义代码。

您上面采用的方法的问题似乎是它响应了Show 事件,这只是通知已请求显示,并非对话框可见即可。 Show事件可以很好地设计为让你知道什么东西即将被展示,并在你发生之前采取一些行动。

答案 3 :(得分:1)

我知道这是一个老话题。但是如果有人发现它有用,我发现重写Dialog.create()而不是Dialog.open()对我有效。

答案 4 :(得分:1)

<块引用>

太快了!

我最近也遇到了同样的麻烦。代码执行得太早 - 我的上传操作(我想在某些情况下自动启动)在页面显示之前就开始了。

出现这种情况是因为只有在 SWT.SHOW 侦听器或继承的 setVisible() 方法中的代码完成后才能显示页面。

@Override
public void setVisible(boolean visible) {
    if (visible) {
        org.eclipse.ui.progress.UIJob("Auto start the upload") {
            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
                if (isAutoStartQcUploadSelected)
                    startUpload();
                return Status.OK_STATUS;
            }
        };
        uiJob.schedule();
    }
    super.setVisible(visible);
}

org.eclipse.ui.progress.UIJob 如所描述的 FAQ_Can_I_make_a_job_run_in_the_UI_thread 已经解决了这个问题。

PS:是的,我知道这是一个老问题:-) 但它是 google 提出的第一个,缺少 UI Job 的提示。

答案 5 :(得分:0)

通过将ShellAdapter存储在变量中,可以进一步改进marioosh的代码。

首次触发侦听器时删除ShellAdapter

不再需要变量started

语句s.setVisible(true);不是必需的,因为只有在shell可见时才会触发此事件。

public class App extends ApplicationWindow {

    @Override
    protected Control createContents(Composite parent) {
        // ...
        ShellAdapter shellActivatedAdapter = new ShellAdapter() {

            @Override
            public void shellActivated(ShellEvent shellevent) {
                shellevent.getSource().removeShellListener(shellActivatedAdapter);
                appStarted();
            }
        };

        getShell().addShellListener(shellActivatedAdapter);
    }
}