JDesktopPane resize

2019-04-20 21:10发布

问题:

We have a application with two JFrames with two JDesktopPanes. We need to move an internal frame from one frame to another.

The problem we have is that after we move the internalframe from first window to the second window, when we resize the fist window, the internal frame of the second window also gets resized.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyVetoException;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

class FirstFrame extends JFrame
{
  JDesktopPane desktopPane = new JDesktopPane();

  SecondFrame secondFrame;

  public FirstFrame(SecondFrame secondFrame)
  {
    this.secondFrame = secondFrame;
    setTitle("FirstFrame example");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    add(desktopPane);

    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("File");
    JMenuItem item = new JMenuItem("Move");

    item.addActionListener(new ActionListener()
    {

      @Override
      public void actionPerformed(ActionEvent actionevent)
      {
        moveFrame();
      }
    });

    menu.add(item);
    menuBar.add(menu);
    setJMenuBar(menuBar);

  }

  public void addAnInternalFrame()
  {
    JInternalFrame frame = new JInternalFrame();
    frame.setTitle("An Internal Frame");

    desktopPane.add(frame);
    frame.setVisible(true);
    frame.setMaximizable(true);
    try
    {
      frame.setSelected(true);
      frame.setMaximum(true);
    }
    catch (PropertyVetoException e)
    {
      e.printStackTrace();
    }

  }

  public void moveFrame()
  {
    JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
    desktopPane.remove(selectedFrame);
    desktopPane.repaint();

    secondFrame.addInternalFrame(selectedFrame);
  }
}

class SecondFrame extends JFrame
{
  JDesktopPane desktopPane = new JDesktopPane();

  public SecondFrame()
  {
    setTitle("SecondFrame example");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    add(desktopPane);
  }

  public void addInternalFrame(JInternalFrame frame)
  {
    desktopPane.add(frame);
  }
}

public class DesktopPaneExample
{
  public static void main(String args[]) throws PropertyVetoException
  {

    SecondFrame secondFrame = new SecondFrame();

    FirstFrame firstFrame = new FirstFrame(secondFrame);

    firstFrame.setSize(400, 400);
    firstFrame.setLocation(100, 100);
    firstFrame.setVisible(true);
    firstFrame.addAnInternalFrame();

    secondFrame.setSize(400, 400);
    secondFrame.setLocation(520, 100);
    secondFrame.setVisible(true);




  }
}

In the above sample application, to reproduce 1) click menu File>move 2) resize the first window

NOTE: This is reproducable in Java 1.7 only. I use jdk1.7.0_03.

Update: add more information

This was not reproducible on Java 1.6 (jdk1.6.0_21)

回答1:

The issue is due to Java 7's tweaking on javax.swing.plaf.basic.BasicInternalFrameUI implementation.

  • Java 1.6 Code

    public void propertyChange(PropertyChangeEvent evt) {

            if ((frame.getParent() != null) && !componentListenerAdded) {
                f.getParent().addComponentListener(componentListener);
                componentListenerAdded = true;
            } else if ((newValue == null) && componentListenerAdded) {
                if (f.getParent() != null) {
                    f.getParent()
                            .removeComponentListener(componentListener);
                }
                componentListenerAdded = false;
            }
    
  • Java 1.7 Code

    public void propertyChange(PropertyChangeEvent evt) {

            if ((frame.getParent() != null) && !componentListenerAdded) {
                f.getParent().addComponentListener(componentListener);
                componentListenerAdded = true;
            }
    

    NOTE: The else if condition was removed. This is the culprit.

I suggest you 2 options:

  • Option one

    JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
    desktopPane.remove(selectedFrame);
    desktopPane.repaint();
    
    secondFrame.updateUI(); // The magic part, less expensive execution.
    
    secondFrame.addInternalFrame(selectedFrame);
    
  • Option two

You may need to recompile javax.swing.plaf.basic.BasicInternalFrameUI.java with above "else if" condition and add to your rt.jar library's javax.swing.plaf.basic location.

I have attached the recompiled files for Java 1.7.0_25 at http://www.datafilehost.com/d/dfb7238c

Hope this helps!!!

Regards, Nilindra



回答2:

It seems as if adding the frame while in it's maximum state is the culprit. To maintain it's current size on the 1st frame over to the 2nd frame, try this:

public void moveFrame()
{
  JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
  Dimension currentSize = selectedFrame.getSize();
  try
  {
    selectedFrame.setMaximum(false);
  }
  catch (PropertyVetoException ex)
  {
    ex.printStackTrace();
  }
  selectedFrame.setSize(currentSize);

  desktopPane.remove(selectedFrame);
  desktopPane.repaint();
  secondFrame.addInternalFrame(selectedFrame);
}

EDIT:

After reading the API for Container#remove(Component c), I got this idea that seems to work:

public void moveFrame()
{
  final JInternalFrame selectedFrame = desktopPane.getSelectedFrame();

  desktopPane.remove(selectedFrame);
  desktopPane.repaint();
  SwingUtilities.updateComponentTreeUI(selectedFrame);

  SwingUtilities.invokeLater(new Runnable()
  {
    public void run()
    {
      secondFrame.addInternalFrame(selectedFrame);
    }
  });
}