tags:

views:

1025

answers:

2

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

  1. The ModalInternal frame never goes away. I think some exception is being thrown but...
  2. 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.

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

calling close() will cause internalFrameClosing() to be called again, until the stack overflows.

Try removing that listener altogether.

objects
Thanks, I'll try this out when I get the chance. I found an alternative to modal JInternalFrames altogether, but I still want to see this work.
drhorrible
A: 

I can't quite get your code to run, but here's a simpler version, based on the Sun example, that does work -- the main frame has a button in it (taking up all the available space), but clicking the button is blocked until the internal frame has been closed.

You can see, pretty much all I did was replace the new JOptionPane().createInternalFrame() business with my own frame. My guess is that you're overcomplicating things when you try to do your own event dispatching.

Or am I missing something?

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