简体   繁体   中英

How to close JOptionPane directly by closing JFrame?

I am new to learning javax.swing and have a doubt.

I have a JFrame whose defaultCloseOperation is set to EXIT_ON_CLOSE . I have another component - a JOptionPane - over the JFrame . What I want to happen is that even when the focus is on the JOptionPane message dialog, I want the program to terminate when I click the x button on the JFrame window.

So, precisely, I'm looking to bring the JFrame in focus without dismissing the JOptionPane message dialog is over it so that I can close the JFrame window and, consequently, make the program terminate.

Here is my code:

import javax.swing.*;

public class JJSS {
    public JFrame jf;

    public JJSS(){
        jf = new JFrame();

        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setSize(400, 400);
        jf.setVisible(true);
    }

    public void runMethod(){
        String str = JOptionPane.showInputDialog(jf, "Enter something...");
        str = String.valueOf(new StringBuffer(str).reverse());
        JOptionPane.showMessageDialog(jf, "Reversed: "+str, "Output", JOptionPane.PLAIN_MESSAGE);
    }

    public static void main(String[] args){
        new JJSS().runMethod();
        System.exit(0);
    }

}

With the current code, nothing happens when I click on the close button ( x ) of the JFrame window.

How do I bring the focus on the JFrame window, while the JOptionPane dialog is still on it, and terminate the program by closing the JFrame window?

Dialog modality is the key

You can't do this with a normal JOptionPane or with any modal dialog as the modality prevents the user from interacting with other components of the GUI while the dialog is displayed. You can only get this to work if you create a non-modal dialog, meaning that the JOptionPane must be created not with the JOptionPane static factory methods, but rather in a non-traditional way, using a JOptionPane constructor -- check the JOptionPane API for how to do this.

For example:

import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.*;

public class NonModalJOptionPane {

    private static void createAndShowGui() {
        JPanel panel = new JPanel();
        panel.setPreferredSize(new Dimension(400, 300));

        final JFrame frame = new JFrame("NonModalJOptionPane");

        panel.add(new JButton(new AbstractAction("Push Me") {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane optionPane = new JOptionPane("My Message", JOptionPane.PLAIN_MESSAGE);
                JDialog dialog = optionPane.createDialog(frame, "My Option");
                dialog.setModalityType(ModalityType.MODELESS); // **** key ***
                dialog.setVisible(true);
            }
        }));

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

The key to this code is here:

// create the JOptionPane using one of its constructors
JOptionPane optionPane = new JOptionPane("My Message", JOptionPane.PLAIN_MESSAGE);

// create a JDialog from it, tying it to the parent JFrame, here called "frame"
JDialog dialog = optionPane.createDialog(frame, "My Option");

// setting the modality type so that it is **not** modal
dialog.setModalityType(ModalityType.MODELESS); // **** key ***

// and then displaying it
dialog.setVisible(true);

Where I create a JOptionPane via its constructor, not via a static method, I create a JDialog and set it to be MODELESS , and then display it.


Another viable option is to create your own JDialog, making sure that you set it to being non-modal as well.

For example, you could add the following code to the code above:

panel.add(new JButton(new AbstractAction("Push Me 2 -- Using Dialog") {
    @Override
    public void actionPerformed(ActionEvent e) {
        // button that when pressed, closes the JDialog that holds it
        // similar to a JOptionPane's OK button
        JButton disposeWinBtn = new JButton(new DisposeWindowAction("OK", KeyEvent.VK_O));

        // create a bunch of JPanels, add components to them, ...
        JPanel bottomPanel = new JPanel();
        bottomPanel.add(disposeWinBtn);

        JLabel msgLabel = new JLabel("My Message");
        JPanel msgPanel = new JPanel();
        msgPanel.add(msgLabel);

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(msgPanel, BorderLayout.CENTER);
        panel.add(bottomPanel, BorderLayout.PAGE_END);

        // create a JDialog whose parent component is the main JFrame
        // and make sure that it is *****non-modal ***** <===== this is KEY *****
        JDialog dialog = new JDialog(frame, "Dialog", ModalityType.MODELESS);
        dialog.add(panel);  // add the JPanel, panel, created above, with components
        dialog.pack();  // have layout managers do their thing
        dialog.setLocationRelativeTo(frame); // center it over the main JFrame
        dialog.setVisible(true);  // and display it
    }
}));

just under where the first button is added. You'll also need the DisposeWindowAction class, that allows the button to close and dispose of the window that is displaying it (here a JDialog window):

import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class DisposeWindowAction extends AbstractAction {
    public DisposeWindowAction(String name, int mnemonic) {
        super(name);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Component component = (Component) e.getSource();
        if (component == null) {
            return;
        }
        Window win = SwingUtilities.getWindowAncestor(component);
        if (win == null) {
            return;
        }
        win.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