Question

This code should produce a frame with 2 vertical split panes that should initialise so that the dividers are evenly placed.

However, this only works if the frame size is fixed. It seems this is because the sum of the preferred heights of the split pane is too big for my screen (1280x1024). The JFrame height reported by getSize() ends up being greater than my screen height and thus the dividers are badly placed.

How should this be done when using frame.pack()?

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class TestSplitPanels extends JPanel {


public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    TestSplitPanels tps = new TestSplitPanels();

    frame.setContentPane(tps);

    frame.pack();

    // uncomment this and the dividers are nicely positioned
    // frame.setSize(600,600);

    frame.setVisible(true);

}

public TestSplitPanels() {
    JTable jt1 = new JTable();

    JTable jt2 = new JTable();

    JTable jt3 = new JTable();

    // wrap every JTable in a scroll pane

    JScrollPane jsr1 = new JScrollPane();
    jsr1.setViewportView(jt1);

    JScrollPane jsr2 = new JScrollPane();
    jsr2.setViewportView(jt2);

    JScrollPane jsr3 = new JScrollPane();
    jsr3.setViewportView(jt3);


    final JSplitPane jsl1 = new JSplitPane();
    final JSplitPane jsl2 = new JSplitPane();

    /* 
     * Make a vertical split pane who's top component is
     * is the first scroll pane and bottom component is 
     * another scroll pane. Try to set the divider location
     * at a third of the height of the parent component,
     * when that value is known
     */
    jsl1.setOrientation(JSplitPane.VERTICAL_SPLIT);
    jsl1.setTopComponent(jsr1);
    jsl1.setBottomComponent(jsl2);
    jsl1.addAncestorListener(new BaseAncestorListener() {

        @Override
        public void ancestorAdded(AncestorEvent event) {
            jsl1.setDividerLocation(getSize().height/3);
        }
    });

    /*
     * Set components and set the divider position as before
     * for the second split pane
     */
    jsl2.setOrientation(JSplitPane.VERTICAL_SPLIT);
    jsl2.setTopComponent(jsr2);
    jsl2.setBottomComponent(jsr3);
    jsl2.addAncestorListener(new BaseAncestorListener() {

        @Override
        public void ancestorAdded(AncestorEvent event) {
            jsl2.setDividerLocation(getSize().height/3);
        }
    });

    setLayout(new BorderLayout());
    add(jsl1, BorderLayout.CENTER);

}

public static class BaseAncestorListener 
    implements AncestorListener {

    @Override
    public void ancestorAdded(AncestorEvent event) {
    }

    @Override
    public void ancestorRemoved(AncestorEvent event) {
    }

    @Override
    public void ancestorMoved(AncestorEvent event) {
    }

}

}
Was it helpful?

Solution

I used setResizeWeigth to tell the JSplitPanes how to distribute size. As a bonus, the split panes keep the even distribution even when you resize the window. They will lose the even distribution once you resize one of the panes.

Note that you do not necessarily need the AncestorListener anymore. I used it just to print out the sizes of the JScrollPanes.

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;

public class TestSplitPanels extends JPanel {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        final TestSplitPanels tps = new TestSplitPanels();
        frame.setContentPane(tps);
        frame.pack();
        frame.setVisible(true);
    }

    public TestSplitPanels() {

        JTable jt1 = new JTable();
        JTable jt2 = new JTable();
        JTable jt3 = new JTable();

        final JScrollPane jsr1 = new JScrollPane();
        final JScrollPane jsr2 = new JScrollPane();
        final JScrollPane jsr3 = new JScrollPane();

        jsr1.setViewportView(jt1);
        jsr2.setViewportView(jt2);
        jsr3.setViewportView(jt3);

        JSplitPane jsl1 = new JSplitPane();
        JSplitPane jsl2 = new JSplitPane();

        jsl1.setOrientation(JSplitPane.VERTICAL_SPLIT);
        jsl1.setTopComponent(jsr1);
        jsl1.setBottomComponent(jsl2);
        jsl1.setResizeWeight(0.33); // <-- here

        jsl2.setOrientation(JSplitPane.VERTICAL_SPLIT);
        jsl2.setTopComponent(jsr2);
        jsl2.setBottomComponent(jsr3);
        jsl2.setResizeWeight(0.5); // <-- here

        this.addAncestorListener(new BaseAncestorListener() {
            @Override
            public void ancestorMoved(AncestorEvent event) {
                System.out.println("jsr1 size: " + jsr1.getSize());
                System.out.println("jsr2 size: " + jsr2.getSize());
                System.out.println("jsr3 size: " + jsr3.getSize());
                System.out.println("----");
            }
        });

        setLayout(new BorderLayout());
        add(jsl1, BorderLayout.CENTER);
    }

    public static class BaseAncestorListener implements AncestorListener {

        @Override
        public void ancestorAdded(AncestorEvent event) {
        }

        @Override
        public void ancestorRemoved(AncestorEvent event) {
        }

        @Override
        public void ancestorMoved(AncestorEvent event) {
        }

    }
}

OTHER TIPS

jsl2.addAncestorListener(new BaseAncestorListener() {
            @Override
            public void ancestorAdded(AncestorEvent event) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        jsl2.setDividerLocation(getSize().height / 3);                    }
                });
            }
        });

You can use the method : setDividerLocation in the JSplitPaneClass

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top