如何实现模态对话框的效果

时间:2014-06-16 08:42:01

标签: java swing awt

我有一个父窗口,它将启动另一个窗口。当子窗口启动时,我希望它显示为模态对话框。

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

上面的演示描述了我的应用程序的过程,架构也是一样的。那么解决方案是什么?

3 个答案:

答案 0 :(得分:6)

您无法设置JFrame的模态;第二个窗口必须是JDialog。因此,请将第二个JFrame更改为JDialog并在其上使用setModalityType()方法。

答案 1 :(得分:5)

  1. JFrame无法成为模式,请改用JDialog

  2. 不要创建一堆JFrame,而是使用JDialog

  3. 只创建一个JDialog作为本地变量,在调用JDialog.getContentPane.removeAll()之前,JDialog.setVisible(false)重新使用此容器进行其他操作

  4. 注意Top-Level Containers永远不会是GC,所有新实例都会增加使用的JVM内存,more details about here

答案 2 :(得分:1)

可以制作一个Frame模态,但你应该将JDialog作为标准选择。 这是一个我发现制作Frame模式的例子(代码适用于Java 1.4,但也适用于实际的java版本。)

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