How to Correctly Set Minimum Sizes in Java?

user1017523 picture user1017523 · Sep 18, 2012 · Viewed 39.9k times · Source

For a GUI application I am creating in Java, I have the following:

  • A JFrame, set to have a minimum size of (300,200)
  • A JSplitPane, in which lies:
    • On the left, a JScrollPane (containing a JTree) with a minimum size of (100,0) (I only want to restrict the width to 200)
    • On the right, a JPanel with a minimum size of (200,0)

The sizing does not give me any issue under the following conditions:

  • Resizing the JSplitPane all the way to the left (to the JScrollPane's minimum size), and subsequently resize the window afterward
  • Just resizing the window, to a certain degree

The problem occurs when I move the JSplitPane too close to the right, whereupon resizing the window the JPanel in the right of the JSplitPane fails to adhere to the minimum width I set.

I attempted setting a maximum width on the JScrollPane, which did not seem to help at all.

Is there something involving maximum sizes I must do? Or perhaps there is a way to attach a Listener to one of the panels to force my desired behavior? Ultimately, I just want the right panel in the JSplitPane to never be less than 200px wide.

Here is an example with behavior I am experiencing:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;

public class ResizeTest
{
    private JFrame frame;
    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    ResizeTest window = new ResizeTest();
                    window.frame.setVisible(true);
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    public ResizeTest()
    {
        initialize();
    }
    private void initialize()
    {
        frame = new JFrame();
        frame.setMinimumSize(new Dimension(300, 200));
        frame.setBounds(100,100,450,300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new GridLayout(0, 1, 0, 0));

        JSplitPane splitPane = new JSplitPane();
        frame.getContentPane().add(splitPane);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setMinimumSize(new Dimension(100, 0));
        splitPane.setLeftComponent(scrollPane);

        JTree tree = new JTree();
        tree.setMinimumSize(new Dimension(100, 0));
        scrollPane.setViewportView(tree);

        JPanel panel = new JPanel();
        panel.setMinimumSize(new Dimension(200, 0));
        splitPane.setRightComponent(panel);
    }
}

Update:

I'm afraid I don't fully understand the point trying to be made in the proposed solutions, except for that setPreferred() and setMinimum/Maximum() are better to be avoided.

My question in response to learning this is, what are my options for restricting the JSplitPane divider outside of using these methods? MadProgrammer mentioned listening for the componentResized event, but I need just a little more clarification as to why. Am I calling setDividerLocation() in response to this event?

I apologize in advance if the appended question is meant as a separate StackOverflow question entirely, I can post another and link here if necessary.

Update 2:

Is simply not regulating how the user chooses to size the window and having the right panel in a JScrollPane a viable option? This looks to me like somewhat of a standard practice.

Answer

MadProgrammer picture MadProgrammer · Sep 19, 2012

Firstly, the method setMinimumSize is a suggestion to the LayoutManager API. A suggestion that may be ignored.

In order to be able to even come close to supporting this, you will need to use something like a ComponentListener and monitor the componentResized event.

The best solution I can think of is to use a LayoutManager that actually uses the minimum and maximum size constraints, something like GridBagLayout.

Use this on a "content" pane and place you're JSplitPane onto this (setting it's minimum and maximum size accordingly) then add the "content" pane to frame.

UPDATE

Sorry, I'm probably missing something really obvious, but I put this little test together, I hope it has some ideas that help :P

public class TestFrameSize extends JFrame {

    public TestFrameSize() throws HeadlessException {

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(600, 600);
        setLocationRelativeTo(null);

        setMinimumSize(new Dimension(250, 250));

        JLabel left = new JLabel("Left");
        JLabel right = new JLabel("Right");

        Dimension pSize = new Dimension(100, 100);
        Dimension mSize = new Dimension(25, 100);

        left.setPreferredSize(pSize);
        left.setMinimumSize(mSize);
        right.setPreferredSize(pSize);
        right.setMinimumSize(mSize);

        JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);

        JPanel content = new JPanel(new GridBagLayout());
        content.add(pane);

        setLayout(new BorderLayout());
        add(content);

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        new TestFrameSize().setVisible(true);

    }
}