关闭模态JInternalFrame

我按照本指南的第 2步,所以现在我有一个ModalInternalFrame阻止所有其他帧的输入,就像我想要的那样。 但是,我从这个例子中做了一个改变,现在我有两个问题。

改变

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

问题

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

代码

如果我对问题的描述没有帮助,这是我的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(); } } 

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

尝试这个。 我是通过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 JInternalFrame that provides modality in a child/parent hierarchy. * source: webby it internal frames blog post * * @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()); } } } 

我无法完全运行您的代码,但这是一个更简单的版本,基于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); } } 

我只需要为一个项目做这件事。 我所做的就是将主窗口对象传递给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) } 

我按照教程进行了操作,但是大多数都是过于复杂的事情,因为当一个被调用帧没有关闭时,单个信号量会做出不让你点击任何区域的技巧。

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

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

尝试完全删除该侦听器。

你可以添加setClosable(true); 在构造函数中