【问题标题】:How do I detect that a SWT dialog has been opened and is visible?如何检测 SWT 对话框是否已打开且可见?
【发布时间】:2011-11-15 07:31:20
【问题描述】:

我有一个 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,其中一个计时器被设置为在未来 200 毫秒内触发,并希望它在对话框可见时触发,但显然这可能会引入它自己的问题。

【问题讨论】:

    标签: java eclipse swt rcp


    【解决方案1】:

    我在类似的情况下使用(需要在应用程序窗口可见后调用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();
    

    【讨论】:

      【解决方案2】:

      而不是挂钩SWT.Show 事件,您可以通过将PaintListener 挂钩到对话框的Composite 来获得更多运气。 (您可能希望在第一次执行期间解开它。)

      【讨论】:

        【解决方案3】:

        WizardDialog 类上覆盖dialog.open() 方法怎么样?被覆盖方法的第一行将调用super.open(),这将使其可见。之后只需将您的自定义代码放在 .open() 方法中即可。

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

        【讨论】:

        • 同意 100% - 虽然我认为你的意思是写 super.open()。
        • 我无法覆盖 Window.open() (这是打开对话框的方法),因为对话框被阻塞了。 open() 方法调用 shell.open(),然后调用 runEventLoop(),这是一个私有方法,用于泵送消息直到对话框被处理掉。如果 runEventLoop() 受到保护,我可能会在其中插入一些东西,但因为它不是我不能。目前我正在使用计时器而不是弹出一个消息框,但显然这根本不是我喜欢的。
        • 那么,如果您覆盖Window.open,它不会在您确认对话框之前将控制权交还给您?好吧,让我再想一想……
        • 你能否通过事件传递一个对shell的引用,然后使用if (!shell.isDisposed()) { ...your code... }来检测对话框是否打开? (请参阅自定义对话框的示例代码,以及它如何使用 open 方法 - 以这种方式获取对 shell 的引用是否可行?)help.eclipse.org/helios/index.jsp?topic=/…
        • 您可以在打开时关闭块,调用 Dialog#open 然后自己运行事件循环 (while (! Display.readAndDispatch()) { Display.sleep(); })。
        【解决方案4】:

        我知道这是一个旧线程。但如果有人觉得它有用,我发现覆盖 Dialog.create() 而不是 Dialog.open() 对我有用。

        【讨论】:

          【解决方案5】:

          它调用得太早了!

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

          这是因为页面只能在 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.UIJobFAQ_Can_I_make_a_job_run_in_the_UI_thread 所述已解决问题。

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

          【讨论】:

            【解决方案6】:

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

            当第一次触发监听器时删除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);
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-03-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-01-24
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多