Keep BoxLayout From Expanding Children
Asked Answered
M

2

6

I want to stack some JComponents vertically inside a JPanel so they stack at the top and any extra space is at the bottom. I'm using a BoxLayout. The components will each contain a JTextArea that should allow the text to wrap if necessary. So, basically, I want the height of each of these components to be the minimum necessary for displaying the (possibly wrapped) text.

Here's a contained code example of what I'm doing:

import javax.swing.*;
import java.awt.*;
public class TextAreaTester {
    public static void main(String[] args){
        new TextAreaTester();
    }
    public TextAreaTester(){
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel,BoxLayout.PAGE_AXIS));
        panel.setPreferredSize(new Dimension(100,400));
        for(int i = 0; i<3; i++){
            JPanel item = new JPanel(new BorderLayout());
            JTextArea textarea = new JTextArea("this is a line of text I want to wrap if necessary");
            textarea.setWrapStyleWord(true);
            textarea.setLineWrap(true);
            textarea.setMaximumSize( textarea.getPreferredSize() );
            item.add(textarea,BorderLayout.NORTH);
            panel.add(item);
        }
        panel.add(Box.createGlue());
        frame.add(panel);
        frame.setVisible(true);
        frame.pack();  
    }
}

The child JPanels are expanding to fill the vertical space. I tried using glue because I thought that's what glue was for, but it seems to do nothing at all. Any help?

Note: I have found questions that look almost identical, but none with answers I can apply.

Mccombs answered 23/12, 2012 at 12:14 Comment(2)
don't ever use any of the setXXSize - providing reasonable sizing hints is the exclusive task of the component itself.Nikola
@Nikola If you have some reason why I shouldn't use a method published in the API, maybe you should give it.Mccombs
G
5

One solution: nest JPanels with the outer JPanel using Borderlayout and adding the BoxLayout using JPanel to this one BorderLayout.NORTH, also known as BorderLayout.PAGE_START:

Edit for Kleopatra:

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

public class TextAreaTester {
   public static void main(String[] args) {
      new TextAreaTester();
   }

   public TextAreaTester() {
      JFrame frame = new JFrame();
      JPanel panel = new JPanel();
      panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
      // panel.setPreferredSize(new Dimension(100,400));
      for (int i = 0; i < 3; i++) {
         JPanel item = new JPanel(new BorderLayout());
         // item.setLayout(new BoxLayout(item,BoxLayout.LINE_AXIS));
         JTextArea textarea = new JTextArea(
               "this is a line of text I want to wrap if necessary", 3, 35);
         textarea.setWrapStyleWord(true);
         textarea.setLineWrap(true);
         // textarea.setMaximumSize(textarea.getPreferredSize());
         // item.setMaximumSize( item.getPreferredSize() );
         item.add(new JScrollPane(textarea), BorderLayout.NORTH);
         panel.add(item);
      }
      panel.add(Box.createGlue());

      JPanel mainPanel = new JPanel(new BorderLayout()) {
         private final int prefW = 100;
         private final int prefH = 400;

         @Override
         public Dimension getPreferredSize() {
            return new Dimension(prefW, prefH);
         }
      };
      // mainPanel.setPreferredSize(new Dimension(100, 400));
      mainPanel.add(panel, BorderLayout.PAGE_START);

      frame.add(mainPanel);
      frame.setVisible(true);
      // frame.getContentPane().add(jp);
      frame.pack();
   }
}
Guertin answered 23/12, 2012 at 12:18 Comment(6)
@kleopatra: there, ya happy?Guertin
The world is too full of programmers saying, in absolute terms, "thou shalt not ...". It's unhelpful. I was referring to kleopatra's addition to this question.Mccombs
@AdamCross: ah, I see. She and I have had a discussion on this subject many times. Her point of view is that if you override the getPreferredSize() method of a component, then it becomes an intrinsic part of that class and its objects, and outside forces can't change the preferredSize setting, and she is right. If you follow her discussions on this and other sites, you will find that her knowledge and wisdom of Swing is among the best that is out there.Guertin
better - but still a setMax left over :-)Nikola
@kleopatra: oops, didn't see that. Deleted. Question for you: What are your thoughts on JavaFX vs the future of Swing?Guertin
better not get me started on that ;-)Nikola
J
4

Alternatively, you can use Box.Filler. Just replace your call to panel.add(Box.createGlue()) with

panel.add(new Box.Filler(new Dimension(0, 0),
    new Dimension(0, Short.MAX_VALUE),
    new Dimension(0, Short.MAX_VALUE)));

If you want to achieve the same for a horizontal layout, just use Short.MAX_VALUE for width instead of height in the Dimension call.

Jurisprudent answered 6/8, 2015 at 14:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.