Java Swing dispose() 与 setVisible(false)

Posted

技术标签:

【中文标题】Java Swing dispose() 与 setVisible(false)【英文标题】:Java Swing dispose() vs. setVisible(false) 【发布时间】:2011-12-10 12:21:14 【问题描述】:

我有一个独立的 Java 应用程序,它从数据库中获取数据并将其显示在 JTable 中。当应用程序启动时,会在 JDialog 中提示用户输入用户名/密码。输入正确的凭据后,将显示包含数据的主 JFrame。在主 JFrame 上,我有一个注销按钮,单击该按钮应关闭主 JFrame 并重新显示登录 JDialog。一切正常,除了我发现单击注销按钮时主 JFrame 并没有消失。下面是我的代码的一个小型工作示例:

Main.java:

import javax.swing.SwingUtilities;

public class Main 

    public static void main(String[] args) 
        SwingUtilities.invokeLater(new Runnable() 
            public void run() 
                new MainFrame();
            
        );
    

MainFrame.java:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MainFrame extends JFrame implements ActionListener 
    private JButton button;
    private MyDialog dialog;

    public MainFrame() 
        super("this is the JFrame");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        dialog = new MyDialog(this);
        button = new JButton("click me to hide this JFrame and display JDialog");
        button.addActionListener(this);
        add(button);
        pack();
        setVisible(true);
    

    @Override
    public void actionPerformed(ActionEvent e) 
        setVisible(false); // works when changed to dispose();
        dialog.setVisible(true);
    

MyDialog.java:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;


public class MyDialog extends JDialog implements ActionListener 
    private JFrame parentFrame;
    private JButton button;

    public MyDialog(JFrame parentFrame) 
        super(parentFrame, "this is the JDialog", true);
        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.parentFrame = parentFrame;
        button = new JButton("click me to hide JDialog and show JFrame");
        button.addActionListener(this);
        add(button);
        pack();
        setVisible(true);
    

    @Override
    public void actionPerformed(ActionEvent e) 
        setVisible(false);
        parentFrame.setVisible(true);
    

MainFrame.java 中,如果我将setVisible(false) 的行更改为dispose(),那么当我单击按钮时,JFrame 就会消失。我的问题是,为什么这适用于dispose() 而不是setVisible(false)?有没有更好的方法来组织我的代码?我是 Swing 新手,所以如果这是一个基本问题,我深表歉意。谢谢。


2011-10-19 10:26 PDT 编辑

感谢大家的帮助。我将 JDialog 更改为具有 null 父级,现在一切正常。

【问题讨论】:

如需尽快获得更好的帮助,请发帖SSCCE。 【参考方案1】:

我只会以我自己的风格给出正确的代码。它当然不是唯一的,甚至不是经过验证的最佳解决方案。

主框架上的 setVisible(false) 应该调用关闭操作,逻辑上用于主框架 EXIT_ON_CLOSE。如果对话框是主框架的子框架,则应用程序退出。

所以我将模态对话框设置为第二个顶部窗口,它有一个 (JFrame)null 作为父窗口。因此,您有一个带有两个顶部窗口的应用程序。并且每次都处理模态对话框。 我制作了模式对话框 DO_NOTHING_ON_CLOSE,因为您不希望关闭图标起作用。 因此 actionPerformed 中的 dispose()。 (如果您在任何时候都有父级,则可以使用 getOwner() 而不是将父级复制到字段中。)

public class Main 

    public static void main(String[] args) 
        SwingUtilities.invokeLater(new Runnable() 
            public void run() 
                MainFrame mainFrame = new MainFrame();
                mainFrame.actionPerformed(null);
            
        );
    



public class MainFrame extends JFrame implements ActionListener 
    private JButton button;

    public MainFrame() 
        super("this is the JFrame");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        button = new JButton("click me to hide this JFrame and display JDialog");
        button.addActionListener(this);
        add(button);
        pack();
    

    @Override
    public void actionPerformed(ActionEvent e) 
        MyDialog dialog = new MyDialog(MainFrame.this);
        dialog.setVisible(true);
        setVisible(false);
    



public class MyDialog extends JDialog implements ActionListener 
    private JButton button;
    private JFrame parentFrame;

    public MyDialog(JFrame parentFrame) 
        super((JFrame)null, "this is the JDialog", false);
        this.parentFrame = parentFrame;
        setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        button = new JButton("click me to hide JDialog and show JFrame");
        button.addActionListener(this);
        add(button);
        pack();
        setVisible(false);
    

    @Override
    public void actionPerformed(ActionEvent e) 
        parentFrame.setVisible(true);
        dispose();
    

【讨论】:

我认为 setVisible 不会调用关闭操作。它只是隐藏了框架/对话框...【参考方案2】:

查看启动 JDialog 的行:

dialog = new MyDialog(this);

您设置的框架与对话框所在的父框架相同。你看,对话框不能单独出现,它必须位于父框架之上。

所以在你的代码中,当你写的时候:

setVisible(false); // works when changed to dispose();
dialog.setVisible(true);

在第一行你告诉框架消失,然后你告诉对话框出现,这实际上告诉对话框出现在它的父框架上。由于父框架是相同的,它看起来对您保持可见。如果您删除第二行,我相信框架会消失。但是当你告诉框架处理它时,它会完全消失,因为你告诉它不仅要失去可见性,还要从内存中删除它自己。

然后,当您告诉对话框出现时,它会查找其 JFrame(已被释放),重新初始化并打开。

解决问题的方法是为 JDialog 创建一个单独的新 JFrame。然后不要使用 dispose,而只需使用 setVisible 命令。

-阿萨夫

【讨论】:

不使框架重新打开其父框架就足够了。所以,请在MyDialog() 中拨打超级电话:super(null, "this is the JDialog", false);。如果主框架被隐藏,它无论如何都不会收到有意义的输入,所以没有理由使对话框成为模态。 @Inerdia 你是对的,这也是一种选择。我忘记了用于模态的布尔值。此外,我相当肯定布尔模态已被弃用,现在首选 ModalityType 方法。 并没有真正被弃用,至少没有正式被弃用。它指定了哪个布尔值对应于哪个模态类型,所以这可能只是你喜欢哪种风格的问题。 @Inerdia 很有趣,因为如果您尝试在 Eclipse 中使用 setModal(boolean modal) 它会被标记为已弃用。 在 OS X 附带的 Java 版本中,文档中没有这样标记(@Deprecated 或相应的 javadoc 标记都没有),我没有收到编译器警告在使用 IntelliJ 的 javac 构建时,我将其归结为 Eclipse 对此有自己的看法。文档提到 setModal() 是“过时的”,所以这可能是动机。 (但他们并没有这么说构造函数。)

以上是关于Java Swing dispose() 与 setVisible(false)的主要内容,如果未能解决你的问题,请参考以下文章

如何从代码中关闭 Java Swing 应用程序

百分百用Java se写QQ项目的整体设计思想(swing)

百分百用Java se写QQ项目的整体设计思想(swing)

百分百用Java se写QQ项目的整体设计思想(swing)

百分百用Java se写QQ项目的整体设计思想(swing)

java学习路线