简体   繁体   中英

Java Swing dispose() vs. setVisible(false)

I have a standalone Java application that gets data from a database and displays it in a JTable . When the application starts, the user is prompted for a username/password in a JDialog . Once the correct credentials are entered, the main JFrame containing the data is displayed. On the main JFrame I have a logout button that, when clicked, should close the main JFrame and redisplay the login JDialog . Everything is mostly working except I have found that the main JFrame does not go away when the logout button is clicked. Below is a small working example of my code:

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

In MainFrame.java if I change the line that says setVisible(false) to dispose() then the JFrame goes away when I click the button. My question is, why does this work with dispose() and not with setVisible(false) ? Is there a better way for me to organize my code? I am new to Swing so I apologize if this is a basic question. Thank you.


EDITED 2011-10-19 10:26 PDT

Thank you everyone for your help. I changed the JDialog to have a null parent and now everything works as I wanted.

See the line where you initiate the JDialog:

dialog = new MyDialog(this);

You're setting the same frame as the parent frame that the dialog sits on. You see, a dialog can't appear on its own, it must sit on top of a parent frame.

So in your code, when you write:

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

In the first line you tell the frame to disappear, then you tell the dialog to appear, which really tells the dialog to appear on its parent frame. Since the parent frame is the same it looks like it stays visible to you. If you remove the second line, I'm sure the frame would disappear. But when you tell the frame to dispose, it disappears entirely because you told it not just to lose visibility, but also remove itself from memory.

Then when you tell the dialog to appear it looks for its JFrame (which has been disposed), re-initializes it and opens up.

The way to solve your problem is to make a separate new JFrame for the JDialog. Then don't use dispose and just use the setVisible command.

-Asaf

I will simply give correct code, in my own style. It certainly is not the single or even proven best solution.

setVisible(false) on the main frame should invoke the close operation, logically for a main frame EXIT_ON_CLOSE. If the dialog is a child of the main frame, then the application exits.

So I made the modal dialog a second top window, which has a (JFrame)null as parent. Hence you have an application with two top windows. And the modal dialogs are every time disposed. I made the modal dialog DO_NOTHING_ON_CLOSE, as you do not want the Close icon to function. Hence the dispose() in the actionPerformed. (If you at any time have a parent, you may use getOwner() instead of copying the parent to a field.)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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