This week, we're demonstrating one of the more important fundamentals in Java applet design: complex interface layouts. The following is an example applet: Complex Interface Layouts
Note that the applet's interface is complex. Hopefully, however, it will serve to show some of the various tools you have at your disposal when using the
GridBagLayoutthat we've been talking about in previous columns.Almost all the various types of layout constraints we mentioned last week are in play here. Our explanation will probably be most clear, though, if we start from the beginning. GridBagLayout, without any tuning of constraints at all, results in the exact same thing as
FlowLayout.In the applet above, all we have done is to set GridBagLayout to be our main Panel's layout manager, and then
add()ed six Button objects. Since GridBagLayout requires it, we also make a call tosetConstraints()declaring each button along with aGridBagConstraintsobject before actually adding them to the panel.The most basic change we make is to break our applet's row of interface objects into three lines. We do this by making a change to the
GridBagConstraintsobject for three of the buttons we add, like so:... ourconstraints.gridwidth = GridBagConstraints.REMAINDER; ourlayout.setConstraints(b2,ourconstraints); add(b2); ourconstraints.gridwidth = 1; ourlayout.setConstraints(b3,ourconstraints); add(b3); ourlayout.setConstraints(b4,ourconstraints); add(b4); ourconstraints.gridwidth = GridBagConstraints.REMAINDER; ourlayout.setConstraints(b5,ourconstraints); add(b5); ...
By having the constraint object's
gridwidthset to the valueGridBagConstraints.REMAINDER, the associated interface object will be positioned to take up the "remainder" of the "grid" row. Of course, since we're keeping and using the same constraints object for every Button, we don't set it every time for every change. As you can see, the grid is defined in terms of its longest row. Button 1's gridwidth, which we haven't touched, is 1, so it takes up the same amount of space as the "gridwidth 1" button below it. Buttons 2 and 6, on the other hand, both center themselves in their "remaining" space.Notice that the Buttons are small and contiguous on the screen; in other words, they take up only as much space as they need to contain their labels, and they stick together. We can change constraints to control these properties too, which would give us this set of statements:
... ourconstraints.insets = new Insets (10,10,10,10); // Make space around me ourconstraints.fill = GridBagConstraints.BOTH; // Fill out in BOTH directions ourconstraints.weightx = 1; ourconstraints.weighty = 1; ourlayout.setConstraints(b1,ourconstraints); add(b1); ourconstraints.insets = new Insets (0,0,0,0); ourconstraints.gridwidth = GridBagConstraints.REMAINDER; ourlayout.setConstraints(b2,ourconstraints); add(b2); ourconstraints.gridwidth = 1; ourconstraints.weighty = .2; ourlayout.setConstraints(b3,ourconstraints); add(b3); ...
Here we use the
insetsconstraint. This takes an Insets object as its value. Think of this as simply an object that contains four numbers, namely, the number of pixels of space to add around each side of your object. You can see that we specify 10 pixels of space on every side for our first Button, and then reduce the inset space to zero for every side on the subsequent objects (obviously, this is the default).Our use of the
fillconstraint has made most of the buttons expand to fill the available room (in this case, the height and width of the panel we gave in the APPLET tag), except for Button 6, of course. Before setting the constraints for this button, we issued a
ourconstraints.fill = GridBagConstraints.NONE;This returned the last button to the default state--not filling unused space. Notice also that the top two buttons (even with the inset on Button 1) are taller than the remaining ones. This is due to our use of the
weightxandweightyconstraints.These two constraints must be set to something in order for fill to work. Their purpose is to indicate how much sizing "weight" an object may have for taking up extra space. Because the top two buttons have a
weightyof 2, and the rest of the buttons have aweightyof only 0.2, the vertical space is distributed accordingly.There is still more flexibility easily available to us within this layout manager. We mentioned the
gridwidthconstraint before. There is also agridheightconstraint, which works in a similar fashion--specifying a gridheight of 2 for an object will make it take up two row's worth of height. However, according to the GridBag constraint tutorial, a Java 1.0 bug prevents your objects from spanning multiple rows unless they're in the leftmost column, as ours is.... ourconstraints.gridwidth = 1; ourconstraints.gridheight = 2; // We add this... ourconstraints.weighty = .2; ourlayout.setConstraints(b3,ourconstraints); add(b3); ourconstraints.gridheight = 1; // And then set it back to normal here... ourlayout.setConstraints(b4,ourconstraints); add(b4); ...
To conclude, in addition to adding a gridheight specification to the two blocks shown above, we also used the
anchorconstraint. This constraint is relevant when you aren't usingfillto expand into your empty space. Instead, this allows you to specify, much like in a BorderLayout, to which of the "cardinal directions" you would prefer your object to be "anchored." When we specify our anchor for Button 6 to be GridBagConstraints.NORTH, the button migrates to the top center of its space.
ourconstraints.anchor = GridBagConstraints.NORTH;We hope this peek at the evolution of our layout has been illustrative. The Sun tutorial piece on the subject is excellent as a reference and only adequate for beginners, but we urge you to look it over.
We can't stress enough the importance of being able to create good dynamic layouts for your applets. Frozen layouts (often created by the "UI builders" in some of the first-run Java development tools) may seem easier to create in the short run, but your portability is lost when your carefully arranged interface frays everywhere and becomes unreadable due to a font size or screen resolution change.