2

I have a parent window which will start another window.When the child window is started, I want it to display like a modal dialog.

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

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class ModalDialogTest {
    public void createUI(){
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        JPanel mainPanel = new JPanel();

        mainPanel.setBorder(BorderFactory.createEmptyBorder(200, 200, 200, 200));
        JButton openButton = new JButton("Open a frame");
        openButton.addActionListener(new ActionListener() { 
            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                AnotherWindow anotherWindow = new AnotherWindow();
                anotherWindow.createUI();
            }
        });
        mainPanel.add(openButton,BorderLayout.CENTER);

        frame.add(mainPanel,BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        ModalDialogTest modelDialogTest = new ModalDialogTest();
        modelDialogTest.createUI();
    }

    class AnotherWindow{
        public void createUI(){
            JFrame frame = new JFrame("Dialog");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);
            JPanel mainPanel = new JPanel();

            mainPanel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));

            JLabel label = new JLabel("I want to be a modal dialog");
            mainPanel.add(label,BorderLayout.CENTER);

            frame.add(mainPanel,BorderLayout.CENTER);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
}

The demo above describes the process of my app and the architecture is just the same.So what is the solution?

Eugene
  • 8,507
  • 3
  • 35
  • 55

3 Answers3

6

You cannot set the modality of a JFrame; the second window must be a JDialog. Therefore, change the second JFrame to a JDialog and use the method setModalityType() on it.

David Yee
  • 3,285
  • 20
  • 41
5
  1. JFrame can't be a modal, use JDialog instead

  2. don't to create a bunch of JFrames, use JDialog instead

  3. create only one JDialog, as local variable, re_use this container for another action by JDialog.getContentPane.removeAll() before JDialog.setVisible(false) is called

  4. note Top-Level Containers never will be GC'ed, all a new instances increasing used JVM memory, more details about here

Community
  • 1
  • 1
mKorbel
  • 108,320
  • 17
  • 126
  • 296
1

It's possible to make a Frame modal, but you should JDialog as standard choice. Here is an example which I've found to make a Frame modal (code is for Java 1.4 but should also work for the actual java version).

    static class EventPump implements InvocationHandler {
        Frame frame;

        public EventPump(Frame frame) {
            this.frame = frame;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return frame.isShowing() ? Boolean.TRUE : Boolean.FALSE;
        }

        // when the reflection calls in this method has to be
        // replaced once Sun provides a public API to pump events.
        public void start() throws Exception {
            final Class clazz = Class.forName("java.awt.Conditional");
            final Object conditional = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, this);
            final Method pumpMethod = Class.forName("java.awt.EventDispatchThread").getDeclaredMethod("pumpEvents", new Class[] {clazz});
            pumpMethod.setAccessible(true);
            pumpMethod.invoke(Thread.currentThread(), new Object[] {conditional});
        }
    }

    // show the given frame as modal to the specified owner.
    // NOTE: this method returns only after the modal frame is closed.
    public static void showAsModal(final Frame frame, final Frame owner) {
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                owner.setEnabled(false);
            }

            @Override
            public void windowClosed(WindowEvent e) {
                owner.setEnabled(true);
                frame.removeWindowListener(this);
            }
        });

        owner.addWindowListener(new WindowAdapter() {
            @Override
            public void windowActivated(WindowEvent e) {
                if (frame.isShowing()) {
                    frame.setExtendedState(JFrame.NORMAL);
                    frame.toFront();
                } else {
                    owner.removeWindowListener(this);
                }
            }
        });

        frame.setVisible(true);
        try {
            new EventPump(frame).start();
        } catch (final Throwable throwable) {
            throw new RuntimeException(throwable); // NOPMD
        }
    }
Sergiy Medvynskyy
  • 10,540
  • 1
  • 26
  • 43