views:

43

answers:

4

I'm trying to use GridBagLayout to position labels in two rows, but I want some of the labels to span both rows and others to be placed on top of each other. I need to use GridBagLayout because of the proportional sizing functionality in the weightx and weighty properties of GridBagConstraints. This is the layout I'm looking for:

+----------+----------+----------+----------+
|          |          |  labelC  |          |
|  labelA  |  labelB  |----------|  labelD  |
|          |          |  labelE  |          |
+----------+----------+----------+----------+

The problem is that labelE is being placed beneath LabelA. Here is the layout portion of my code:

GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
this.setLayout(gridBag);
c.fill = GridBagConstraints.BOTH;

c.gridwidth = 1;
c.gridheight = 2;
c.weighty = PANEL_HEIGHT;
gridbag.setConstraints(labelA, c);
this.add(labelA);

gridbag.setConstraints(labelB, c);
this.add(labelB);

c.gridheight = 1;
c.weighty = TOPROW_HEIGHT;
gridbag.setConstraints(labelC, c);
this.add(labelC);

c.gridheight = 2;
c.gridwidth = GridBagConstraints.REMAINDER;
c.weighty = PANEL_HEIGHT;
gridbag.setConstraints(labelD, c);
this.add(labelD);

c.gridheight = 1;
c.gridwidth = 1;
c.weighty = BOTROW_HEIGHT;
gridbag.setConstraints(labelE, c);
this.add(labelE);

this.validate();

Any ideas about what I'm missing?

+1  A: 
Bragboy
The problem I have with `GridLayout` is the lack of setting the heights and widths of each component. The `weightx` and `weighty` parts of the `GridBagConstraints` class work perfectly for how I need this panel to size. I omitted the `weightx` from the sample code because it is irrelevant to the problem. Because of this, however, `GridLayout` will not suit my needs. Sorry.
Erick Robertson
Not that I am against GridBagLayout. I myself have used it many times. But when you start coding without the help of a Swing editor like Netbeans, the code becomes really crazy in size with a GridBagLayout. That is the reason I thought I would suggest GridLayout. Plus, why dont you try Netbeans, it does real magic.. Just my few cents.
Bragboy
I learn a lot more when I do it manually. I generally don't like to trust any sort of graphical layout editor to write my code. I don't see this as being that hard - and the code is going to be crazy in size anyways whether I write it or generate it. Typically, I use `GroupLayout`, actually. It's very powerful.
Erick Robertson
GridBagLayout was intended to work with GUI editors, it's actually not a good layout manager for manual editing because it tends to be very difficult to get it to scale (change window size) smoothly in an intuitive manner. I'd find a way to make GridLayout or some other nesting layouts to work OR create a routine to generate your layout for you--but don't put all that crap in your code--horrible horrible programming--keep your data and your code separate!
Bill K
@Erick: Good. Once you learn and master the structure of layouts in Swing (I assume only a handful exists), you can later master it using some IDE as well. Few years back, I was adamant not to learn one. But the features that it offer cannot be beaten by manual coding. Yes, you can achieve what you want by simple coding, but you will definitely avoid lots of trial and error scenario thus saving huge amount of time. Trust me, I've been using Swing for many years. But for now, I like your spirit to learn! All the best!!!
Bragboy
@Bill: No reason to call it horrible horrible programming. If I generated this code in a GUI editor, it would look like this anyways.
Erick Robertson
@Erick: Generating code by a editor is not a bad thing. You have your preview (in xml) and your code intact. Infact you dont have to care much about the issue, you can simply abstract the view generation logic to a separate method and forget about it totally. You can then put a layer inbetween to handle events, work with datamodels thus giving less time and importance to writing and debugging code layouts.
Bragboy
@Bragboy: I think you're making assumptions that I don't know what I'm doing, just because I got hung up on a detail of one specific class. What you propose is a lot more complicated than what I did. I fundamentally disagree with your approach of adding layers and abstraction to the problem. In my opinion, it kills maintainability. I also think it's important to note - I chose GridBagLayout exactly for its ability to scale properly. When I resize my panel, the contents move exactly how I want them to. I had one very specific problem, and the solution was not to switch to GridLayout.
Erick Robertson
Bill K
@Bill: Well, I'm not going to put these definitions in an XML file and then use a parser to load that and use it to layout my components. That's obfuscation. This code is fast, and it works. It's tucked away in a class that just handles this one piece of layout. There's nothing wrong with it.
Erick Robertson
Bill K
@Bill: I wouldn't reuse this code. It was written specifically for this class and does the exact job necessary for layout out this panel. I think impossible to reuse is a bad concept. I actually have a panel that works in the same paradigm in another part of the application, but I didn't build some construct for doing these layouts. I don't want these two panels to be tied together like that. They'll never be updated together. I think it's a bad idea to spend time building constructs to extend swing just because you have a personal philosophy that all code should be 100% reusable.
Erick Robertson
There's one more point to be made here - that is of programmatically building these layouts. As I continue to work on this panel today, I realize that a couple of these components are going to have to change positioning programmatically. For example, in some cases, some of the columns that are split into two actually won't be. So in this case, I can't use a GUI editor. I have to write the code myself. If I had built a construct for reusing the layout code, I'd have to seriously extend it or throw it away. This is why I don't spend time extending Swing for trivial things.
Erick Robertson
+1  A: 

