XYLayout is a feature of JBuilder Professional and Enterprise. If you use JBuilder Foundation, substitutenull
layout whereverXYLayout
is specified.
The reason we decided upon this particular design is precisely because of the complications introduced by adding the odd number of buttons at the bottom. Also, this is a situation you will encounter frequently.
As you work through this part of the tutorial, please keep in mind that due to individual differences in drawing and arranging the components, your design may not exactly look like, nor behave like ours. But, it should be similar enough to allow you to achieve the desired results.
Steps 1 through 3 of this tutorial involve creating the layout in the UI designer. Steps 4-6 walk you through converting it to GridBagLayout. Step 7 shows you how to adjust the individual constraints to fine tune your design, and the reasoning behind these modifications.
Take your time, and don't be afraid to experiment. The UI designer makes it easy to try out different things and immediately see the effects. Just save your Frame1.java file before you try anything so you can Undo back to that point after you're done.
We have already done this step below.
In our sketch, we grouped the components into three panels which the GridBagLayout will control: two equal sized panels to hold the components in the main part of the UI, and one panel across the bottom for three OK, Cancel, and Help buttons. We did this for two reasons:
Runtime, before resizing:
Runtime, after resizing:
You could also use only one panel for the three buttons at the bottom and let the GridBagLayout control all the other components separately, rather than nesting them inside panels. This can work, as long as you are very careful to make all the upper components the same width on each side. However, GridBagLayout will create more columns based on where each component ends, making a much more complicated design that is more difficult to control.
Notice that the conversion created six columns this time. (Again, the background color has been changed on the transparent components so you can see where they end, illustrating how the columns and rows were calculated.)
Finally, if you don't use any inner panels to group components, GridBagLayout's job is much harder. In addition to creating even more cells, it makes a determination as to how many of these cells each component uses for a display area, and which components get weight
constraints. The more components in the design, the greater the potential for a real mess.
The images below show how a GridBagLayout panel with no inner panels behaves when it is resized at runtime:
Before resizing:
After resizing
As you can see, the components don't do what we want, and without grouping them into panels, it's practically impossible to control their placement and size during resizing.
Also, without any panels, if the components are not aligned very carefully and evenly, you could potentially end up with a grid that looks this:
When your grid becomes larger than the Frame, it can be an indication that you have too many disparate objects for GridBagLayout to control, and the decisions it makes as to weight
constraints, gridwidth
, gridheight
and anchor
cause the design to require a larger grid than the container can hold. When this happens, the display area of the objects are off the edge of the Frame.
If this does happen to you during GridBagLayout conversion, you may not want to waste time trying to go on to correct it. It could take hours and lots of frustration to try clean it up by modifying constraints, and you still might not succeed satisfactorily.
Just do an Undo (CTRL+Z) to reverse the conversion, returning to XYLayout. Readjust the design in XYLayout, then try converting it again.
For a cleaner conversion to GridBagLayout, some changes you can try while the container is in XYLayout are:
gridx
and gridy
locations for each display area, as well as where the components are anchored in that display area. Also, in this case, you may want to try removing all weight
constraints until the other constraints are fixed.
But, you can save yourself all this hassle if you use nested panels wisely in your design.
One more thought. It might also cross your mind that if you use four panels (three inside one GridBagLayout panel), it would work just as well to use BorderLayout for the main panel instead of GridBagLayout. The image below demonstrates how differently BorderLayout handles the components from GridBagLayout.
text
property for these components as follows:
jLabel1 = "Sorted Columns"
jButton1 = "Remove from Sort"
jCheckbox1 = "Descending"
font
property in the Inspector.
Font dialog
foreground
property to black.
![]()
|
Since jList1 was the first component selected in the group, the other components will match its width.
Note: While it's actually not necessary to make the components the same width, it is preferable in this case because it will simplify the grid created during the conversion to GridBagLayout. This will decrease the number of columns generated for GridBagLayout, as demonstrated earlier in Step 1.
![]() |
For best results, when laying out components in XYLayout for conversion to GridBagLayout, you should try to match the start and end of components evenly. Wherever possible, try to make the components conform more to an even grid design, rather than a stair-step design.
When the end of a component on one row overlaps the start of another component on a different row, GridBagLayout has a more difficult time calculating how many cells to create, which cells should have weights, how many cells the component should span, and how to apply insets and padding. The results are often not quite right, and it can be a real chore to clean up. |
jLabel2 = "Available Columns"
jButton2 = "Add to Sort"
jCheckbox2 = "Case Sensitive
![]() |
Since the default layout for a jPanel is FlowLayout, you can take advantage of this temporarily to add the buttons to the panel. As you drop the buttons into a FlowLayout panel, the layout manager centers the buttons in the panel with an even horizontal distance between them. You can then go directly to GridLayout without needing to use XYLayout. |
text
property (not the label
property which has been deprecated) for each of the three buttons to display OK, Cancel, and Help, in that order. The layout manager will adjust the width of the buttons to fit the text. Don't bother with resizing or positioning them because when you convert this panel to GridLayout, the buttons will all be the same size, height, and width.
Congratulations! You're all done with the initial layout. Save your file before proceeding.
![]() |
For best results, don't crowd the components in their containers, otherwise you may have a mismatch between the collective minimum or preferred size of the components and the minimum or preferred size of the containers, including the Frame. |
layout
property to GridBagLayout. This should result in very little visible change to your layout, especially since you grouped the components nicely into three panels that are easy for the GridBagLayout manager to manage.
You should see a grid of only two columns and two rows, as shown below:
To change these two panels to GridBagLayout:
![]() |
If you find it difficult to select a component in the UI designer, you can always select it in the component tree. |
You should see little difference in these panels after you convert them to GridBagLayout, although you might lose some of the margin, or gap, around the outside of the two panels.
Don't worry if things are not perfect yet. We'll make final adjustments in Step 7.
![]() |
Note: Since jPanel4 was left in XYLayout during jPanel1's GridBagLayout conversion, and since it was stretched across the entire width of jPanel1, it should have stayed nicely centered in the container after converting to GridBagLayout, spanning all columns. JBuilder assumes for conversion purposes that jPanel1's preferred size is the size it was in XYLayout, and assigns constraints assignments during the conversion based on this pixel size (for example, by giving it a gridwidth value equal to the number of columns generated during the conversion, or its ipadx value.)
Now, as you change the layout to GridLayout, the panel stays the same width as it was in XYLayout, but notice that the buttons expand to fill the panel, and there is no gap between them. Also, the panel is larger than necessary. We'll fix these things in Step 7, where we'll make minor adjustments to the constraints for all the components. |
One thing to keep in mind as we continue is that all the discussion about how the constraints affect the components during resizing is relevant only if at least one component has weight
constraints. In fact, it is unlikely that you would ever create an outer GridBagLayout container without using weight
constraints. When none of the components have weight
, resizing has no affect on the placement of the components. All the components clump at their minimum or preferred size in the center of the GridBagLayout panel, and any extra space given to the container by enlarging it gets put between the outside edges of the components and the edge of their container.
Another important point is that there is more than one combination of constraint values that can accomplish the same results. For example, as with the GridLayout panel below, to keep it centered and a consistent size at the bottom of the GridBagLayout container, you can use insets
, anchor
, padding
, or a combination of these.
Most of the modifications you will make during the rest of this part of the tutorial will be made in the GridBagConstraints Editor.
To open the GridBagConstraints Editor,
After finishing this tutorial, do some experimentation with this UI. Open the GridBagConstraints Editor and try out different constraint values to see what happens.
Now, let's continue by fixing the GridLayout panel (jPanel4) first.
hgap
property for the GridLayout itself.
To change the horizontal gap value,
gridLayout1
node in the component tree (immediately below the jPanel4 node.)
gridLayout1
's hgap
property in the Inspector and enter a pixel value (we used 6 pixels in our example).
Before resizing:
After resizing:
This is the expected behavior of GridLayout: the components it contains fill up the panel, no matter what size it is (honoring, of course, any values specified for horizontal and vertical gap surrounding the buttons.)
Therefore, to control the size of the buttons in the grid, you must restrict the size of the GridLayout panel itself, using its GridBagConstraints.
fill
If you look in the GridBagConstraints Editor at the constraint values assigned to jPanel4, you'll see that both its horizontal and vertical fill
constraints are turned on. When this is the case, GridBagLayout stretches the panel to completely fill its display area, up to the edge of any insets
that are set. If there are no insets
, the panel fills up the display area all the way to the edge of the cells.
This is definitely not the behavior we want for this GridLayout panel since we want the buttons in the panel to be their preferred size. To accomplish this, you need to remove the panel's fill
constraints.
To remove both the horizontal and vertical fill
constraints at the same time, right-click the GridLayout panel and do one of the following:
fill
from the pop-up menu.
fill
constraint value in the GridBagConstraints Editor.
anchor
To make sure the panel always stays centered in its display area, you need to set the anchor
constraint to Center. Since we centered the panel before we converted to GridBagLayout, the anchor
constraint is probably already set to Center. But, open the GridBagConstraints Editor and make sure it looks like the following:
Now that the fill
is None, and the anchor
is Center, when the container is resized, the buttons stay small and centered when the Frame is resized.
insets
Insets
simply define an area between the component and the edges of its display area into which the component cannot enter. It is just like setting margins in a document. No matter how the container is resized, the number of pixels for the insets
remains constant, and work like brakes to keep the component away from the edge of the display area.
If you have fill
turned on for the component, it fills the display area up to the insets
. As you resize the container, the component expands to stay up against those insets
.
In the case of this GridLayout panel, since you removed the fill
and anchored it in the center of its display area, nothing would be gained by adding any insets
to the left and right edges of the display area. The only thing you need to do here is make sure both the left and right Inset values match (set to zero.)
You do, however, want to set the top and bottom insets
to put some space above and below the panel. Set each of these values in the GridBagConstraints Editor to 15 pixels.
Padding
Padding (ipadx
, ipady
) changes the actual size of the panel component by adding a specified number of pixels to its minimum width and/or height. The minimum size of the GridLayout panel is just large enough to display the buttons at their minimum size, plus any width you specified in the hgap
property for GridLayout. (In the case of buttons, there is a margin
property that is also included in the calculation of the button's minimum size.)
If you like the size of the buttons and the panel at their minimum size, then you don't need to do anything more with the padding. If you want the buttons in the GridLayout panel to be larger than their minimum size, you can specify how many additional pixels to add to the panel to accomplish this. You can even make the buttons smaller by using negative values.
For this tutorial, since the size of the buttons in jPanel4 is acceptable at their minimum size, set both padding values to zero.
You can remove all padding values quickly by right-clicking jPanel4 in the designer and choosing Remove Padding.
That takes care of the GridLayout panel. Now, lets move on to the upper panels.
gridwidth
and gridheight
First, open the GridBagConstraints Editor, and in the Grid Position area, check that each component in these two panels only specifies one cell in the Width and Height values (gridwidth
and gridheight
) . If not, correct this.
Do the same thing for jPanel2 and jPanel3.
fill
Next, you want all the components and their containers to fill up their display area, except for the buttons. As in the GridLayout panel, we don't want the buttons to expand as the Frame is resized.
Again, working with one panel at a time, select all the components inside the panel, except the button, and check Both for the fill
constraint.
Lastly, you want the panels themselves to fill up their display area in the main GridBagLayout container. So, make sure jPanel2 and jPanel3 have a fill
constraint of Both as well.
insets
Since the components in both of these panels happen to be the same, matching insets
for all of them will ensure the components look the same in both panels. None of the components need left and right insets
, as the panels containing them are invisible and will control the spacing in the main container. However, top and bottom insets
will put some spacing between each of the components within the panels.
Set the Inset values for the components in each panel as follows:
Labels: | Top = 0, Left = 0, Bottom = 4, Right = 0 |
Lists: | Top = 0, Left = 0, Bottom = 0, Right = 0 |
Buttons: | Top = 10, Left = 0, Bottom = 0, Right = 0 |
Checkboxes: | Top = 6, Left = 0, Bottom = 0, Right = 0 |
Finally, to put a little space between the top and sides of these two panels and the outer container (jPanel1), set the following insets
for jPanel2 and jPanel3:
Top = 10, Left = 10, Bottom = 0, Right =10 |
Note: you don't need to set insets
for the bottom, since the GridLayout panel's top insets
are taking care of that space.
anchor
The two panels, and their label, list, and checkbox components all have fill
constraints of Both. Since each of these components fills its display area both horizontally and vertically, anchor
constraints have no effect. There is simply no room inside the display area for the component to move.
If you want to verify this, try changing some of the anchor
constraints for these components, then running your program and resizing the container. You'll see there is no change.
The only components in these panels for which anchor
will have an effect are the buttons, which have no fill
. Since they do not fill up their display area, they can be moved around inside it. To make sure these buttons stay centered in their display area, set their anchor
constraint to Center.
ipadx
, ipady
One place in this design where ipadx
is appropriate is for controlling the size of the Add to Sort button in jPanel3. If you leave the ipadx
at zero for both buttons, then the Add to Sort button will display at it's minimum size which won't match the size of the Remove from Sort button.
You can use Horizontal Padding (ipadx
) to increase the width of the button and make it the same width as the other button.
fill
constraints still say None.
Add to Sort button without ipadx
Add to Sort button with ipadx
None of the other components in these panels need padding, nor do the panels themselves. Since the jPanel2 and jPanel3 have fill
constraints, these override any padding that might be assigned.
You'll also notice that the list components use ipadx
and ipady
, which you might not want in reality. Since you did nothing to populate the lists with items in this example, if you remove the ipadx
and ipady
constraints along with the fill
, the lists will disappear. Their minimum size is determined by the number of items in the list. We just added ipadx
and ipady
constraints to force a particular size for demonstration purposes.
weight
As we said earlier, if you want the components in a container to change size as the container is resized, you need to assign weight
constraints values to at least one component horizontally and vertically.
weight
constraints specify how to distribute the extra container space created when resizing the container.
You need to set both the weight
and fill
constraints for a component if you want it to grow. For example, if a component has a horizontal weight
constraint, but no horizontal fill
constraint, then the extra space goes to the padding between the left and right edges of the component and the edges of the cell. It enlarges the width of the cell without changing the size of the component. If a component has both weight
and fill
constraints, then the extra space is added to the cell, plus the component expands to fill the new cell dimension in the direction of the fill
constraint (horizontal in this case).
First, we took all the weight
constraint values off that the conversion had set. This is what happened:
No weights
Before resizing
No weights
After resizing
Notice how the components are all clumped in the middle. This is easier to see when the container is resized as in the second image.
We determined that the components we want to grow are jPanel2 and jPanel3, and both list components inside them. We tried various weight
constraint combinations on these components to see the results. Below are links to these results:
weight
constraints on both panels and lists
weight
constraints on the panels, but not on the lists
weight
constraints on the lists, but not on the panels
weight
constraints only
weight
constraints only
weight
constraints on only one panel and list component in the row
Number 1 is the behavior we want. Set the weight
constraints to 1.0 in the GridBagConstraints Editor for all four components: jPanel1, jPanel2, jList1, and jList2.
One thing that should be obvious from this exercise is that each GridBagLayout is going to require experimentation with the constraints until you achieve just the look and behavior you want. However, JBuilder can assist in that process by quickly getting you past the initial GridBagLayout coding and on to the fine tuning. And, just like anything else, the more you practice, the easier it gets.