23

I'm trying to get the Layout of a JDialog of mine to fit a particular look that a program in which I'm porting to Java has, I've used several LayoutManagers before with great success yet for some reason I cannot seem to get this working at all. My goal is to have the Right (East) side of the JDialog contain a "Find Next" and "Cancel" button in a top-down order and then any extra space below so that the two buttons are always at the top of the JDialog, yet for some reason BoxLayout is continously ignoring any attempts at changing (this is where I'm lost) the width of a JButton. Code follows.

JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
cancel.setPreferredSize(new Dimension((int)findNext.getPreferredSize().getWidth(),  
    (int)cancel.getPreferredSize().getHeight()));

JPanel example = new JPanel();  
example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));  
example.add(findNext);
example.add(cancel);  
example.add(Box.createGlue());  

No matter what I try, cancel always retains it's normal size. I've tried setMinimumSize() and setMaximumSize() with the same parameters as setPreferredSize with no luck. I've even tried cancel.setPreferredSize(new Dimension(500, 500)); and the buttons height was the only thing adjusted, it STILL retained the default width it was given.

To clear up any questions, here is what it looks like (now that I've finished it) and you'll see that the "Find Next" and "Cancel" buttons are not the same size.

example image

Community
  • 1
  • 1
Brandon Buck
  • 7,177
  • 2
  • 30
  • 51
  • I added a link to the main question of the completed JDialog so you can better understand my issue. – Brandon Buck Sep 12 '10 at 01:00
  • @Tim Thank you, I was revising the code to put the relevant portion here, sorry I missed the parenthesis. – Brandon Buck Sep 12 '10 at 01:51
  • @izuriel - No problem, I just copied it over to Eclipse to play around with it a bit and noticed it was missing, so wanted to fix it for others. :) – Tim Stone Sep 12 '10 at 01:57
  • So using `setMaximumSize()` doesn't work? What version of Java are you running the program under? – Tim Stone Sep 12 '10 at 02:28
  • I'm using Java 6 Update 21 with NetBeans 6.9.1 set to test compatibility with Java 5. – Brandon Buck Sep 12 '10 at 03:06
  • 1
    @Tim I cannot say what I did wrong, perhaps it was a copy/paste issue when I copied the setPreferredSize() but adding in setMaximumSize() made it work. I can't believe it was something I overlooked, thanks for bringing that up or else I wouldn't have thought to try it again! – Brandon Buck Sep 12 '10 at 03:09
  • Glad it's working! I've gone ahead and explained what's going on under the hood that makes the difference between the two relevant, for completeness. – Tim Stone Sep 12 '10 at 03:41

6 Answers6

55

I know this is an old question but I don't really see a good explanation. So for the sake of searchers that stumble upon this I will add my two cents.

There are three methods associated with sizing components in Swing: setPreferredSize(), setMinimumSize(), and setMaximumSize(). However, the important point is that it is up to the particular layout manager being used as to whether or not it honors any of these methods.

For BoxLayout (the layout the original poster is using):

  • setMinimumSize() -- BoxLayout honors this
  • setMaximumSize() -- BoxLayout honors this
  • setPreferredSize() -- if X_AXIS is being used width is honored, if Y_AXIS is being used height is honored

The OP is using a Y_AXIS BoxLayout which is why only his height was being changed.

Update: I put together a page with this same information for all of the layout managers. Hopefully it can help some searchers out: http://thebadprogrammer.com/swing-layout-manager-sizing/

Michael
  • 2,683
  • 28
  • 30
  • 1
    Yes this is an old question, and yes my problem was solved with the previous answers given but I have to thank you so much for explaining what exactly was causing this problem. I do not know as much about the internal workings of Java as I would like and am learning rather slowly so I really do appreciate this response! Thank you! – Brandon Buck May 13 '11 at 04:06
  • 1
    +1 for the nice summary. Nitpicking: it's not the _setXX_ in that the LayoutManager honors (or not), it's the _property_ XX: components should implement something reasonable, especially for maximumSize. Some core components don't (as f.i. one-liners like textField, comboBox ... should max their height) – kleopatra Jul 09 '13 at 16:41
9

You may not want Box.createGlue(), which "grows as necessary to absorb any extra space in its container." Instead, use Box.createVerticalStrut() between the buttons, as shown below and in the ControlPanel of this simulation.

example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));
example.add(findNext);
Box.createVerticalStrut(10);
example.add(cancel);

Addendum:

adding in setMaximumSize() made it work.