You need to set the gridX and gridY:

GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
this.setLayout(gridBag);
c.fill = GridBagConstraints.BOTH;

c.gridwidth = 1;
c.gridheight = 2;
c.gridx = 0;
c.gridy = 0;
c.weighty = PANEL_HEIGHT;
gridbag.setConstraints(labelA, c);
this.add(labelA);

c.gridx = 1;
c.gridy = 0;
gridbag.setConstraints(labelB, c);
this.add(labelB);

c.gridx = 2;
c.gridy = 0;
c.gridheight = 1;
c.weighty = TOPROW_HEIGHT;
gridbag.setConstraints(labelC, c);
this.add(labelC);

c.gridx = 3;
c.gridy = 0;
c.gridheight = 2;
c.gridwidth = GridBagConstraints.REMAINDER;
c.weighty = PANEL_HEIGHT;
gridbag.setConstraints(labelD, c);
this.add(labelD);

c.gridx = 2;
c.gridy = 1;
c.gridheight = 1;
c.gridwidth = 1;
c.weighty = BOTROW_HEIGHT;
gridbag.setConstraints(labelE, c);
this.add(labelE);

this.validate();

Hope that helps.

aperkins
Just wanted to say thanks for the solution. You and Colin answered at exactly the same time. +1
Erick Robertson
@Erick no problem, glad I could help you out. The biggest problem with gridbag I have seen people have is exactly this - the column spanning issue. Glad to see it worked for you! :)
aperkins
+1  A: 

You can use gridx and gridy to select your position on the grid :

    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();

    this.setLayout(gridbag);

    c.fill = GridBagConstraints.BOTH;

    c.gridwidth = 1;
    c.gridheight = 2;
    c.gridx = 0;
    c.gridy = 0;
    c.weighty = PANEL_HEIGHT;
    gridbag.setConstraints(labelA, c);
    this.add(labelA);

    c.gridx = 1;
    c.gridy = 0;
    gridbag.setConstraints(labelB, c);
    this.add(labelB);

    c.gridx = 2;
    c.gridy = 0;
    c.gridheight = 1;
    c.weighty = TOPROW_HEIGHT;
    gridbag.setConstraints(labelC, c);
    this.add(labelC);


    c.gridx = 3;
    c.gridy = 0;
    c.gridheight = 2;
    c.gridwidth = GridBagConstraints.REMAINDER;
    c.weighty = PANEL_HEIGHT;
    gridbag.setConstraints(labelD, c);
    this.add(labelD);

    c.gridx = 2;
    c.gridy = 1;
    c.fill = GridBagConstraints.VERTICAL;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.weighty = BOTROW_HEIGHT;
    gridbag.setConstraints(labelE, c);
    this.add(labelE);

    this.validate();
Colin Hebert
Oddly enough, `gridx` and `gridy` are not used in the `GridBagLayout` javadoc sample code, although it has this behavior. However, this works perfectly. Thanks, Colin!
Erick Robertson
Don't need `this.pack()`, though.
Erick Robertson
@Erick Robertson, You're right, it's just a leftover from my modification attempts. You can find some examples of GridBagLayout on java tutorials : http://download.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
Colin Hebert
I actually have quite a nice implementation of it in another component where I added panels into the GridBaglayout which I use to resize the other panels by changing the weighty appropriately. But in that implementation, everything always lined up in a perfect grid - there were no spanning columns or rows.
Erick Robertson
A: 

The easiest way to solve this problem (using GridBag) is to have labelC and labelE inside a JPanel.

The more difficult way to solve it, is to use the gridx, gridy and gridheight constraints. So, you would have

+---------------+--------------+----------+----------+
|  gridy=0      | gridy=0      |  gridy=0 |  gridy=0 |
|               |              |  gridx=2 |  gridx=3 |
|  gridx=0      | gridx=1      |----------|          |
|  gridheight=2 | gridheight=2 |  gridy=1 |          |        
|               |              |  gridx=2 |          |
+---------------+--------------+----------+----------+
Codemwnci
I don't understand why this is the more difficult way.
Erick Robertson
just more coding. Its more difficult, but certainly the right solution. The JPanel allows you to get away with having to worry about gridtheights etc, because it is a single element. The 2 elements inside will then be set out accordingly.
Codemwnci