关闭模态JInternalFrame

时间:2009-05-06 03:01:04

标签: java swing

我按照this guide的方法2,所以现在我有一个ModalInternalFrame阻止所有其他帧的输入,就像我想要的那样。但是,我从示例中做了一处更改,现在我有两个问题。

更改

我删除了JOptionPane,因为重点是显示我自己的窗格。为了使其接近,我将closeable设置为true,并添加了一个InternalFrameListener,其代码与JOptionPane的示例侦听器相同。这不起作用,所以我还在doDefaultCloseAction的末尾添加了代码。

问题

  1. ModalInternal框架永远不会消失。我认为有些例外被抛出但是......
  2. 我看不到任何抛出的异常,我不知道他们要去哪里。通常在调试模式下,Eclipse将在UncaughtExceptionHandler发出异常之前停止,但在这种情况下不会发生这种情况。
  3. 守则

    如果我对问题的描述没有帮助,这是我的ModalInternalFrame版本。如果你想要更多代码,我也可以发布。对不起,这太长了,但我尽量让它尽可能简洁。

    public class ModalInternalFrame extends JInternalFrame {
        public ModalInternalFrame(String title, JRootPane rootPane,
                Component desktop) {
            super(title, false, true, false, false);
    
            // create opaque glass pane
            final JPanel glass = new JPanel();
            glass.setOpaque(false);
    
            // Attach mouse listeners
            MouseInputAdapter adapter = new MouseInputAdapter() { };
            glass.addMouseListener(adapter);
            glass.addMouseMotionListener(adapter);
    
            this.addInternalFrameListener(new InternalFrameListenerAdapter() {
                public void internalFrameClosed(InternalFrameEvent e) { close(); }
                public void internalFrameClosing(InternalFrameEvent e){ close(); }
            });
    
            // Change frame border
            putClientProperty("JInternalFrame.frameType", "optionDialog");
    
            // Size frame
            Dimension size = getPreferredSize();
            Dimension rootSize = desktop.getSize();
    
            setBounds((rootSize.width - size.width) / 2,
                    (rootSize.height - size.height) / 2, size.width, size.height);
            desktop.validate();
            try { setSelected(true); } 
            catch (PropertyVetoException ignored) { }
    
            glass.add(this);              // Add modal internal frame to glass pane
            rootPane.setGlassPane(glass); // Change glass pane to our panel
            glass.setVisible(true);       // Show glass pane, then modal dialog
        }
    
        private void close(){
            if (isVisible()) {
                try { setClosed(true); } 
                catch (PropertyVetoException ignored) { }
                setVisible(false);
                rootPane.getGlassPane().setVisible(false);
            }
        }
    
        @Override public void doDefaultCloseAction() {
            super.doDefaultCloseAction();
            close();
        }
    
        @Override public void setVisible(boolean flag) {
            super.setVisible(flag);
            if (flag) startModal();
            else stopModal();
        }
    
        private synchronized void startModal() {
            try {
                if (SwingUtilities.isEventDispatchThread()) {
                    EventQueue theQueue = getToolkit().getSystemEventQueue();
                    while (isVisible()) {
                        AWTEvent event = theQueue.getNextEvent();
                        Object source = event.getSource();
                        if (event instanceof ActiveEvent) {
                            ((ActiveEvent) event).dispatch();
                        } else if (source instanceof Component) {
                            ((Component) source).dispatchEvent(event);
                        } else if (source instanceof MenuComponent) {
                            ((MenuComponent) source).dispatchEvent(event);
                        } else {
                            System.err.println("Unable to dispatch: " + event);
                        }
                    }
                } else { while (isVisible()) { wait(); } }
            } catch (InterruptedException ignored) {
            }
    
        }
    
        private synchronized void stopModal() { notifyAll(); }
    
    }
    

    更新:我发现模态对话框很适合我的需求,但如果有人有想法,我会很高兴听到它。我没有尝试过的一件事是在try {} catch(Exception e){}中包装每个方法,这可能会有很大帮助。

5 个答案:

答案 0 :(得分:2)

