0

I have a JPanel with a vertical BoxLayout on top of a JPanel with a null layout.

I would like the JPanel with the BoxLayout to grow as the components are being added.

See this code:

public static void main (String[] args) {
    JFrame f = new JFrame();
    f.setSize(500,500);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel total = new JPanel();
    total.setLayout(null);
    total.setSize(f.getWidth(),f.getHeight());
    total.setBackground(Color.green);
    JPanel box = new JPanel();
    box.setLocation(100,200);
    box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
    box.add(new JButton("test"));
    box.add(new JLabel("hey"));
    total.add(box);
    f.add(total);
    f.setVisible(true);
}

You will notice that no components show up.

How can I make the JPanel "box" such that the size dynamically increases as I add more components (which are added vertically).

IN ADVANCE: I need the position of "box" to be at exactly 100,200 so please do not suggest that I do not use null layout. I must use null layout. The null layout of "total" should not effect the answer to my question, which focuses on the "box" panel.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
CodeGuy
  • 28,427
  • 76
  • 200
  • 317
  • What happens currently when you add your components? I think on some event you need to add the components and repaint(). – Nickoli Roussakov Jan 12 '13 at 03:52
  • If you run the code I posted, no components show up, and calling repaint after adding the components makes no difference. – CodeGuy Jan 12 '13 at 03:52
  • 1
    Your posted code is non-runnable. No main method. – Hovercraft Full Of Eels Jan 12 '13 at 03:53
  • 2
    That is the main method code...Just toss that in a main method. (as if I needed to tell you that...) – CodeGuy Jan 12 '13 at 03:53
  • 2
    Because you've chosen to throw away (IMHO) one of the most powerful API assets Swing has to offer, you've failed to honor that job that it is responsible for doing...setting the size of the child components. – MadProgrammer Jan 12 '13 at 05:26
  • related to your problem or not: -1 for insisting on null layout - that's _always_ (to minimum of 3rd approximation, and that's veery near to 100%) the wrong thingy to do. Instead, use a suitable LayoutManager that supports the control you seem to need (f.i. MigLayout) – kleopatra Jan 12 '13 at 14:17
  • 2
    a simple LayoutManager that takes over the _sizing_ while letting you control the _locating_ is [Rob's DragLayout](http://tips4java.wordpress.com/2011/10/23/drag-layout/) – kleopatra Jan 12 '13 at 14:29

4 Answers4

9

By throwing away the layout manager, you suddenly become responsible for it's job. A job I might add, which isn't easy ...

Basically, given you example, you've failed to set the size of the child component...

JFrame f = new JFrame();
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel total = new JPanel();
total.setLayout(null);
total.setSize(f.getWidth(), f.getHeight());
total.setBackground(Color.green);

JPanel box = new JPanel();
box.setLocation(100, 200);
box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
box.add(new JButton("test"));
box.add(new JLabel("hey"));
box.setSize(100, 100);  // <-- Don't forget this..

total.add(box);
f.add(total);
f.setVisible(true);

Personally, I think your asking for trouble, but what would I know...

A better idea might be to use something like an EmptyBorder to providing padding...

enter image description here

JFrame f = new JFrame();
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel total = new JPanel(new BorderLayout());
total.setSize(f.getWidth(), f.getHeight());
total.setBackground(Color.green);
total.setBorder(new EmptyBorder(100, 200, 100, 200));

JPanel box = new JPanel();
box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
box.add(new JButton("test"));
box.add(new JLabel("hey"));

total.add(box);
f.add(total);
f.setVisible(true);

Updated with Layout Manager example

Now, if all the layout managers are failing you, you could try writing your own. This has the benefits you need from the null layout manager and the benefits of intergrating into Swing's component changing process, without the need to resort to ComponentListeners and ContainerListeners

enter image description here

JPanel total = new JPanel();
total.setLayout(new SuperAwesomeBetterThenYoursLayout());

Custom Layout Manager

public static class SuperAwesomeBetterThenYoursLayout implements LayoutManager {

    @Override
    public void addLayoutComponent(String name, Component comp) {
    }

    @Override
    public void removeLayoutComponent(Component comp) {
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        return new Dimension(100, 300);
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return new Dimension(100, 300);
    }

    @Override
    public void layoutContainer(Container parent) {
        boolean laidOut = false;
        for (Component child : parent.getComponents()) {
            if (child.isVisible() && !laidOut) {
                child.setLocation(200, 100);
                child.setSize(child.getPreferredSize());
            } else {
                child.setSize(0, 0);
            }
        }
    }
    
}

This basically represents the work you are going have to do anyway, but does it in a way that works with how Swing was designed...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 1
    +1 Great example MadProgrammer! Creating a Custom Layout manager is a bit more advanced but you did it in a very simple way, nice job. – John Jan 12 '13 at 05:58
6

Suggestions:

  • Don't use null layout, almost ever.
  • Why not give the total JPanel a BorderLayout?
  • Then add the BoxLayout using JPanel to the BorderLayout.NORTH (or also known as BorderLayout.PAGE_START) position.

Edit
You state,

IN ADVANCE: I need the position of "box" to be at exactly 100,200 so please do not suggest that I do not use null layout. I must use null layout. The null layout of "total" should not effect the answer to my question, which focuses on the "box" panel.

I think that you are once again putting needless restrictions on your program. You can place your "box" at 100, 200 easily by putting an empty border of that size around it, or by other means. But the answer is not to throw out use of the null layout.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I need the "box" panel to be at exactly that position so I must use null layout. But...the null layout should not effect the answer to my question. – CodeGuy Jan 12 '13 at 03:49
  • @CodeGuy: but you can place your "box" in a position by using borders and what-not, and yes the null layout is having a direct effect on your ability to solve your problem. – Hovercraft Full Of Eels Jan 12 '13 at 03:51
  • Think of the question independent of the null layout issue. Think of this question: "How do you make a dynamic JPanel with a vertical box layout that increases size as you add more components" – CodeGuy Jan 12 '13 at 03:55
  • @CodeGuy the reason why Hovercraft is trying to get you to not use the null layout is because it can often lead to 'flakey' behavior, JPanel was not designed to be initialized with a null layout manager. It is possible you could see symptoms which are relevant to the null layout, not to your actual question. – John Jan 12 '13 at 05:14
  • 3
    @CodeGuy As you add components to a container, the container is invalidated, causing the layout manager to called, request that it should layout its contents. Part of this is will determine the preferred, min and max lay out requirements of the container. By removing the layout manager of higher containers you've broken this process, meaning that, while the container is "trying" to grow, you're not letting it. That's the problem... – MadProgrammer Jan 12 '13 at 05:22
  • 3
    @CodeGuy _Think of this question: "How do you make a dynamic JPanel with a vertical box layout that increases size as you add more components"_ that's **exactly** what the LayoutManager is responsible for doing. If you want to waste your time on re-inventing the wheel, shrugs, be on your own: others might not be as enthusiastic wasting time and effort ... there are more interesting problems to solve ;-) – kleopatra Jan 12 '13 at 14:22
3

Off the bat, what I would change:

public static void main (String[] args) {
    JFrame f = new JFrame();
    //f.setSize(500,500);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel total = new JPanel();
    //total.setLayout(null); //<-- this is usually a bad idea, but you can keep it
    //                                if you want to specify an EXACT location
    //                                for your JPanel
    total.setPreferredSize(500, 500);
    total.setBackground(Color.green);
    JPanel box = new JPanel();
    //box.setLocation(100,200);
    box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
    box.add(new JButton("test"));
    box.add(new JLabel("hey"));
    total.add(box);
    f.add(total);
    f.pack();
    f.setVisible(true);
}

Once you have that basis, all you need to do to dynamically change the size of a JPanel is:

panel.setSize(width, heightOfComponentWithin * numberOfComponents);
container.repaint(); //<-- Im not sure if you also have to call panel.repaint(),
//                           you probably don't have to.

I would also recommend using a scroll view, just in case the JPanel starts getting out of view. Good Luck!

John
  • 3,769
  • 6
  • 30
  • 49
  • 2
    (You need to read HoverCrafts answer and the comments to realise that while your suggest is an excellent - the OP won't generally like it - Sorry - +1 from me though ;)) – MadProgrammer Jan 12 '13 at 05:33
  • along with not doing any manual sizing/locating (which the OP insists on, not your fault :-) [don't use setXXSize](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi/7229519#7229519) ;-) – kleopatra Jan 12 '13 at 14:26
2

Maybe it's because you haven't setSize for box JPanel.

Rudy Setiady
  • 76
  • 1
  • 3
  • 2
    You're right, but I would, personally, go out of my way to suggest just about anything other then this - IMHO... – MadProgrammer Jan 12 '13 at 05:32
  • 1
    to emphasize @MadProgrammer 's comment: if you need to do manual locating/sizing on anything else than a top-level container ... you are doing something wrong. – kleopatra Jan 12 '13 at 14:49