I followed approach 2 of this guide, so now I have a ModalInternalFrame that blocks input to all other frames, just as I wanted. However, I made one change from the example, and now I have two problems.
The Change
I removed the JOptionPane, because the whole point is to show my own pane. In order to make it close, I set closeable
to true
, and added an InternalFrameListener with the same code as the example's listener for the JOptionPane. That doesn't work, so I also added code at the end of doDefaultCloseAction.
The Problems
- The ModalInternal frame never goes away. I think some exception is being thrown but...
- I can't see any thrown exceptions, and I don't know where they're going. Usually when in debug mode, Eclipse will stop right before the exception is given to the UncaughtExceptionHandler, but that isn't happening in this case.
The Code
If my description of the problem doesn't help, here's my version of the ModalInternalFrame. If you want more code, I can post that as well. Sorry it's so long, but I tried to make it as concise as possible.
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(); }
}
Update: I've discovered that modal dialog boxes suit my needs fine, but if anyone does have an idea, I'd be glad to hear it. One thing I haven't tried is wrapping every method in a try {} catch (Exception e){} which would probably help a lot.