简体   繁体   English

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

[英]How to dispose of SWT Shells (and Dialogs)?

What is the proper way to dispose of SWT Shells? 处置SWT外壳的正确方法是什么? I have created some Dialogs with success following the template given in the Dialog API docs. 我已经按照Dialog API文档中给出的模板成功创建了一些Dialogs。 The SWT API for Dialog says : 对话框SWT API说

The basic template for a user-defined dialog typically looks something like this: 用户定义对话框的基本模板通常如下所示:

  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; } } 

The Dialogs I have created do not have their own taskbar icon on Windows, as I would expect for a Dialog. 我创建的对话框在Windows上没有自己的任务栏图标,就像我期望的那样。 I now want to create some Shells, which if I understand correctly will receive their own taskbar entry on Windows? 现在,我想创建一些Shell,如果我理解正确,它们在Windows上收到它们自己的任务栏条目?

In contrast to the directions given in the above API docs, I have also seen an article which seems to suggest that having a while loop as shown in the API docs is the wrong way to do it. 与上述API文档中给出的说明相反,我还看到了一篇文章 ,似乎暗示API文档中显示的while循环是错误的处理方式。 The article instead suggests disposing the Shell by using the close event listener. 相反,本文建议通过使用close事件侦听器来处置Shell。

What is the correct way to dispose of SWT Shells (and while were on the topic, Dialogs as well)? 处置SWT外壳的正确方法是什么(在本主题中也包括对话框)?

Hopefully I can help explain what's going on here. 希望我能帮助解释这里发生的事情。

Dialog is basically just a convenient class to subclass, because Shell itself is not supposed to be subclassed. Dialog基本上只是子类的便捷类,因为不应将Shell本身作为子类。 You can create shells without using Dialog at all, if you want to. 如果需要,可以完全不使用Dialog来创建外壳。 In this case, your MyDialog class is a class that others can use to open the same kind of dialog repeatedly. 在这种情况下,您的MyDialog类是其他人可以用来重复打开相同类型对话框的类。

This piece of code drives the SWT event loop as long as the shell is open (clicking the close button on the shell disposes the shell by default): 只要外壳处于打开状态,这段代码就会驱动SWT事件循环(默认情况下,单击外壳上的关闭按钮将处置该外壳):

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

You have to call Display.readAndDispatch periodically to keep your SWT application from "locking up". 您必须定期调用Display.readAndDispatch以防止SWT应用程序“锁定”。 Basically it causes all of the incoming events from the operating system (keyboard and mouse events, repaint events, etc.) to be correctly processed by your application. 基本上,它会使应用程序正确处理来自操作系统的所有传入事件(键盘和鼠标事件,重绘事件等)。 readAndDispatch basically takes an event from the application's event queue and invokes the correct listeners. readAndDispatch基本上从应用程序的事件队列中获取一个事件,并调用正确的侦听器。 In an Eclipse RCP application, the workbench is normally responsible for "pumping" the event loop and you don't have to mess with it. 在Eclipse RCP应用程序中,工作台通常负责“抽取”事件循环,而您不必弄乱它。 Here's a little more info about the event loop. 这是有关事件循环的更多信息。

The purpose of "manually" pumping the event loop in this context is to prevent MyDialog.open from returning while the shell is not disposed, but still keep the application from "hanging". 在这种情况下“手动”泵送事件循环的目的是为了防止MyDialog.open在未处置外壳的情况下返回,但仍使应用程序“挂起”。 If your MyDialog.open method tried to wait for the shell to be disposed, but it didn't pump the event loop, your application would "lock up" because without the event loop running, there's no way for the shell to ever be notified that it should be disposed! 如果您的MyDialog.open方法尝试等待处置外壳程序,但没有启动事件循环,则您的应用程序将“锁定”,因为如果没有运行事件循环,就无法通知外壳程序应该将其丢弃!

You can create shells without using this pattern. 可以创建外壳而无需使用此模式。 Here's an example of a very simple SWT application that opens a ton of shells all at once and keeps running as long as at least one of them is still open (I've omitted the package declaration and imports): 这是一个非常简单的SWT应用程序的示例,该应用程序一次打开大量的shell,只要至少其中一个shell仍然打开,就保持运行(我已经省略了软件包的声明和导入):

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

Note that I add a DisposeListener to each shell so I can take some action when the shell is closed. 请注意,我向每个外壳添加了一个DisposeListener ,以便在外壳关闭时可以采取一些措施。 You can also use IShellListener to listen more directly for the close event and even actually prevent it (which you might want to do if the shell contains unsaved work, for example). 您还可以使用IShellListener来更直接地侦听close事件,甚至实际上阻止它(例如,如果shell包含未保存的工作,则可能要执行此操作)。 Here's an annoying modification to the first program that starts 5 shells and randomly prevents you from closing them: 这是对第一个程序的令人讨厌的修改,该程序启动了5个shell,并随机阻止您关闭它们:

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

Hopefully this has helped make things more clear! 希望这有助于使事情变得更清楚!


Edited to add: I'm not totally sure why you aren't getting a windows taskbar item for your shell, but I suspect it has something to do with the style flags you're passing into the shell's constructor. 编辑添加:我不完全确定为什么您的外壳没有Windows任务栏项,但是我怀疑它与您传递给外壳的构造函数的样式标志有关。 The shells in my example have no style flags and they all get a taskbar icon. 在我的示例中,shell没有样式标志,并且都具有任务栏图标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM