【问题标题】:How can a Swing WindowListener veto JFrame closingSwing WindowListener 如何否决 JFrame 关闭
【发布时间】:2011-04-16 04:24:12
【问题描述】:

我有一个框架,想在用户关闭它时提示保存文档。但如果他们取消,框架不应关闭。

frame.addWindowListener(new SaveOnCloseWindowListener(fileState));
...
public class SaveOnCloseWindowListener extends WindowAdapter {
    private final FileState fileState;

    public SaveOnCloseWindowListener(FileState fileState) {
        this.fileState = fileState;
    }

    public void windowClosing(WindowEvent e) {
        if (!fileState.onQuit())
            cancelClose();  
    }
}

FileState 查看文档是否脏。如果不是,则不执行任何操作并返回 true。如果它脏了,它会询问用户是否要保存(是/否/取消)。如果用户此时取消,它应该中止 windowClosing。

我在网上看到的所有建议都涉及显式退出windowClosing方法,从而覆盖JFrame.setDefaultCloseOperation()的使用,并复制JFrame.processWindowEvent()中的代码。

我实际上有一个肮脏的解决方案,但想看看是否有更清洁的解决方案。

干杯

【问题讨论】:

标签: java swing awt


【解决方案1】:

正确的方法是在创建窗口时将JFrame.setDefaultCloseOperation设置为DO_NOTHING_ON_CLOSE。然后在您的用户接受关闭时调用setVisible(false)dispose(),或者在不接受关闭时不执行任何操作。

JFrame.setDefaultCloseOperation 的全部目的只是为了防止需要为最简单的操作实现WindowListeners。这些默认关闭操作执行的操作非常简单。

编辑:

我已经添加了我所描述的解决方案。这假设您希望完全删除框架。

frame.setDefaultCloseOperation(setDefaultCloseOperation);
frame.addWindowListener(new SaveOnCloseWindowListener(fileState));
...

public class SaveOnCloseWindowListener extends WindowAdapter {
    private final FileState fileState;

    public SaveOnCloseWindowListener(FileState fileState) {
        this.fileState = fileState;
    }

    public void windowClosing(WindowEvent e) {
        if (fileState.onQuit())
            frame.dispose();
    }
}

【讨论】:

  • 但是我的听众需要知道所需的操作是什么。我想我可以将默认关闭操作传递给它并在 processWindowEvent 中复制代码,但这似乎很可惜。
  • 如果你的意思是用户想要的操作,那么是的。在侦听器中,您必须弹出对话框。因此,如果我正确理解了您想要什么:在您获得关闭事件之前,您不应该询问用户想要什么。
  • 确实 - 我已经编辑了这个问题,希望能更清楚地说明这一点。
  • 其实我的回答仍然适用。您给定示例所需的唯一更改是您需要在创建时调用setDefaultCloseOperation 以防止它执行任何操作。而不是取消关闭,而是在您认为需要时显式关闭窗口。
  • 阅读您的答案我确实喜欢“JFrame.setDefaultCloseOperation 的全部目的只是为了防止需要为最简单的操作实现 WindowListeners。”如果 JFrame processWindowEvent 委托给我可以调用的 processCloseOperation,这将更容易表达。
【解决方案2】:

我认为这是 Thirler 回答的合乎逻辑的表达方式,也是我试图避免的。

frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new SaveOnCloseWindowListener(fileState, JFrame.EXIT_ON_CLOSE));

public class SaveOnCloseWindowListener extends WindowAdapter {

    private final int closeOperation;
    private final Document document;

    public SaveOnCloseWindowListener(int closeOperation, Document document) {
        this.closeOperation = closeOperation;
        this.document = document;
    }

    public void windowClosing(WindowEvent e) {
        if (!document.onClose())
            doClose((Window) e.getSource());
    }

    private void doClose(Window w) {
        switch (closeOperation) {
        case JFrame.HIDE_ON_CLOSE:
            w.setVisible(false);
            break;
        case JFrame.DISPOSE_ON_CLOSE:
            w.dispose();
            break;
        case JFrame.DO_NOTHING_ON_CLOSE:
        default:
            break;
        case JFrame.EXIT_ON_CLOSE:
            System.exit(0);
            break;
        }
    }
}

【讨论】:

  • 我不喜欢这样的原因是因为它复制了JFrame中的代码,并且要求frame子类在创建窗口监听器时知道需要的操作是什么。我想我可以重写 setDefaultCloseOperation 以将操作传递给侦听器...
  • 我将使用我的意思的解决方案编辑我的答案。一般来说,你是制作 JFrame 的人,所以你知道你想要哪个关闭操作,本质上你禁用了关闭操作。
  • 我认为这就是我们不同的地方。如果用户说他们不想关闭它,我想要一个能够否决关闭它的 JFrame,但默认关闭操作是应用程序的策略,而不是框架。
【解决方案3】:

Closing an Application 可能会让您的过程更轻松。

【讨论】:

  • 谢谢,但我了解这些东西是如何工作的(自从 import com.sun.java.swing.* 以来,我一直在 Swing 中编程)。我正在尝试找到一种解决问题的优雅方法。
  • 我以为我给出了一个优雅的解决方案。它为您管理“提示”和“关闭操作”。我想我不明白你的担心是什么。
  • 我不得不承认我没有点击进入你的代码。现在我有了 - ExitAction 并没有真正退出,它关闭了活动框架,它可能会也可能不会退出应用程序。
  • 而且我无法决定是否喜欢 CloseListener 即时操作 defaultCloseOperation。这对我来说感觉不对,但我可以看到它完成了这项工作。所以谢谢,我会尽量少一点不客气的;-)
【解决方案4】:

感谢 Thirler 和 camickr 的投入。这是我的解决方案,我相信有些人会讨厌它,但避免在 JFrame 中重复逻辑,并允许客户端代码像往常一样设置默认关闭操作。

class MyFrame {        
    @Override protected void processWindowEvent(WindowEvent e) {
        try {
            super.processWindowEvent(e);
        } catch (SaveOnCloseWindowListener.VetoException x) {}
    }
}

public class SaveOnCloseWindowListener extends WindowAdapter {

    public static class VetoException extends RuntimeException {
    }

    private final DocumentController documentController;

    public SaveOnCloseWindowListener(DocumentController documentController) {
        this.documentController = documentController;
    }

    public void windowClosing(WindowEvent e) {
        if (!documentController.onClose())
            throw new VetoException();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-02
    • 2012-10-23
    • 1970-01-01
    • 2012-01-18
    • 2016-05-14
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    相关资源
    最近更新 更多