title: JDesktopPane preferred size set by content
body: <p>I have been trying to tame <a href="http://docs.oracle.com/javase/7/docs/api/javax/swing/JDesktopPane.html#constructor_summary" rel="nofollow noreferrer"><code>JDesktopPane</code></a> to work nicely with a resizable GUI &amp; a scroll pane, but am having some troubles doing so.  It seems that <em>unless the drag mode is outline,</em> the desktop pane will not resize as expected (when an internal frame is dragged beyond the edge of the desktop pane) &amp; therefore not produce scroll-bars.  </p>
  
  <p><img src="https://i.stack.imgur.com/EnDCp.gif" alt="enter image description here"></p>
  
  <p>Am I doing something very silly in this source?  Have I missed a far better approach?</p>
  
  <pre><code>import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  import javax.swing.border.EmptyBorder;
  
  public class MDIPreferredSize {
  
      public static void main(String[] args) {
          Runnable r = new Runnable() {
  
              @Override
              public void run() {
                  final JDesktopPane dt = new JDesktopPane() {
  
                      @Override
                      public Dimension getPreferredSize() {
                          Dimension prefSize = super.getPreferredSize();
                          System.out.println("prefSize: " + prefSize);
                          // inititialize the max to the first normalized bounds
                          Rectangle max = getAllFrames()[0].getNormalBounds();
                          for (JInternalFrame jif : this.getAllFrames()) {
                              max.add(jif.getNormalBounds());
                          }
                          System.out.println("maxBounds(): "
                                  + max);
                          int x1 = max.width + (max.x * 2) &lt; prefSize.width
                                  ? prefSize.width
                                  : max.width + (max.x * 2);
                          int y1 = max.height + (max.y * 2) &lt; prefSize.height
                                  ? prefSize.height
                                  : max.height + (max.y * 2);
                          System.out.println("x,y: "
                                  + x1
                                  + ","
                                  + y1);
                          return new Dimension(x1, y1);
                      }
                  };
                  dt.setAutoscrolls(true);
  
                  int xx = 5;
                  int yy = 5;
                  int vStep = 10;
                  int yStep = 22;
                  for (int ii = 0; ii &lt; 3; ii++) {
                      JInternalFrame jif = new JInternalFrame(
                              "Internal Frame " + (ii + 1),
                              true,
                              true,
                              true);
                      dt.add(jif);
                      jif.setLocation(xx, yy);
                      xx += vStep;
                      yy += yStep;
                      jif.setSize(200, 75);
                      jif.setVisible(true);
                  }
  
                  ComponentListener componentListener = new ComponentListener() {
  
                      @Override
                      public void componentResized(ComponentEvent e) {
                          e.getComponent().validate();
                      }
  
                      @Override
                      public void componentMoved(ComponentEvent e) {
                          e.getComponent().validate();
                      }
  
                      @Override
                      public void componentShown(ComponentEvent e) {
                          e.getComponent().validate();
                      }
  
                      @Override
                      public void componentHidden(ComponentEvent e) {
                          // do nothing 
                      }
                  };
                  // causes maximized internal frames to be resized..
                  dt.addComponentListener(componentListener);
  
                  final JCheckBox outLineDragMode = new JCheckBox("Outline Drag Mode");
                  ActionListener dragModeListener = new ActionListener() {
  
                      @Override
                      public void actionPerformed(ActionEvent e) {
                          if (outLineDragMode.isSelected()) {
                              dt.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
                          } else {
                              dt.setDragMode(JDesktopPane.LIVE_DRAG_MODE);
                          }
                      }
                  };
                  outLineDragMode.addActionListener(dragModeListener);
  
                  JPanel gui = new JPanel(new BorderLayout());
                  gui.add(outLineDragMode, BorderLayout.PAGE_START);
                  gui.setBorder(new EmptyBorder(2, 3, 2, 3));
                  gui.add(new JScrollPane(dt), BorderLayout.CENTER);
  
                  JFrame f = new JFrame("DTP Preferred");
                  f.add(gui);
                  // Ensures JVM closes after frame(s) closed and
                  // all non-daemon threads are finished
                  f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                  // See http://stackoverflow.com/a/7143398/418556 for demo.
                  f.setLocationByPlatform(true);
  
                  // ensures the frame is the minimum size it needs to be
                  // in order display the components within it
                  f.pack();
                  f.setMinimumSize(f.getSize());
  
                  // should be done last, to avoid flickering, moving,
                  // resizing artifacts.
                  f.setVisible(true);
  
                  printProperty("os.name");
                  printProperty("java.version");
                  printProperty("java.vendor");
              }
          };
          // Swing GUIs should be created and updated on the EDT
          // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
          SwingUtilities.invokeLater(r);
      }
  
      public static void printProperty(String name) {
          System.out.println(name + ": \t" + System.getProperty(name));
      }
  }
  </code></pre>
  
  <h2>Edit</h2>
  
  <p>Amongst the information printed, see also the 3 system properties:</p>
  
  <pre><code>os.name:    Windows 7
  java.version:   1.7.0_21
  java.vendor:    Oracle Corporation
  </code></pre>
  
  <p>Those are the values here.</p>
  
  <h2><code>MouseMotionListener</code> <em>fixed</em> code</h2>
  
  <p>Thanks to Jonathan Drapeau's suggestion of a <code>MouseListener</code>, this fixed example actually uses a <code>MouseMotionListener</code> to allow the desktop pane to be resized actively while dragging.  It might suffer some quirks beyond use of a <code>MouseListener</code> that cause problems (none yet known), if so, go back to the simpler technique of 'resize desktop pane on internal frame drop' (<code>MouseListener</code> only).</p>
  
  <pre><code>import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  import javax.swing.border.EmptyBorder;
  import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
  
  public class MDIPreferredSize {
  
      public static void main(String[] args) {
          Runnable r = new Runnable() {
  
              @Override
              public void run() {
                  final JDesktopPane dt = new JDesktopPane() {
  
                      @Override
                      public Dimension getPreferredSize() {
                          Dimension prefSize = super.getPreferredSize();
                          System.out.println("prefSize: " + prefSize);
                          // inititialize the max to the first normalized bounds
                          Rectangle max = getAllFrames()[0].getNormalBounds();
                          for (JInternalFrame jif : this.getAllFrames()) {
                              max.add(jif.getNormalBounds());
                          }
                          System.out.println("maxBounds(): "
                                  + max);
                          int x1 = max.width + (max.x * 2) &lt; prefSize.width
                                  ? prefSize.width
                                  : max.width + (max.x * 2);
                          int y1 = max.height + (max.y * 2) &lt; prefSize.height
                                  ? prefSize.height
                                  : max.height + (max.y * 2);
                          System.out.println("x,y: "
                                  + x1
                                  + ","
                                  + y1);
                          return new Dimension(x1, y1);
                      }
                  };
  
                  int xx = 5;
                  int yy = 5;
                  int vStep = 10;
                  int yStep = 22;
                  for (int ii = 0; ii &lt; 3; ii++) {
                      JInternalFrame jif = new JInternalFrame(
                              "Internal Frame " + (ii + 1),
                              true,
                              true,
                              true);
                      dt.add(jif);
                      jif.setLocation(xx, yy);
                      xx += vStep;
                      yy += yStep;
                      jif.setSize(200, 75);
                      jif.setVisible(true);
                  }
  
                  /*final MouseListener mouseListener = new MouseAdapter() {
  
                      @Override
                      public void mouseReleased(MouseEvent e) {
                          dt.revalidate();
                      }
                  };
                  */
                  final MouseMotionListener mouseMotionListener = new MouseMotionAdapter() {
  
                      @Override
                      public void mouseDragged(MouseEvent e) {
                          dt.revalidate();
                      }
                  };
                  for (JInternalFrame jif : dt.getAllFrames()) {
                      for (Component comp : jif.getComponents()) {
                          if (comp instanceof BasicInternalFrameTitlePane) {
                              //comp.addMouseListener(mouseListener);
                              comp.addMouseMotionListener(mouseMotionListener);
                          }
                      }
                  }
  
                  dt.setAutoscrolls(true);
  
  
                  final JCheckBox outLineDragMode =
                          new JCheckBox("Outline Drag Mode");
                  ActionListener dragModeListener = new ActionListener() {
  
                      @Override
                      public void actionPerformed(ActionEvent e) {
                          if (outLineDragMode.isSelected()) {
                              dt.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
                          } else {
                              dt.setDragMode(JDesktopPane.LIVE_DRAG_MODE);
                          }
                      }
                  };
                  outLineDragMode.addActionListener(dragModeListener);
  
                  JPanel gui = new JPanel(new BorderLayout());
                  gui.add(outLineDragMode, BorderLayout.PAGE_START);
                  gui.setBorder(new EmptyBorder(2, 3, 2, 3));
                  gui.add(new JScrollPane(dt), BorderLayout.CENTER);
  
                  JFrame f = new JFrame("DTP Preferred");
                  f.add(gui);
                  // Ensures JVM closes after frame(s) closed and
                  // all non-daemon threads are finished
                  f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                  // See http://stackoverflow.com/a/7143398/418556 for demo.
                  f.setLocationByPlatform(true);
  
                  // ensures the frame is the minimum size it needs to be
                  // in order display the components within it
                  f.pack();
                  f.setMinimumSize(f.getSize());
  
                  // should be done last, to avoid flickering, moving,
                  // resizing artifacts.
                  f.setVisible(true);
  
                  printProperty("os.name");
                  printProperty("java.version");
                  printProperty("java.vendor");
              }
          };
          // Swing GUIs should be created and updated on the EDT
          // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
          SwingUtilities.invokeLater(r);
      }
  
      public static void printProperty(String name) {
          System.out.println(name + ": \t" + System.getProperty(name));
      }
  }
  </code></pre>
  
  <h2>Quirks</h2>
  
  <blockquote>
    <p>It might suffer some quirks beyond use of a <code>MouseListener</code> that cause problems (none yet known).</p>
  </blockquote>
  
  <p>That was then..</p>
  
  <ol>
  <li>In full render mode, the desktop pane will grow dynamically as far as the user drags the internal frame (even off the GUI).  (Good.)  In outline mode, the container will only resize on drop, not drag.  (Less good, but at least the scroll-bars appear/disappear reliably.)</li>
  </ol>