【问题标题】:How to force ImageJ to close all its windows without close event error?如何强制 ImageJ 在没有关闭事件错误的情况下关闭其所有窗口?
【发布时间】:2016-03-13 04:57:09
【问题描述】:

我正在编写一个用于图像分析的 Java 应用程序,它会在某一时刻打开 ImageJ

ImageJ ij = new ImageJ();

还会打开一个包含ImagePlus 的窗口。

现在,只要先关闭ImageJ,按下关闭按钮时ImagePlus不关闭。反之亦然,但是在这两种情况下,关闭ImageJ 后都会引发异常:

java.lang.reflect.InvocationTargetException
    at java.awt.EventQueue.invokeAndWait(EventQueue.java:1288)
    at java.awt.Window.doDispose(Window.java:1209)
    at java.awt.Window.dispose(Window.java:1147)
    at ij.ImageJ.run(ImageJ.java:784)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: null source
    at java.util.EventObject.<init>(EventObject.java:56)
    at java.awt.AWTEvent.<init>(AWTEvent.java:337)
    at java.awt.event.InvocationEvent.<init>(InvocationEvent.java:285)
    at java.awt.event.InvocationEvent.<init>(InvocationEvent.java:174)
    at sun.awt.X11.XBaseMenuWindow.dispose(XBaseMenuWindow.java:907)
    ...

我不知道这两种情况是否相关。

关于如何强制ImageJ 关闭其所有窗口的任何建议?

【问题讨论】:

    标签: java imagej


    【解决方案1】:

    异常

    在 Linux 上使用 OpenJDK 7 时会发生这种情况。例外是fixed in Java 8

    另外:请注意,该异常并不是您看到的退出问题的实际原因。

    处置问题

    ImageJ 1.x 的应用程序处理是一团糟。 (有关一些技术讨论,请参阅this news post。)它实际上主要是作为独立应用程序运行的,并且主要在exitWhenQuitting 标志设置为 true 的情况下进行测试,以便 JVM 在主窗口关闭时关闭。因此,以不同方式使用 ImageJ 会导致图像窗口挂起也就不足为奇了。

    我已经测试了各种解决方法,例如:

    ij.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(final WindowEvent e) {
            // dispose all image windows
            for (final int id : WindowManager.getIDList()) {
                final ImagePlus imp = WindowManager.getImage(id);
                if (imp == null) continue;
                final ImageWindow win = imp.getWindow();
                if (win != null) win.dispose();
            }
            // dispose all other ImageJ windows
            for (final Window w : WindowManager.getAllNonImageWindows()) {
                w.dispose();
            }
        }
    });
    

    但它们都没有像人们希望的那样工作。根据上面链接的新闻,我花了数周的时间进行开发和实验,才能在ImageJ2 中实现我们想要的退出工作。

    下面是一些使用 ImageJ2 的代码,几乎按照你想要的方式运行:

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.WindowConstants;
    
    import net.imagej.ImageJ;
    
    public class IJDispose {
    
      public static void main(final String... args) {
        final ImageJ ij = new ImageJ();
        ij.ui().showUI();
    
        final JFrame frame = new JFrame("Hello");
        final JButton b = new JButton("Close ImageJ");
        b.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(final ActionEvent e) {
            ij.getContext().dispose();
          }
        });
        frame.getContentPane().add(b);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
      }
    
    }
    

    启动后,按 Shift+B 打开 Blob 示例图像。然后单击非 ImageJ 框架中的“关闭 ImageJ”按钮。您会看到 ImageJ 主窗口图像窗口按照需要进行了处理(使用 this code from ImageJ Legacy)。

    但是,存在(至少)三个问题:

    1. 此示例未将 ij.getContext().dispose() 调用与实际的 ImageJ1 UI 窗口关闭事件挂钩。而且这样做并非易事(我说的是最近没有深入研究这段代码)。

    2. 在处理 ImageJ 以及额外的 JFrame 之后,JVM 应该关闭。实际上,我们付出了很多努力来做到这一点。但它实际上不适用于当前版本的 ImageJ,可能是由于某处的一些未处置的资源。这是一个错误。

    3. 单击 ImageJ 主窗口上的 X 会关闭整个 JVM,因为 ImageJ1 的 exitWhenQuitting 标志会得到 set to true。您可以自己将其切换回 false,但这实际上很棘手,因为与 ImageJ2 在运行时使用 Javassist 修补 ImageJ1 相关的类加载问题。

    下一个问题是:你真的需要这个工作有多严重?

    【讨论】:

    • 感谢您的提示。确实,在 Java 8 中错误消息消失了,但主要问题仍然存在。如果先关闭 ImageJ,则打开的图像是不可关闭的。知道如何解决吗?
    • 非常感谢您提供的信息丰富的回答。我可能会看看 ImageJ2 并可能替换 ImageJ1 的东西。但至少我知道这不仅仅是一个编码错误。
    猜你喜欢
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 2010-09-08
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多