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

Java 如何处理SWT外壳(和对话框)?,java,swt,eclipse-rcp,dispose,Java,Swt,Eclipse Rcp,Dispose,处理SWT外壳的正确方法是什么?我已经按照对话框API文档中给出的模板成功创建了一些对话框。委员会: 用户定义对话框的基本模板通常看起来像 像这样: public class MyDialog extends Dialog { Object result; public MyDialog (Shell parent, int style) { super (parent, style); } pu

处理SWT外壳的正确方法是什么?我已经按照对话框API文档中给出的模板成功创建了一些对话框。委员会:

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

 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上没有自己的任务栏图标,正如我所期望的那样。我现在想创建一些shell,如果我理解正确,它们将在Windows上接收自己的任务栏条目

与上述API文档中给出的方向相反,我也看到了这一点,这似乎表明使用API文档中所示的while循环是错误的做法。本文建议使用close事件侦听器来处理Shell


处理SWT外壳的正确方法是什么(在本主题中,还有对话框)?

希望我能帮助解释这里发生了什么

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

只要shell处于打开状态,这段代码就会驱动SWT事件循环(默认情况下,单击shell上的关闭按钮会处理shell):

您必须定期调用
Display.readAndDispatch
,以防止SWT应用程序“锁定”。基本上,它会使应用程序正确处理来自操作系统的所有传入事件(键盘和鼠标事件、重绘事件等)
readAndDispatch
基本上从应用程序的事件队列中获取事件并调用正确的侦听器。在EclipseRCP应用程序中,工作台通常负责“泵送”事件循环,您不必处理它

在此上下文中“手动”泵送事件循环的目的是防止
MyDialog.open
在shell未被释放时返回,但仍然防止应用程序“挂起”。如果您的
MyDialog.open
方法试图等待shell被释放,但它没有泵送事件循环,那么您的应用程序将“锁定”,因为如果没有事件循环运行,shell将永远无法得到应该被释放的通知

可以不使用此图案创建壳。下面是一个非常简单的SWT应用程序的示例,该应用程序一次打开一吨shell,只要其中至少一个shell仍然打开(我省略了包声明和导入):

希望这有助于让事情变得更清楚



编辑添加:我不完全确定为什么您的shell没有windows任务栏项,但我怀疑这与您传递到shell构造函数中的样式标志有关。我的示例中的shell没有样式标志,它们都有一个任务栏图标。

感谢您提供了这一信息丰富的答案。关于任务栏图标:我已将“主窗口”设置为对话框外壳的父窗口。当您将另一个shell作为父级传递给新shell的构造函数时,新shell将不会收到任务栏图标,并且新shell将始终位于其父级之上(以便不被忽略)。任务栏(Windows 7)上仅显示将显示器作为其父级的Shell。至少,这是我的测试所建议的。
            while (!shell.isDisposed()) {
                    if (!display.readAndDispatch()) display.sleep();
            }
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();
            }
        }
    }
}
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();
            }
        }
    }
}