I'm trying to do something that sounds like it should be simple.
I want to create a vertical JSplitPane where the bottom area has an
original size that is known, and the top has all the rest of the space.
I was hoping to not have to mess with setDividerLocation() or
setResizeWeight() because for either of those I have to know the
size of the top component, and in my real application that size
can change depending on the data.
Here's a sample program that I think is behaving badly. It seems
like the JSplitPane is not respecting the setMaximumSize() call
for the bottom component. It is giving the bottom component a bigger
size than its maximum.
Can somebody tell me a simple way to make the bottom component get
a fixed size, and the top component get all the rest of the size?
Thanks.
import java.awt.*;
import javax.swing.*;
class Split extends JFrame {
public static void main(String [] args) {
new Split().show();
}
Split() {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
JTextArea a1 = new JTextArea("top text area");
a1.setPreferredSize(new Dimension(300, 300));
JTextArea a2 = new JTextArea("bottom text area");
a2.setMaximumSize(new Dimension(300, 100));
JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, a1, a2);
setLayout(new BorderLayout());
add(pane, BorderLayout.CENTER);
setSize(new Dimension(300, 300));
}
}
Indeed, the setMaximumSize does not seem to work properly using a
JSplitPane. However, setMinimumSize does work, so instead of calling
setMaximumSize on your bottom component, you're forced to do it the
other way round, by calling setMinimumSize on your top component.
In most situations this works well enough, though in your situation I
agree that it would be more pleasant if you could simply call
setMaximumSize on your bottom component.
Another tip is to use setPreferredSize on both components, as this
dicates how they will be drawn initially.
Regards, Jonck
mitch - 12 May 2005 21:10 GMT
I read the Sun code for JSplitPane and it looks like they are
completely
ignoring the max sizes of the components. So I made a class that
extends
JSplitPane and it seems to do the trick. Here it is in case anyone
else
wants it, or wants to comment on it.
- Mitch
import java.awt.*;
import javax.swing.*;
class MySplitPane extends JSplitPane {
MySplitPane() {
super();
}
MySplitPane(int newOrientation) {
super(newOrientation);
}
MySplitPane(int newOrientation, boolean newContinuousLayout) {
super(newOrientation, newContinuousLayout);
}
MySplitPane(
int newOrientation, boolean newContinuousLayout,
Component newLeftComponent, Component newRightComponent)
{
super(newOrientation, newContinuousLayout, newLeftComponent,
newRightComponent);
}
MySplitPane(int newOrientation, Component newLeftComponent,
Component newRightComponent) {
super(newOrientation, newLeftComponent, newRightComponent);
}
/**
* Override this method to prevent setting a location
* that violates the maximum size of either component in the
splitter,
* if setMaximumSize() has been called.
*/
public void setDividerLocation(int requested) {
int currentLoc = getDividerLocation();
if (currentLoc == requested) {
super.setDividerLocation(requested);
return;
}
boolean growing = requested > currentLoc;
Component maxComp = growing ? getLeftComponent() :
getRightComponent();
if (maxComp == null) {
super.setDividerLocation(requested);
return;
}
Dimension maxDim = maxComp.getMaximumSize();
if (maxDim == null) {
super.setDividerLocation(requested);
return;
}
int maxCompSize = getSizeForPrimaryAxis(maxDim);
if (growing) {
if (requested > maxCompSize) {
super.setDividerLocation(maxCompSize);
return;
}
} else {
int totalSize = getSizeForPrimaryAxis(getSize());
int minPos = totalSize - maxCompSize - getDividerSize();
if (requested < minPos) {
super.setDividerLocation(minPos);
return;
}
}
super.setDividerLocation(requested);
}
/**
* If the orientation is Horizontal, the width is returned,
otherwise the height.
*/
private int getSizeForPrimaryAxis(Dimension size) {
return (getOrientation() == HORIZONTAL_SPLIT) ? size.width :
size.height;
}
}