Java – jdesktoppane preferred size set by content
I have been trying to tame jdesktoppane and use resizable GUI & scrolling pane, but I have some trouble doing so It seems that unless the drag mode is outline, the desktop pane will not resize as expected (when the inner frame is dragged outside the edge of the desktop pane), so there will be no scroll bar
Is what I do stupid in this regard? Did I miss a better way?
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) < prefSize.width ? prefSize.width : max.width + (max.x * 2); int y1 = max.height + (max.y * 2) < 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 < 3; ii++) { JInternalFrame jif = new JInternalFrame( "Internal Frame " + (ii + 1),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 JCheck@R_698_2419@ outLineDragMode = new JCheck@R_698_2419@("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 https://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)); } }
edit
In the printed information, you can also see three system attributes:
os.name: Windows 7 java.version: 1.7.0_21 java.vendor: Oracle Corporation
These are the values here
Mousemotionlistener fixed code
Thanks to Jonathan drapeau's advice on mouselistener, this fixed example actually uses a mousemotionlistener to allow active adjustment of the desktop pane when dragging In addition to using the mouselistener that causes the problem (not yet known), it may suffer from some quirks. If so, you can go back to the simple technique of "resizing the desktop pane" on "mouselistener only"
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) < prefSize.width ? prefSize.width : max.width + (max.x * 2); int y1 = max.height + (max.y * 2) < prefSize.height ? prefSize.height : max.height + (max.y * 2); System.out.println("x,y1); } }; int xx = 5; int yy = 5; int vStep = 10; int yStep = 22; for (int ii = 0; ii < 3; ii++) { JInternalFrame jif = new JInternalFrame( "Internal Frame " + (ii + 1),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 JCheck@R_698_2419@ outLineDragMode = new JCheck@R_698_2419@("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,// 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)); } }
Quirks
That's
>In full rendering mode, the desktop pane will grow dynamically as long as the user drags the internal frame (or even GUI) (OK.) In outline mode, containers can only be resized, not dragged (not very good, but at least the scroll bar appears / disappears reliably.)
Solution
In jdesktoppane LIVE_ DRAG_ In mode, add a mouselistener in the jinternalframe Title pane to re verify that jdesktoppane is a way to obtain exactly the same behavior in each mode
final MouseListener testList = new MouseListener() { @Override public void mouseReleased(MouseEvent e) { dt.revalidate(); } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { } }; // causes maximized internal frames to be resized.. dt.addComponentListener(componentListener); for (JInternalFrame jif : dt.getAllFrames()) { for (Component comp : jif.getComponents()) { if (comp instanceof BasicInternalFrameTitlePane) { comp.addMouseListener(testList); } } } final JCheck@R_698_2419@ outLineDragMode = new JCheck@R_698_2419@("Outline Drag Mode"); ActionListener dragModeListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (outLineDragMode.isSelected()) { dt.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); for (JInternalFrame jif : dt.getAllFrames()) { for (Component comp : jif.getComponents()) { if (comp instanceof BasicInternalFrameTitlePane) { comp.removeMouseListener(testList); } } } } else { dt.setDragMode(JDesktopPane.LIVE_DRAG_MODE); for (JInternalFrame jif : dt.getAllFrames()) { for (Component comp : jif.getComponents()) { if (comp instanceof BasicInternalFrameTitlePane) { comp.addMouseListener(testList); } } } } } };
I'm at jdesktopane OUTLINE_ DRAG_ Delete them in mode because it has responded correctly