This is the expected behavior for components having identical maximum widths in a vertical BoxLayout, as described in Box Layout Features. The preferred width of the container becomes that of the (equally wide) children, and the X alignment becomes irrelevant.

example.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
Dimension d = findNext.getMaximumSize();
cancel.setMaximumSize(new Dimension(d));
example.add(findNext);
example.add(cancel);
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I appreciate the response trashgod but I think you may have misunderstood the question. The only issue I'm having is that BoxLayout (at least I'm assuming this is what's doing it) is not allowing or displaying any changes to the width of the JButton cancel which I would like to make the same size as the JButton findNext. The Box.createGlue(); is there for the purpose it was intended for, to take up all the space below the two buttons which would keep the buttons at the top of the JDialog. – Brandon Buck Sep 12 '10 at 00:45
  • @izuriel: Quite right, I misread; sorry. I've added my understanding of why `setMaximumSize()` works. – trashgod Sep 12 '10 at 04:10
  • Again, thanks for the response, your description along with Tim's has helped me understand the issue that I was having and I appreciate it all. – Brandon Buck Sep 12 '10 at 04:42
4

As mentioned in the comments on the question, you were able to fix it by switching to setMaximumSize(). However, as you noted, setPreferredSize() doesn't work. So, what's up with that?

With many things Swing, the properties used to determine the actual component size when using the BoxLayout are somewhat random (in my opinion). When determining how to render the components, Swing calls layoutComponent() on the layout manager, which is figures out where to position everything.

BoxLayout's implementation of layoutComponent() involves a call to a method that creates SizeRequirements objects for the width and height of each of the components you add to the JPanel, based on their getMinimum/Preferred/MaximumSize() methods.

Later, it calls SizeRequirements.calculateAlignedPositions() for determining the correct width values for each component, because your orientation is BoxLayout.Y_AXIS (The heights are calculated using a different method). Taking snippets from the source, the relevant implementation of this method is as follows:

for (int i = 0; i < children.length; i++) {
    SizeRequirements req = children[i];
    //...
    int maxAscent = (int)(req.maximum * alignment);
    int maxDescent = req.maximum - maxAscent;
    //...
    int descent = Math.min(totalDescent, maxDescent);
    //...
    spans[i] = (int)Math.min((long) ascent + (long)descent, Integer.MAX_VALUE);
}

Note that totalDescent is the available width, so descent is always set to maxDescent, which is based on SizeRequirements.maximum, which was taken from JButton.getMaximumSize(). The value of spans[i] is then used later in a call to JButton.setBounds() as the width. As you'll note, getPreferredSize() was never involved here, which is why setting it has no impact in this case.

Tim Stone
  • 19,119
  • 6
  • 56
  • 66
  • Thank you so much for the assistance and the explanation, I will admit it's a bit above me as of understanding it completely right now but I get the basic concept of why it works this way and I appreciate the extra help. – Brandon Buck Sep 12 '10 at 04:41
0
button.setMaximumSize(getMaximumSize());
Adi
  • 5,089
  • 6
  • 33
  • 47
Lesya Makhova
  • 1,340
  • 3
  • 14
  • 28
0

Usually if want to ensure a size of the component in Swing you need to call setMinimumSize(), setMaximumSize(), and SetPrefferedSize() with the same value.

Denis Tulskiy
  • 19,012
  • 6
  • 50
  • 68
  • Yes, normally I do this but it seems that I made the (at least in my case) all-to-common copy paste error when I copied the setPreferredSize(), I pasted it twice, changed one to setMinimumSize and left the other accidentally, thinking I had changed it. A simple error that I overlooked. Thanks for the assistance. – Brandon Buck Sep 12 '10 at 05:07
  • no, you don't [want to interfere with component provided sizing hints](http://stackoverflow.com/a/7229519/203657), ever ;-) – kleopatra Jul 09 '13 at 16:34
  • @kleopatra: I know you shouldn't mess with these but quite often one comes to this method in desperation of trying to make the damned layout work. – Denis Tulskiy Jul 09 '13 at 16:54
  • @kleopatra: actually, now that I think of it, for OP's problem I would've put the buttons in GridLayout, and then in vertical BoxLayout with glue. Should make them same width and default height. – Denis Tulskiy Jul 09 '13 at 16:54
0

If you put your buttons in a GridLayout panel they will be the same width.

Denizen
  • 15
  • 6
  • Along with filling all the space around them they possible can, like the entire east side of the panel - which makes this a non-ideal solution sadly. While GridLayout serves a purpose, I don't think it's applicable to solving this problem, and as was informatively described in the accepted answer the solution was quite simple. – Brandon Buck May 05 '17 at 06:17