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

Java 如何检测SWT对话框已打开且可见?,java,eclipse,swt,rcp,Java,Eclipse,Swt,Rcp,我有一个SWT向导对话框,有很多页面。当这个对话框第一次打开时,我必须检查一些条件,如果这些条件得到满足,我需要在新打开的对话框上显示一个弹出窗口 所以我有这个代码来监听SWT.Show事件。事件侦听器响应SWT.Show进行测试并显示消息框: final WizardDialog dialog = new WizardDialog(shell, wizard); dialog.setTitle("New Wizard"); dialog.create(); dialog.get

我有一个SWT
向导对话框
,有很多页面。当这个对话框第一次打开时,我必须检查一些条件,如果这些条件得到满足,我需要在新打开的对话框上显示一个弹出窗口

所以我有这个代码来监听
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
是不可靠的,至少在我运行它的
窗口上是如此。我还尝试在激活时将此代码放入
ShellListener
,但这甚至发生在上面的
SWT.Show
示例之前

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


Plan B是一种基于脏定时器的黑客攻击,定时器被设置为在未来触发200毫秒,并希望它在对话框可见时触发,但显然这可能会引入它自己的问题。

向导对话框上覆盖
对话框.open()
方法怎么样?被重写方法的第一行将调用
super.open()
,这将使其可见。只需将自定义代码放在
.open()
方法中


您所采取的上述方法的问题似乎是它响应了一个Show事件,该事件只是通知已请求Show,而不是对话框可见。Show事件可以很好地设计为让您知道什么时候将要显示某些内容,并在显示之前采取一些行动,正如您所经历的那样。

您可以将
PaintListener
挂接到对话框的
Composite
上,而不是挂接
SWT.Show
事件。(您可能希望在第一次执行时将其解钩。)

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

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

我知道这是一条旧线。但是,如果有人觉得它有用,我发现重写Dialog.create()而不是Dialog.open()对我很有效。

的代码可以进一步改进,方法是将
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);
    }
}
叫得太早了

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

这是因为只有在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解决了这个问题

旁白:是的,我知道这是一个老问题:-)
但这是谷歌推出的第一款,用户界面作业的提示丢失了。

100%同意,尽管我想你是想写super.open()。我不能重写Window.open()(打开对话框的方法),因为对话框被阻塞了。open()方法调用shell.open(),然后调用runEventLoop(),这是一个私有方法,在对话框被释放之前,它会一直输出消息。如果runEventLoop()受到保护,我可能会在其中插入一些东西,但因为它不是,所以我不能。目前,我使用计时器来弹出一个消息框,但显然这一点我都不喜欢。因此,如果您覆盖
窗口。打开
,在您确认对话框之前,它不会将控制权返回给您?好的,让我再考虑一下……您能通过事件传递对shell的引用,然后使用
if(!shell.isDisposed()){……您的代码……}
检测正在打开的对话框吗?(请参阅自定义对话框的示例代码,以及它如何使用
open
方法-以这种方式获取对shell的引用是否可行?)您可以关闭block-on-open,调用dialog#open,然后自己运行事件循环(
while(!Display.readAndDispatch()){Display.sleep();}
)。