如何处理SWT壳(和对话框)?

问题描述:

什么是处理SWT壳的正确方法?我使用Dialog API文档中给出的模板创建了一些成功的对话框。该SWT API for Dialog says如何处理SWT壳(和对话框)?

为用户自定义对话框的基本模板通常看起来是这样的 :

public class MyDialog extends Dialog { 
     Object result; 

     public MyDialog (Shell parent, int style) { 
       super (parent, style); 
     } 
     public MyDialog (Shell parent) { 
       this (parent, 0); // your default style bits go here (not the Shell's style bits) 
     } 
     public Object open() { 
       Shell parent = getParent(); 
       Shell shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); 
       shell.setText(getText()); 
       // Your code goes here (widget creation, set result, etc). 
       shell.open(); 
       Display display = parent.getDisplay(); 
       while (!shell.isDisposed()) { 
         if (!display.readAndDispatch()) display.sleep(); 
       } 
       return result; 
     } 
} 

我已经创建对话框不具有Windows自己的任务栏图标,正如我期望的一个Dialog。我现在想创建一些shell,如果我理解正确在Windows上接收他们自己的任务栏条目?

与上述API文档中给出的指示相反,我也看到an article,这似乎表明API文档中显示的具有while循环是错误的方法。该文章改为建议使用close事件侦听器来处置Shell。

什么是正确的方式处理SWT贝壳(而同时在主题上,对话框以及)?

希望我能帮忙解释一下这里发生了什么。

Dialog基本上只是一个方便的子类,因为Shell本身不应该被子类化。如果您愿意,您可以根本不使用Dialog来创建shell。在这种情况下,您的MyDialog类是其他人可以用来反复打开同一类型对话的类。

这段代码驱动SWT事件循环只要壳是开放的(点击外壳上的关闭按钮部署默认的shell):

  while (!shell.isDisposed()) { 
        if (!display.readAndDispatch()) display.sleep(); 
      } 

你必须定期调用Display.readAndDispatch保持你的SWT应用程序“锁定”。基本上它会导致您的应用程序正确处理来自操作系统的所有传入事件(键盘和鼠标事件,重绘事件等)。 readAndDispatch基本上从应用程序的事件队列中获取事件并调用正确的侦听器。在Eclipse RCP应用程序中,工作台通常负责“抽取”事件循环,而不必混淆它。 Here's a little more info about the event loop.

的目的,“手动”抽在此背景下,事件循环是防止MyDialog.open从而外壳没有设置返回,但仍然保持从“挂起”的应用程序。如果你的MyDialog.open方法试图等待shell被释放,但它没有抽取事件循环,你的应用程序将会“锁定”,因为没有事件循环运行,shell就没有办法被通知它应该处置!

可以不使用此模式创建壳。下面是打开一吨炮弹一下子一个非常简单的SWT应用程序的例子,只要其中至少有一个是仍处于打开状态继续运行(我省略了包声明和进口):

public class Shells { 
    private static int numDisposals = 0; 

    public static void main(String[] args) { 
     Display d = Display.getDefault(); 

     for (int i = 0; i < 5; i++) { 
      Shell s = new Shell(d); 
      s.open(); 
      s.addDisposeListener(new DisposeListener() { 
       @Override 
       public void widgetDisposed(DisposeEvent arg0) { 
        numDisposals++; 
       } 
      }); 
     } 

     while (numDisposals < 5) { 
      while (!d.readAndDispatch()) { 
       d.sleep(); 
      } 
     } 
    } 
} 

请注意,我为每个外壳添加一个DisposeListener,以便在关闭外壳时采取一些措施。您还可以使用IShellListener直接侦听关闭事件,甚至实际防止它(例如,如果shell包含未保存的工作,则可能需要执行此操作)。下面是一个恼人的修改到启动5个弹的第一个程序,并随机阻止您关闭它们:

public class Shells { 
    private static Random r = new Random(); 
    private static int numDisposals = 0; 

    public static void main(String[] args) { 
     Display d = Display.getDefault(); 

     for (int i = 0; i < 5; i++) { 
      Shell s = new Shell(d); 
      s.open(); 
      s.addShellListener(new ShellAdapter() { 
       @Override 
       public void shellClosed(ShellEvent e) { 
        boolean close = r.nextBoolean(); 
        if (close) { 
         System.out.println("Alright, shell closing."); 
        } else { 
         System.out.println("Try again."); 
        } 
        e.doit = close; 
       } 
      }); 
      s.addDisposeListener(new DisposeListener() { 
       @Override 
       public void widgetDisposed(DisposeEvent arg0) { 
        numDisposals++; 
       } 
      }); 
     } 

     while (numDisposals < 5) { 
      while (!d.readAndDispatch()) { 
       d.sleep(); 
      } 
     } 
    } 
} 

希望这有助于使事情更清楚!


编辑补充:我不能完全肯定,为什么你没有得到你的shell在Windows任务栏项目,但我怀疑它有话跟你传递到外壳的风格标志构造函数。我的示例中的shell没有样式标志,它们都有一个任务栏图标。

+0

感谢这非常丰富的答案。关于任务栏图标:我已将“主窗口”设置为我的对话框的父级。当您将另一个shell作为父项传递给新的shell构造函数时,那么新的shell将不会收到任务栏图标,并且新的shell始终位于其父项之上(以免被忽略)。只有显示屏作为其父母的外壳才会显示在任务栏上(Windows 7)。至少,这是我的测试所暗示的。 – Buttons840 2011-12-22 18:04:04