javaswinglook-and-feeljinternalframemaximize-window

Maximizing JInternalFrame Windows Look and Feel maximizes all JInternalFrame


In the SSCCE below, you can see that if you maximize one of the JInternalFrames, then it maximizes them both. This only (AFAIK) happens with the "Windows" LookAndFeel (if you omit the LookAndFeel code, it works as expected).

To reproduce:

  1. Run the SSCCE below.
  2. Maximize one of the JInternalFrames.
  3. Close (X) the one you maximized
  4. Observe the other one was maximized as well.

Is there any way to stop this behavior? Is this a bug?

SSCCE:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;

class Test2 {
    public static void main(String[] args) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        JFrame frame = new JFrame();
        JDesktopPane jdp = new JDesktopPane();
        jdp.setBackground(Color.gray);
        frame.add(jdp);
        jdp.setVisible(true);
        frame.setExtendedState(frame.getExtendedState()|JFrame.MAXIMIZED_BOTH );
        frame.setVisible(true);

        JInternalFrame jiffy1 = new JInternalFrame("Jiffy1", true, true, true, true);
        jdp.add(jiffy1);
        JLabel jiffy1_label = new JLabel("Jiffy1");
        jiffy1_label.setHorizontalAlignment(SwingConstants.CENTER);
        jiffy1_label.setFont(new Font("Tahoma", 0, 50));
        jiffy1.add(jiffy1_label);
        jiffy1.setPreferredSize(new Dimension(300,300));
        jiffy1.setVisible(true);
        jiffy1.pack();
        centerJIF(jdp, jiffy1);

        JInternalFrame jiffy2 = new JInternalFrame("Jiffy2", true, true, true, true);
        jdp.add(jiffy2);
        JLabel jiffy2_label = new JLabel("Jiffy2");
        jiffy2_label.setHorizontalAlignment(SwingConstants.CENTER);
        jiffy2_label.setFont(new Font("Tahoma", 0, 50));
        jiffy2.add(jiffy2_label);
        jiffy2.setPreferredSize(new Dimension(200,200));
        jiffy2.setVisible(true);
        jiffy2.pack();
        centerJIF(jdp, jiffy2);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private static void centerJIF(JDesktopPane jdp, JInternalFrame jiffy) {
        Dimension desktopSize = jdp.getSize();
        Dimension VInternalFrameSize = jiffy.getSize();
        int width = (desktopSize.width - VInternalFrameSize.width) / 2;
        int height = (desktopSize.height - VInternalFrameSize.height) / 2;
        jiffy.setLocation(width, height);
    }
}

Solution

  • In Windows DesktopManager there's a feature (in my opinion a bug...) that maximize all frames when you maximize one frame.

    from WindowsDesktopManager.java (Java 7) from line 62

    ... 
    public void activateFrame(JInternalFrame f) {
        JInternalFrame currentFrame = currentFrameRef != null ? 
            currentFrameRef.get() : null;
        try {
            super.activateFrame(f);
            if (currentFrame != null && f != currentFrame) {
    
                // If the current frame is maximized, transfer that 
                // attribute to the frame being activated.
    
                if (currentFrame.isMaximum() &&
            (f.getClientProperty("JInternalFrame.frameType") !=
            "optionDialog") ) {
                    //Special case.  If key binding was used to select next
                    //frame instead of minimizing the icon via the minimize
                    //icon.
                    if (!currentFrame.isIcon()) {
                        currentFrame.setMaximum(false);
                        if (f.isMaximizable()) {
                            if (!f.isMaximum()) {
                                f.setMaximum(true);
                            } else if (f.isMaximum() && f.isIcon()) {
                                f.setIcon(false);
                            } else {
                                f.setMaximum(false);
                            }
                        }
                    }
                }
                if (currentFrame.isSelected()) {
                    currentFrame.setSelected(false);
                }
            }
    
            if (!f.isSelected()) {
                f.setSelected(true);
            }
        } catch (PropertyVetoException e) {}
        if (f != currentFrame) {
            currentFrameRef = new WeakReference(f);
        }
    }
    ...
    

    so you can reinstall DefaultDesktopManager instead of WindowsDesktopManager and solve the problem:

    JDesktopPane jdp = new JDesktopPane();
    jdp.setDesktopManager(new DefaultDesktopManager());