试试这个。我是通过JInternal Frames上的Webby IT博客文章得到的:http://webbyit.blogspot.com/2011/03/managing-jinternalframes-within.html

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;

/**
 * An extended <code>JInternalFrame</code> that provides modality in a child/parent hierarchy.
 * <a href="From http://webbyit.blogspot.com/2011/03/managing-jinternalframes-within.html">source: webby it internal frames blog post</a>
 *
 * @author webbyit
 */
public class ModalityInternalFrame extends JInternalFrame {

    protected JDesktopPane desktopPane;
    protected JComponent parent;
    protected ModalityInternalFrame childFrame;
    protected JComponent focusOwner;
    private boolean wasCloseable;

    public ModalityInternalFrame() {
        init(); // here to allow netbeans to use class in gui builder
    }

    public ModalityInternalFrame(JComponent parent) {
        this(parent, null);
    }

    public ModalityInternalFrame(JComponent parent, String title) {
        this(parent, title, false);
    }

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable) {
        this(parent, title, resizable, false);
    }

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable) {
        this(parent, title, resizable, closeable, false);
    }

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable,
            boolean maximizable) {
        this(parent, title, resizable, closeable, maximizable, false);
    }

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable,
            boolean maximizable,
            boolean iconifiable) {
        super(title, resizable, closeable, maximizable, iconifiable);
        setParentFrame(parent);
        //setFocusTraversalKeysEnabled(false);
        if (parent != null && parent instanceof ModalityInternalFrame) {
            ((ModalityInternalFrame) parent).setChildFrame(ModalityInternalFrame.this);

            /*
             * set focus to the new frame and show the frame Code added by Jasir
             */
            try {
                ((ModalityInternalFrame) parent).setSelected(false);
                setSelected(true);
                setVisible(true);
            } catch (PropertyVetoException ex) {
                Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        // Add glass pane
        ModalityInternalGlassPane glassPane = new ModalityInternalGlassPane(this);
        setGlassPane(glassPane);


        // Add frame listeners
        addFrameListener();

        // Add frame veto listenr
        addFrameVetoListener();

        init();


        // calculate size and position


    }

    private void setParentFrame(JComponent parent) {
        desktopPane = JOptionPane.getDesktopPaneForComponent(parent);
        this.parent = parent == null ? JOptionPane.getDesktopPaneForComponent(parent) : parent; // default to desktop if no parent given
    }

    public JComponent getParentFrame() {
        return parent;
    }

    public void setChildFrame(ModalityInternalFrame childFrame) {
        this.childFrame = childFrame;
    }

    public ModalityInternalFrame getChildFrame() {
        return childFrame;
    }

    public boolean hasChildFrame() {
        return (childFrame != null);
    }

    protected void addFrameVetoListener() {
        addVetoableChangeListener(new VetoableChangeListener() {

            public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
                if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY)
                        && evt.getNewValue().equals(Boolean.TRUE)) {
                    if (hasChildFrame()) {
                        //childFrame.setSelected(true);
                        if (childFrame.isIcon()) {
                            childFrame.setIcon(false);
                        }
                        throw new PropertyVetoException("no!", evt);
                    }
                }
            }
        });
    }

    /**
     * Method to control the display of the glass pane, dependant on the frame
     * being active or not
     */
    protected synchronized void addFrameListener() {
        addInternalFrameListener(new InternalFrameAdapter() {

            @Override
            public void internalFrameActivated(InternalFrameEvent e) {
                if (hasChildFrame() == true) {
                    getGlassPane().setVisible(true);
                    grabFocus();
                } else {
                    getGlassPane().setVisible(false);
                }
            }

            @Override
            public void internalFrameOpened(InternalFrameEvent e) {
                getGlassPane().setVisible(false);
                try {
                    setSelected(true);
                } catch (PropertyVetoException ex) {
                    Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

            @Override
            public void internalFrameClosing(InternalFrameEvent e) {
                if (parent != null && parent instanceof ModalityInternalFrame) {
                    ((ModalityInternalFrame) parent).childClosing();
                }
            }
        });
    }

    /**
     * Method to handle child frame closing and make this frame available for
     * user input again with no glass pane visible
     */
    protected void childClosing() {
        setClosable(wasCloseable);
        getGlassPane().setVisible(false);
        if (focusOwner != null) {
            java.awt.EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    try {
                        moveToFront();
                        setSelected(true);
                        focusOwner.grabFocus();
                    } catch (PropertyVetoException ex) {
                    }
                }
            });
            focusOwner.grabFocus();
        }
        getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        setChildFrame(null);
        getDesktopPane().setSelectedFrame(this);
        System.out.println(getDesktopPane().getSelectedFrame());
    }

    /*
     * Method to handle child opening and becoming visible.
     */
    protected void childOpening() {
        // record the present focused component
        wasCloseable = isClosable();
        setClosable(false);
        focusOwner = (JComponent) getMostRecentFocusOwner();
        grabFocus();
        getGlassPane().setVisible(true);
        getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    }

    @Override
    public void show() {
        if (parent != null && parent instanceof ModalityInternalFrame) {
            // Need to inform parent its about to lose its focus due
            // to child opening
            ((ModalityInternalFrame) parent).childOpening();
        }
        calculateBounds();
        super.show();
    }

    protected void init() {
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 394, Short.MAX_VALUE));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 274, Short.MAX_VALUE));

        pack();
    }

    public void calculateBounds() {
        Dimension frameSize = getPreferredSize();
        Dimension parentSize = new Dimension();
        Dimension rootSize = new Dimension(); // size of desktop
        Point frameCoord = new Point();

        if (desktopPane != null) {
            rootSize = desktopPane.getSize(); // size of desktop
            frameCoord = SwingUtilities.convertPoint(parent, 0, 0, desktopPane);
            parentSize = parent.getSize();
        }

        //setBounds((rootSize.width - frameSize.width) / 2, (rootSize.height - frameSize.height) / 2, frameSize.width, frameSize.height);

        // We want dialog centered relative to its parent component
        int x = (parentSize.width - frameSize.width) / 2 + frameCoord.x;
        int y = (parentSize.height - frameSize.height) / 2 + frameCoord.y;

        // If possible, dialog should be fully visible
        int ovrx = x + frameSize.width - rootSize.width;
        int ovry = y + frameSize.height - rootSize.height;
        x = Math.max((ovrx > 0 ? x - ovrx : x), 0);
        y = Math.max((ovry > 0 ? y - ovry : y), 0);
        setBounds(x, y, frameSize.width, frameSize.height);
    }

    /**
     * Glass pane to overlay. Listens for mouse clicks and sets selected on
     * associated modal frame. Also if modal frame has no children make class
     * pane invisible
     */
    class ModalityInternalGlassPane extends JComponent {

        private ModalityInternalFrame modalFrame;

        public ModalityInternalGlassPane(ModalityInternalFrame frame) {
            modalFrame = frame;
            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    if (modalFrame.isSelected() == false) {
                        try {
                            modalFrame.setSelected(true);
                            if (modalFrame.hasChildFrame() == false) {
                                setVisible(false);
                            }
                        } catch (PropertyVetoException e1) {
                            //e1.printStackTrace();
                        }
                    }
                }
            });
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            g.setColor(new Color(255, 255, 255, 100));
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }
}

答案 1 :(得分:1)

我无法让你的代码运行,但这里有一个更简单的版本,基于Sun的例子,它可以工作 - 主框架中有一个按钮(占用所有可用空间),但点击按钮被阻挡,直到内部框架关闭。

你可以看到,我所做的就是用我自己的框架替换new JOptionPane().createInternalFrame()业务。我的猜测是,当你尝试进行自己的事件调度时,你会过度复杂化。

或者我错过了什么?

public class Foo {

  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setSize(600, 400);
    frame.setLocationByPlatform(true);

    JButton desktop = new JButton(new AbstractAction("Click me if you can") {
      @Override
      public void actionPerformed(ActionEvent e) {
        System.out.println("I have been clicked");
      }
    });
    frame.getContentPane().add(desktop);

    frame.setVisible(true);

    JInternalFrame modal = 
      new JInternalFrame("Modal Popup", false, true, false, false);
    JLabel popupContent = new JLabel("I am the popup");
    popupContent.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
    modal.add(popupContent);
    modal.pack();

    JPanel glass = new JPanel();
    glass.setOpaque(false);
    glass.add(modal);
    frame.setGlassPane(glass);
    glass.setVisible(true);
    modal.setVisible(true);

    modal.addInternalFrameListener(new ModalAdapter(glass));
  }
}

class ModalAdapter extends InternalFrameAdapter {
  Component glass;

  public ModalAdapter(Component glass) {
    this.glass = glass;

    // Associate dummy mouse listeners
    // Otherwise mouse events pass through
    MouseInputAdapter adapter = new MouseInputAdapter() {
    };
    glass.addMouseListener(adapter);
    glass.addMouseMotionListener(adapter);
  }

  public void internalFrameClosed(InternalFrameEvent e) {
    glass.setVisible(false);
  }
}

答案 2 :(得分:1)

我只需为项目做这件事。我所做的就是将主窗口对象传递给Jinternalframe。主对象有一个信号量,可以跟踪模态是否被锁定。关闭时,Jinternalframe(扩展名)调用主对象的信号量。非常简单。 这不是主要代码,但你明白了这个想法:

//called frame
public CallingFrame parent;
public void setParent(CallingFrame parent_){
    this.parent=parent_;
}
private void frameClosed(javax.swing.event.InternalFrameEvent evt) {
     parent.modalLocked=false; 
}

在我的情况下,应用程序使用带有图像部分的标签来调用内部框架,因此代码以

开头
 //calling frame     
 CalledFrame cf=new CalledFrame();
 cf.setParent(this); 
 cf.setVisible(true);  
 modalLoacked=true;
 private void jLabel1MouseReleased(java.awt.event.MouseEvent evt) {
    if (modalLocked)
    return;
    else// (do your things)
  }

我遵循了教程,但是当一个信号量不会让你点击任何一个区域而一个被叫帧未被关闭时,大多数都会使事情过于复杂。

答案 3 :(得分:0)

     public void internalFrameClosing(InternalFrameEvent e){ close(); }

调用close()将导致再次调用internalFrameClosing(),直到堆栈溢出。

尝试完全删除该侦听器。

答案 4 :(得分:-2)

您只需在构造函数

中添加library(GGally) ggpairs(df,upper = list(continuous = "density"), lower = list(combo = "facetdensity")) #the dataset looks like print(df) x y z w 1 0.49916998 -0.07439680 0.37731097 0.0927331640 2 0.25281542 -1.35130718 1.02680343 0.8462638556 3 0.50950876 -0.22157249 -0.71134553 -0.6137126948 4 0.28740609 -0.17460743 -0.62504812 -0.7658094835 5 0.28220492 -0.47080289 -0.33799637 -0.7032576540 6 -0.06108038 -0.49756810 0.49099505 0.5606988283 7 0.29427440 -1.14998030 0.89409384 0.5656682378 8 -0.37378096 -1.37798177 1.22424964 1.0976507702 9 0.24306941 -0.41519951 0.17502049 -0.1261603208 10 0.45686871 -0.08291032 0.75929106 0.7457002259 11 -0.16567173 -1.16855088 0.59439600 0.6410396945 12 0.22274809 -0.19632766 0.27193362 0.5532901113 13 1.25555629 0.24633499 -0.39836999 -0.5945792966 14 1.30440121 0.05595755 1.04363679 0.7379212885 15 -0.53739075 -0.01977930 0.22634275 0.4699563173 16 0.17740551 -0.56039760 -0.03278126 -0.0002523205 17 1.02873716 0.05929581 -0.74931661 -0.8830775310 18 -0.13417946 -0.60421101 -0.24532606 -0.1951831558 19 0.11552305 -0.14462104 0.28545703 -0.2527437818 20 0.71783902 -0.12285529 1.23488185 1.3224880574 即可