Closing modal JInternalFrame

I followed approach 2 of this guide , so now I have a ModalInternalFrame that blocks input to all other frames, as I wanted. However, I made one change from the example, and now I have two problems.

Edit

I deleted JOptionPane because the whole point is to show my own panel. To close it, I installed closeablein trueand added an InternalFrameListener with the same code as the JOptionPane listener example. This does not work, so I also added code at the end of doDefaultCloseAction.

Problems

  • The ModalInternal frame never disappears. I think some kind of exception throws, but ...
  • I do not see any exceptions, and I do not know where they are going. Typically, in debug mode, Eclipse stops before the exception is thrown to the UncaughtExceptionHandler, but this does not happen in this case.

Code

If my description of the problem does not help, here is my version of ModalInternalFrame. If you want more code, I can publish it as well. Forgive this for 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 found that modal dialogs fit my needs, but if anyone has an idea, I would be glad to hear that. One thing I have not tried is to wrap each method in try {} catch (Exception e) {}, which will probably help a lot.

+3
source share
5 answers

. Webby IT JInternal Frames: 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());
        }
    }
}
+2

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

, , , , Called Frame .

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

close() internalFrameClosing() , .

Try to completely remove this listener.

0
source

You can just add setClosable(true);to the constructor

-2
source

Source: https://habr.com/ru/post/1707732/


All Articles