15

I have a JSplitPane which when shown should split the pane by 50%.

Now on giving an argument of 0.5 (as suggested) to setDividerLocation, Java seems to treat it as a normal number instead of a percentage. As in, the divider, instead of going to the middle of the pane, is almost at the start of the left pane (the pane is vertically split). Any work arounds?

Goutham
  • 2,759
  • 9
  • 30
  • 36

10 Answers10

28

Am I missing something? There seem to be a lot of rather convoluted answers to this question... but I think a simple setResizeWeight(0.5) would solve the issue ... it's described in the SplitPane Tutorial

Sam Dealey
  • 371
  • 4
  • 10
  • Oh oops, I overlooked that in the comments. Thanks. Seems odd though the most popular answer didn't mention it... on a question that's 2 yrs old now. – Sam Dealey Aug 16 '11 at 03:14
17

The setDividerLocation( double ) method only works on a "realized" frame, which means after you've packed or made the frame visible.

The setDividerLocation( int ) method can be used at any time.

camickr
  • 321,443
  • 19
  • 166
  • 288
8

You can only set the split pane divider's location as a percentage when the split pane is visible. You can tap into the split pane owner's events to determine when its OK to set the divider's location. For example:

public class MyFrame extends JFrame {

  public MyFrame() {

    final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
    // ... set up the split pane, and add to the frame ...

    // Listen for the frame's "shown" event.

    addComponentListener(new ComponentAdapter() {

      @Override
      public void componentShown(ComponentEvent componentEvent) {

        // Set the divider location to 20%.
        // This works because we know the pane is visible.

        splitPane.setDividerLocation(.2);

        // Stop listening for "shown" events.

        removeComponentListener(this);
      }

    });

    pack();
  }
}
SingleShot
  • 18,821
  • 13
  • 71
  • 101
3

this fixes it:

public class JSplitPane3 extends JSplitPane {
    private boolean hasProportionalLocation = false;
    private double proportionalLocation = 0.5;
    private boolean isPainted = false;

    public void setDividerLocation(double proportionalLocation) {
        if (!isPainted) {
            hasProportionalLocation = true;
            this.proportionalLocation = proportionalLocation;
        } else {
            super.setDividerLocation(proportionalLocation);
        }
    }

    public void paint(Graphics g) {
        super.paint(g);
        if (!isPainted) {
            if (hasProportionalLocation) {
                super.setDividerLocation(proportionalLocation);
            }
            isPainted = true;
        }
    }

}
david_p
  • 5,722
  • 1
  • 32
  • 26
  • Just for clarification I have gotten it to work using only paint() and no hasProportionalLocation if I specify it manually in the code. Much shorter than this monstrosity – TheLQ Jul 09 '10 at 08:06
  • Thanks. Just came across this and it has been bugging us for ages. +1 – Andez Feb 09 '12 at 14:44
  • I've always used this approach. However, I've noticed that you do momentarily see the divider location in the wrong position before it is moved. To resolve this, rather then overriding paint(Graphics) I have taken to overriding validate() instead. – Adamski Jul 04 '12 at 11:46
2

use setResizeWeight(double);

alaster
  • 3,821
  • 3
  • 24
  • 32
2

If you're happy for the divider to move to the middle every time you resize the pane, you could add a ComponentListener and have its componentResized method call setDividerLocation(0.5).

lins314159
  • 2,510
  • 1
  • 16
  • 19
2

I found the combination of setResizeWeight and setDividerLocation invoked later provides the behavior one would expect:

_splitPane.setResizeWeight(0.5);

SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        _splitPane.setDividerLocation(0.5);
    }
});
Cord Rehn
  • 1,119
  • 14
  • 22
1

This works for me, based on Dave Rays link.

/**
 * Set JSplitPane proportional divider location
 * 
 * @param jsplitpane JSplitPane to set
 * @param proportionalLocation double <0.0; 1.0>
 */
public static void setJSplitPaneDividerLocation(final JSplitPane jsplitpane, final double proportionalLocation)
{
    if (jsplitpane.isShowing())
    {
        if (jsplitpane.getWidth() > 0 && jsplitpane.getHeight() > 0)
        {
            jsplitpane.setDividerLocation(proportionalLocation);
        }
        else
        {
            jsplitpane.addComponentListener(new ComponentAdapter()
            {
                @Override
                public void componentResized(ComponentEvent ce)
                {
                    jsplitpane.removeComponentListener(this);
                    setJSplitPaneDividerLocation(jsplitpane, proportionalLocation);
                }
            });
        }
    }
    else
    {
        jsplitpane.addHierarchyListener(new HierarchyListener()
        {
            @Override
            public void hierarchyChanged(HierarchyEvent e)
            {
                if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && jsplitpane.isShowing())
                {
                    jsplitpane.removeHierarchyListener(this);
                    setJSplitPaneDividerLocation(jsplitpane, proportionalLocation);
                }
            }
        });
    }
}
JackCY
  • 11
  • 3
0

The following in the Component with the JSplitPane does it too:

@Override
public void setVisible(final boolean b) {
    super.setVisible(b);
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            AppFrame.this.jSplitPane.setDividerLocation(0.9d);
        }

    });
}
Stephan
  • 41,764
  • 65
  • 238
  • 329
rodhel
  • 1
0

There's a solution here that is a simple function that doesn't require sub-classing or any other changes to your splitpane.

Dave Ray
  • 39,616
  • 7
  • 83
  • 82