Reputation: 14907
I had no idea if the problem I'm facing was specific to my situation only, so I wrote a stripped-down version of what's causing my problem (with JLabel
s as a sample component).
public class InterestingBehavior {
static int direction = -4;
static final boolean useScroll = true;
static final String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
public static void main(String[] args) {
JFrame test = new JFrame("Test");
test.setSize(500, 300);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setLayout(new BoxLayout(test.getContentPane(), BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++)
test.add(useScroll ? new JScrollPane(new JLabel(longString)) : new JLabel(longString));
test.add(Box.createVerticalGlue()); //should use all available space
final int min = 300, max = 600;
new Timer(50, e -> {
int h = test.getHeight();
SwingUtilities.invokeLater(() -> test.setSize(test.getWidth(), h + direction));
direction = h == min || h == max ? -direction : direction;
}).start();
test.setVisible(true);
}
}
The frame resizes itself to show what I want/don't want. Adding JLabel
s to the BoxLayout
keeps them all at the top of the JFrame
- this is what I want, because I added vertical glue to the panel. However if I wrap the JLabel
in a JScrollPane
, it decides to automatically resize itself vertically based on the height of the JFrame
- how can I avoid this behavior and keep the scroll pane at a constant height?
The frame:
when resized, becomes
which is not what I want.
How can I keep one dimension fixed to exactly that of the child component (viewport)?
Upvotes: 4
Views: 8464
Reputation: 1421
The problem is that JScrollPane
itself grabs all space it gets. The BoxLayout fairly distributes the available space between the JScrollPanes and the vertical glue.
The solution is to limit the vertical space the JScrollPanel demands using e.g. jScrollPane.setMaxmimumSize(new Dimension(1000, 50))
.
Now, you have each ScrollPane grabbing exactly this space which leads to weird behaviour when resizing and actually needing the horizontal scrollbar painted. Therefore you may want to have a preferred size e.g. jScrollPane.setPreferredSize(new Dimension(0, 50))
, too.
Here the complete example:
static int direction = -4;
static final boolean useScroll = true;
static final String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
public static void main(String[] args) {
JFrame test = new JFrame("Test");
test.setSize(500, 300);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setLayout(new BoxLayout(test.getContentPane(), BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++) {
if(useScroll) {
JScrollPane jScrollPane = new JScrollPane(new JLabel(longString));
jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jScrollPane.setMaximumSize(new Dimension(1000, 50));
jScrollPane.setPreferredSize(new Dimension(0, 50));
test.add(jScrollPane);
} else {
test.add(new JLabel(longString));
}
}
test.add(Box.createVerticalGlue()); //should use all available space
final int min = 300, max = 600;
new Timer(50, e -> {
int h = test.getHeight();
SwingUtilities.invokeLater(() -> test.setSize(test.getWidth(), h + direction));
direction = h == min || h == max ? -direction : direction;
}).start();
test.setVisible(true);
}
Upvotes: 6