Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly destroy a JDialog?

I'm currently working on an application for work that has a main JFrame that always exists. I currently have a child JDialog that shows up on a button press. This frame has a JMenu with an item to "log out of the display." I've been tasked to ensure this child JDialog goes away when the log out of the display option is pressed. When the logout occurs, the main display is set invisible via:

mainFrame.setVisible(false);

The child JDialog has the default close operation:

DISPONSE_ON_CLOSE

When the user logs back in, the first thing that's done is:

mainFrame.setVisible(true); 

When this happens, the child dialog shows back up. Looking at the JDialog Javadoc, this seems to be expected behavior. However I haven't found a way to break the parent/child releationship or completely destroy the child JDialog. It also seems like the JDialog will remain until it has been GC, which may not happen in a timely manner.

Here is a sample program that simulates the behavior I'm seeing:

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

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;

public class WindowTest { 

    public static void createAndShowGUI() {
        JFrame aFrame = new JFrame("LAUNCHER");
        final JFrame aParent = new JFrame("PARENT"); 
        final JDialog aChild = new JDialog(aParent);

        aParent.setSize(200,200);

        final JToggleButton showParentButton = new JToggleButton("HIDE");

        showParentButton.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) {
                showParentButton.setText(!showParentButton.isSelected() ? "SHOW": "HIDE");
                aParent.setVisible(!showParentButton.isSelected());
            }
        });

        aChild.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
        aChild.setSize(200,200);
        aParent.addComponentListener(new ComponentAdapter() {

            public void componentHidden(ComponentEvent e) {
                aChild.dispose(); 
                aChild.setVisible(false);
            }
        });
        aFrame.setContentPane(showParentButton);
        aFrame.pack();
        aFrame.setVisible(true);
        aParent.setVisible(true);
        aChild.setVisible(true);
    }
    public static void main(String [] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                createAndShowGUI();
            }
        });
     }
 }

When the parent is hidden, the child is disposed. When the parent is shown, the child shows back up. What's really weird is that when I press the X on the child: when the parent is hidden and then shown again, the child does not show back up.

The only difference I see is that clicking the X also fires a WindowClosing event. I tried the dispatch the even, in the componentHidden method above by:

//Added into the constructor
//add to the imports: import java.awt.event.WindowEvent;
aParent.addComponentListener(new ComponentAdapter() {

        public void componentHidden(ComponentEvent e) {
            aChild.dispose(); 
            aChild.setVisible(false); 
            WindowEvent closingEvent = 
                new WindowEvent(aChild, WindowEvent.WINDOW_CLOSING); 
            aChild.dispatchEvent(closingEvent);
        }
    });

And that didn't solve the problem.

Currently it looks like my only option is to change the type of child to a JFrame. I just wanted to know if there was a proper way of disposing a child JDialog.

I'm currently running with Java version: 1.7.0_76 64 bit on Redhat Enterprise Linux Server release 6.4.

like image 986
lordoku Avatar asked Sep 27 '22 17:09

lordoku


1 Answers

I wasn't aware the naming conventions affected the compile.

It doesn't. Conventions are done for consistency and readability and maintainability. The person who writes the code is not always the person that maintains the code. So if you want other people to read your code, especially when asking for help, follow the standards.

You can start with Java Programming Style Guidelines

I'm copying the code by hand from another screen per my companies standards.

This is a complete waste of time. There is nothing proprietary about your code. Again when you ask a question, the code should be in the form of a SSCCE so it demonstrates the problem. This allows you to remove all the unnecessary code.

it would be straight forward to figure out the imports.

Exactly, so you should do it. You want us to help you, so why should we spend the time figuring it out??? Make is as easy as possible for people to want to help you.

Adding the imports did not help. The code you posted still does not compile so I don't know if it accurately reflects the problem you are attempting to describe.

Again the point of posting code is so that we can copy/paste/compile/test. Until you post a proper SSCCE I will not provide the answer.

Edit:

From my testing, if the visibility of the child window is changed by the visibility of the parent when the parent is made non-visible, then the visibility of the child is also changed by the parent when it is made visible. So it looks like the parent is retaining the state of the child windows when the visibility changes.

So the solution is to make the child window non-visible before the parent:

showParentButton.setText(!showParentButton.isSelected() ? "SHOW": "HIDE");
aChild.setVisible(false); // add this
aParent.setVisible(!showParentButton.isSelected());

If you don't have a reference to the child window then I guess you can use the Windows.getOwnedWindows() method to access all the child windows.

Another edit:

As a hack I created a custom dialog that can't be shown again once it is disposed:

    final JDialog aChild = new JDialog(aParent)
    {
        private boolean disposed = false;

        @Override
        public void dispose()
        {
            super.dispose();
            disposed = true;
        }

        @Override
        public void show()
        {
            if (disposed)
                return;

            super.show();
        }
    };
like image 108
camickr Avatar answered Sep 30 '22 08:09

camickr