• Java图形化界面设计——布局管理器之GridBagLayout


    GridBagLayout 不会随着窗口的变化标签随之发生变化,可固定。

    ----------------------------------------------------------
     
    import java.awt.Button;
    import java.awt.Font;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
     
    import javax.swing.JFrame;
    import javax.swing.JPanel;
     
    public class GridBagEx2 extends  JPanel
    {
        private static final long serialVersionUID = -5214441555967215113L;
     
        protected void makebutton(String name, GridBagLayout gridbag,
                GridBagConstraints c)
        {
            Button button = new Button(name);
            gridbag.setConstraints(button, c);
            add(button);
        }
     
        public void init()
        {
            GridBagLayout gridbag = new GridBagLayout();
            GridBagConstraints c = new GridBagConstraints();
     
            setFont(new Font("SansSerif", Font.PLAIN, 14));
            setLayout(gridbag);
     
            c.fill = GridBagConstraints.BOTH;
            c.weightx = 1.0;
            makebutton("Button1", gridbag, c);
            makebutton("Button2", gridbag, c);
            makebutton("Button3", gridbag, c);
     
            c.gridwidth = GridBagConstraints.REMAINDER; //end row
            makebutton("Button4", gridbag, c);
     
            c.weightx = 0.0; //reset to the default
            makebutton("Button5", gridbag, c); //another row
     
            c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
            makebutton("Button6", gridbag, c);
     
            c.gridwidth = GridBagConstraints.REMAINDER; //end row
            makebutton("Button7", gridbag, c);
     
            c.gridwidth = 1; //reset to the default
            c.gridheight = 2;
            c.weighty = 1.0;
            makebutton("Button8", gridbag, c);
     
            c.weighty = 0.0; //reset to the default
            c.gridwidth = GridBagConstraints.REMAINDER; //end row
            c.gridheight = 1; //reset to the default
            makebutton("Button9", gridbag, c);
            makebutton("Button10", gridbag, c);
     
            setSize(300, 100);
        }
     
        public static void main(String args[])
        {
            JFrame f = new JFrame("GridBag Layout Example");
            f.setLocation(400, 200);
            GridBagEx2 ex1 = new GridBagEx2();
     
            ex1.init();
     
            f.add("Center", ex1);
            f.pack();
            f.setSize(f.getPreferredSize());
            f.setVisible(true);
            f.addWindowListener(new WindowAdapter()
            {
     
                @Override
                public void windowClosing(WindowEvent e)
                {
                    System.exit(0);
                }
                 
            });
        }
     
    }

    The Java AWT: GridBagLayout

    Jan Newmarch
    Web: http://jan.newmarch.name
    Email: jan@newmarch.name


    Contents


    Introduction

    A graphical user interface is built up in Java by adding objects to Containers, and using LayoutManagers to place and size them within the containers. There are several managers supplied in AWT:

    • BorderLayout - NSEW layout
    • FlowLayout - left-to-right with overflow
    • GridLayout - regular rectangular grid
    • GridBagLayout - general gridded layout
    • CardLayout - allows "flipping" through a set of "cards"

    In the last issue of the X Advisor I discussed all of these except for GridBagLayout. The reason is simple: GridBagLayout is a manager that can layout a large number of configurations in a flexible way. This ability comes through complexity, and there is a lot to learn before you can use this manager effectively. This article is devoted entirely to GridBagLayout.

    GridBagLayout is used to place objects in a rectangular grid. The cells of this grid need not be the same size, and the objects can span several cells. There is control over placement of each object within the space allowed for it, and how it fills this space.

    Debugging

    The more complex the layout manager, the harder it is to get layouts correct. Under X, I use two techniques to help me with layouts using this manager. The first is very specifically X Oriented: set the resource borderWidth for all objects to some non-zero value. Then you can see exactly how each object is placed, including objects like labels which don't normally have visible edges. I set this in .Xdefaults:

    *borderWidth: 3
    

    The second technique is more generally applicable, but harder to interpret. GridBagLayout has two protected methods, DumpConstraints() and DumpLayoutInfo(), intended for debugging the manager itself. However, if you want access to this level of information then you can subclass the manager and call these methods yourself. Here is a suitable subclass. Note that it must be installed in $CLASSES/java/awt since it has to belong to package java.awt

    package java.awt;
    
    public class DebugGridBagLayout extends GridBagLayout {
    
        public void dumpLayoutInfo(Container parent) {
    	GridBagLayoutInfo s = GetLayoutInfo(parent, 
    				GridBagLayout.PREFERREDSIZE);
    	DumpLayoutInfo(s);
        }
    
        public void dumpConstraints(Container parent) {
    	Component comp;
    	GridBagConstraints constraints;
    
    	for (int n = 0; n < parent.ncomponents; n++) {
    	    comp = parent.getComponent(n);
    	    constraints = lookupConstraints(comp);
    	    DumpConstraints(constraints);
    	}
        }
    }
    

    Not all problems with using this manager are caused by your bugs :-). Many of the applets that run within this article fail to show components when they begin execution. Partly for this reason, I use components such as Button that respond to inputs and redraw themselves on changes. If some of the applets seem to be missing components, click over them to show the missing ones.

    On my system, at least one of the applets displays correctly using appletviewer but doesn't show under Netscape 2.0.

    GridBagConstraints

    In order to layout objects within a container, the manager needs to know some information about them. A very simple manager like FlowLayout just needs to know the order in which objects were added to the container and it can get this from the container itself. A manager like BorderLayout needs to associate objects with special positions such as "North", and it gets this association from the add(String, Component) method. When the container executes this it also calls the layout object's addLayoutComponent(String, Component) which allows the layout manager to store information.

    The information needed by GridBagLayout for each object is complicated: direction of layout, number of cells spanned, placement within this space, etc. The above methods are too simple for that. Instead, all of this information is stored in a GridBagConstraints object, and this is passed through to the layout manager by

    setConstraints(Component, GridBagConstraints)
    

    The layout manager makes a copy of the GridBagConstraints and links it to the Component using a hash table. (This means that you only need to have one of these objects which you can reset values of without messing up earlier references.)

    Typical code using this manager is

    GridBagLayout gridbag = new GridBagLayout();
    setLayout(gridbag);
    
    GridBagConstraints constraints = new GridBagConstraints();
    // set values in constraints ... 
    
    Button btn = new Button("Hello");
    add(btn);
    
    // tell the layout manager of the constraints
    gridbag.setConstraints(btn, constraints);
    

    The fields of GridBagConstraints are

    public int gridx, gridy, gridwidth, gridheight;
    public double weightx, weighty;
    public int anchor, fill;
    public Insets insets;
    public int ipadx, ipady;
    

    These may be set by an application. They are discussed in the article in the appropriate places.

    Absolute positioning

    The two fields gridx and gridy may be used to set the positions of objects, where the topleft cell is at (0, 0). For example, to arrange four buttons at the corners of a fifth,

    import java.awt.*;
    
    public class Absolute extends Frame {
    
        public static void main(String argv[]) {
    	new Absolute().show();
        }
    
        public Absolute() {
    	GridBagLayout gridbag = new GridBagLayout();
    	setLayout(gridbag);
    
    	GridBagConstraints constraints = new GridBagConstraints();
    
    	Button  btn1 = new Button("Button 1");
    	add(btn1);
    	// set at (0,0)
    	constraints.gridx = 0;
    	constraints.gridy = 0;
    	gridbag.setConstraints(btn1, constraints);
    
    	Button btn2 = new Button("Button 2");
    	add(btn2);
    	// set at (2,0)
    	constraints.gridx = 2;
    	constraints.gridy = 0;
    	gridbag.setConstraints(btn2, constraints);
    
    
    	Button btn3 = new Button("Button 3");
    	add(btn3);
    	// set at (0,2)
    	constraints.gridx = 0;
    	constraints.gridy = 2;
    	gridbag.setConstraints(btn3, constraints);
    
    	Button btn4 = new Button("Button 4");
    	add(btn4);
    	// set at (2,2)
    	constraints.gridx = 2;
    	constraints.gridy = 2;
    	gridbag.setConstraints(btn4, constraints);
    
    	Button btn5 = new Button("Button 5");
    	add(btn5);
    	// set at (1,1)
    	constraints.gridx = 1;
    	constraints.gridy = 1;
    	gridbag.setConstraints(btn5, constraints);
    
    	resize(300, 300);
        }
    }
    

    The program looks like

    Note that problems in the AWT may result in buttons not showing until pressed. It should look like

    Cell sizes

    The manager displays objects in one or more cells. The cells may be of different sizes. In each row the cells all have the same height, though, and in each column the cells all have the same width.

    For each row, the height is calculated by looking at the preferredSize().height of the components in that row. The maximum of these is found, and then the value of ipady is added twice (for top and bottom). The height is usually this, unless made larger by some other constraint. Whatever, the height of the row cannot be smaller than this.

    Similarly, the width of each column is not smaller than the maximum preferred width of each component, plus twice ipadx.

    Different rows can thus have different heights, and different columns can have different widths. To see this, replace one of the buttons by, say, a TextArea:

    The sizing policy means that if there is nothing in a row and ipady is also zero, then the row has no width and does not show. Similarly with a column with no components. In the example program if we remove the central button, "Button 5", then that row and column have zero height and width respectively, and all four buttons show up against each other.

    if you want to get four buttons occupying corners with a middle space, then you need to adjust ipadx and ipady to leave space around each button. This would leave a border around the outside though. This particular problem is revisited later. REVISIT THIS.

    In the JDK version 1.0, there is a limitation on the number of components that can appear in any row or column. Each is set to a maximum of 128. If you exceed this, then an ArrayIndexOutOfBoundsException is raised.

    Relative positioning

    If you want to layout a lot of objects in a row, then having to specify gridx for each of them may be a little tedious. An alternative way is to use relative positioning, in which you say how to layout a component with respect to the last one (roughly). The fields gridx and gridy are used for this relative placement as well as the absolute placement.

    If gridx == RELATIVE then add in row order. That is, place the next component to the right of the previous component unless the previous component was the last in the row, in which case this one starts a new row.

    Similarly, if gridy == RELATIVE then add in column order. That is, add below the previous component unless it was the last in the column, in which case it is placed in a new column to the right.

    If both gridx and gridy are RELATIVE then add in row order. This is the default value for a GridBagConstraints object. These values can be reset for each component. It is also possible to mix up the absolute and relative styles of positioning together.

    A simple example of relative positioning is to set a group of buttons vertically without having to reset the GridBagConstraints each time (this is, of course, easier with GridLayout)

    import java.awt.*;
    
    public class Vertical extends Frame {
    
        public static void main(String argv[]) {
    	new Vertical().show();
        }
    
        public Vertical() {
    	Button btn;
    	GridBagLayout gridbag = new GridBagLayout();
    	setLayout(gridbag);
    
    	GridBagConstraints constraints = new GridBagConstraints();
    	constraints.gridx = 0; // note: gridy == RELATIVE 
    
    	for (int n = 1; n <= 8; n++) {
    	    btn = new Button("Button " + n);
    	    add(btn);
    	    gridbag.setConstraints(btn, constraints);
    	}
        }
    }
    

    which shows as

    More complex arrangements can be obtained by mixing relative and absolute positioning:

    import java.awt.*;
    
    public class Direction extends Frame { 
        Button btn1, btn2, btn3, btn4, btn5, btn6;
        GridBagLayout gridbag;   
        GridBagConstraints c;
    
        public static void main(String argv[])
        {
    	new Direction().show();
        }
    
        void makeButtons() {
    	btn1 = new Button("Button 1"); add(btn1);
    	btn2 = new Button("Button 2"); add(btn2);
    	btn3 = new Button("Button 3"); add(btn3);
    	btn4 = new Button("Button 4"); add(btn4);
    	btn5 = new Button("Button 5"); add(btn5);
    	btn6 = new Button("Button 6"); add(btn6);
        }
    
        public Direction()
        {
    	gridbag = new GridBagLayout();
    	setLayout(gridbag);
    	c = new GridBagConstraints();
    
    	makeButtons();
    
    	// use defaults for btn1
    	gridbag.setConstraints(btn1, c);
    
    	// btn2 below btn1
    	c.gridx = 0; // gridy is still RELATIVE
    	gridbag.setConstraints(btn2, c);
    
    	// btn3 below of btn2 - reuse constraint
    	gridbag.setConstraints(btn3, c);
    
    	// btn4 right of btn2
    	c.gridx = GridBagConstraints.RELATIVE;
    	c.gridy = 1;
    	gridbag.setConstraints(btn4, c);
    
    	// btn5 right of btn4
    	c.gridx = GridBagConstraints.RELATIVE;
    	c.gridy = 2;
    	gridbag.setConstraints(btn5, c);
    
    	// btn6 down and to right of btn5
    	c.gridx = 2;
    	c.gridy = 3;
    	gridbag.setConstraints(btn6, c);
    
    	resize(400, 200);
        }
    }
    

    which shows as

    Filling

    When a component is placed in a cell, the cell is guaranteed to be at least as large as the component plus twice the values of ipadx and ipady. If there are components of different sizes then some of them will be smaller than the cell size. A component may also be set to occupy more than one cell, which it may not be large enough to fill. The amount of space an object occupies within its allocated area is controlled by the fill field of the constraints object. The possible values are

    • HORIZONTAL - set the component's width to the full size available.
    • VERTICAL - set the component's height to the full size available.
    • BOTH - set the width and height to the size of the available space.

    Anchor

    There is an additional method of control over placement of an object when its preferred size is smaller than that of the space it has to occupy. The anchor field controls location within this. The possible values of this are NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST and (the default) CENTER.

    The following example is quite artificial: it forces a space larger than a normal Button by setting a long TextField horizontally and a high TextArea vertically. A Button is set in this because it has natural edges so you can see what happens to its boundaries. The applet allows selection of fill and anchor parameters and how they affect the Button. The source contains several uses of layout managers and is available as FillAnchorApplet.java (Note: setting the anchor has no effect until a change is made to fill - another minor bug in AWT :-( ).

    The program looks like


    Padding and Insets

    There is a third level of control over sizing and placement of objects (just for variety :-( ). Each GridBagConstraint has fields of ipadx, ipady and insets - an Insets object.

    The insets object acts like it does in other managers. Given a space in which to locate an object, insets specifies a top, bottom, left and right restriction of this space. So with a top value of, say, 10, the top of the object must appear 10 pixels down from the top of the space.

    The ipadx and ipady fields specify internal padding i.e. space that is added to the object's size to find its "real" size. With an ipadx of 20 pixels, the object will be 40 pixels (20 for each side) wider than otherwise.

    The difference can be seen by the following applet. It sets up five buttons vertically. Buttons 1, 3 and 5 all have constraints with ipadx = ipday = 0, and insets with all fields zero. Button 2 sets its ipady to 20, and so is 40 pixels taller than normal. Button 4 sets insets.top = 20 and insets.bottom = 50, meaning that the height it requires is 70 pixels taller than the space it displays in.

    import java.awt.*;
    import java.applet.*;
    
    public class PaddingApplet extends Applet {
    
        public PaddingApplet() {
    	GridBagLayout gridbag = new GridBagLayout();
    	setLayout(gridbag);
    
    	GridBagConstraints constraints = new GridBagConstraints();
    
    	Button  btn1 = new Button("Button 1");
    	add(btn1);
    	constraints.gridx = 0;  // add in column order
    	gridbag.setConstraints(btn1, constraints);
    
    	Button btn2 = new Button("Button 2");
    	add(btn2);
    	constraints.ipady = 20;
    	gridbag.setConstraints(btn2, constraints);
    
    	Button btn3 = new Button("Button 3");
    	add(btn3);
    	constraints.ipady = 0; // reset to default
    	gridbag.setConstraints(btn3, constraints);
    
    	Button btn4 = new Button("Button 4");
    	add(btn4);
    	constraints.insets.top = 20;
    	constraints.insets.bottom = 50;
    	gridbag.setConstraints(btn4, constraints);
    
    	Button btn5 = new Button("Button 5");
    	add(btn5);
    	constraints.insets.top = 0;  // reset to default
    	constraints.insets.bottom = 0;  // reset to default
    	gridbag.setConstraints(btn5, constraints);
    
    	resize(300, 300);
        }
    }
    

    The program looks like

    This mechanism allows us to solve the problem posed earlier in "Cell sizes": in the Absolute.java five buttons were shown with corners touching. Remove the center one and the arrangement collapses to the remaining four in a 2x2 grid. The middle row and column have height and width set to zero, respectively, and don't show. To preserve the spacing of these four can be done by setting them in a 2x2 grid but setting insets to force them apart.

    If we want to set the four objects with a fixed space apart, then we can do that by just changing earlier programs to set an Insets object. If we want to set the space to between the four objects to the preferred size (or something related to preferred or minimum sizes) then it gets a bit trickier. This warrants a "sidebar" discussion, so here is an inline version:

    Diversion: widget creation

    Methods such as preferredSize() rely on the native implementation. If the native code object has not yet been created then such methods return "sensible" values such as Dimension(0, 0). The native code objects are created by peer methods such as createButton(). These are called by a GUI object's method addNotify().

    When a container calls layout() the native object has already been created, so it can do meaningful geometry calculations.

    If we want to find meaningful values for preferredSize() before this, then we have to ensure that the native object has already been created. So far, we have been relying on show() to do this.

    The Window method pack() is documented as "packs the components of the Window". It actually does something far more important than that: it calls addNotify() on itself and on all of its children. This creates the peer objects and the native implementation. From then on, whenever a container method add() is executed, it also calls addNotify() on the component.

    To be able to find the preferred/minimum size of an object before show() is executed, call pack() on the toplevel Window (or Frame), and then add() each component. Then geometry works. (For applets, packing has been done by the time the init() method is called.)

    End diversion

    To creae a "hole" that is made from the preferred size of the surrounding objects, first call pack() on the Window and then add() each component. After that it is valid to ask for preferred sizes and set this in the Insets constraint field:

    import java.awt.*;
    
    public class AbsoluteHole extends Frame {
    
        public static void main(String argv[]) {
    	new AbsoluteHole().show();
        }
    
        public AbsoluteHole() {
    	// here is the pack()
    	pack();
    	// then add the rest
    	setContents();
        }
    
        void setContents() {
    	GridBagLayout gridbag = new GridBagLayout();
    	setLayout(gridbag);
    
    	GridBagConstraints constraints = new GridBagConstraints();
    
    	// Button 1
    	Button  btn1 = new Button("Button 1");
    	add(btn1);
    	constraints.gridx = 0;
    	constraints.gridy = 0;
    
    	Dimension size = btn1.preferredSize();
    	constraints.insets = new Insets(0, 0, // top, left
    					size.height/2,  // bottom
    					size.width/2);  // right
    	gridbag.setConstraints(btn1, constraints);
    
    	// Button 2
    	Button btn2 = new Button("Button 2");
    	add(btn2);
    	constraints.gridx = 1;
    	constraints.gridy = 0;
    
    	size = btn2.preferredSize();
    	constraints.insets = new Insets(0, // top
    				size.width/2, // left
    				size.height/2,  //bottom
    				0);
    	gridbag.setConstraints(btn2, constraints);
    
    	// Button 3
    	Button btn3 = new Button("Button 3");
    	add(btn3);
    	constraints.gridx = 0;
    	constraints.gridy = 1;
    
    	size = btn3.preferredSize();
    	constraints.insets = new Insets(size.height/2, // top
    					0, 0, //left, bottom
    					size.width/2); // right
    					
    	gridbag.setConstraints(btn3, constraints);
    
    	// Button 4
    	Button btn4 = new Button("Button 4");
    	add(btn4);
    	constraints.gridx = 1;
    	constraints.gridy = 1;
    
    	size = btn4.preferredSize();
    	constraints.insets = new Insets(size.height/2, //top
    					size.width/2, //left
    					0, 0); // bottom, right
    	gridbag.setConstraints(btn4, constraints);
    	resize(300, 300);
        }
    }
    

    The program looks like

    Spanning multiple cells

    The GridBagConstraints fields gridwidth and gridheight are used to specify how many cells a component should span in that direction. For example, the following applet places three buttons in a row along the top, three down the left, with another button occupying the remaining 2x2 space:

    import java.awt.*;
    import java.applet.*;
    
    public class BigButtonApplet extends Applet { 
        Button btn1, btn2, btn3, btn4, btn5, btn6;
        GridBagLayout gridbag;   
        GridBagConstraints c;
    
        void makeButtons() {
    	btn1 = new Button("Button 1"); add(btn1);
    	btn2 = new Button("Button 2"); add(btn2);
    	btn3 = new Button("Button 3"); add(btn3);
    	btn4 = new Button("Button 4"); add(btn4);
    	btn5 = new Button("Button 5"); add(btn5);
    	btn6 = new Button("Button 6"); add(btn6);
        }
    
        public BigButtonApplet() {
    	gridbag = new GridBagLayout();
    	setLayout(gridbag);
    	c = new GridBagConstraints();
    
    	makeButtons();
    	gridbag.setConstraints(btn1, c);
    
    	c.gridx = 1;
    	c.gridy = 0;
    	gridbag.setConstraints(btn2, c);
    
    	c.gridx = 2;
    	c.gridy = 0;
    	gridbag.setConstraints(btn3, c);
    
    	c.gridx = 0;
    	c.gridy = 1;
    	gridbag.setConstraints(btn4, c);
    
    	c.gridx = 0;
    	c.gridy = 2;
    	gridbag.setConstraints(btn5, c);
    
    	c.gridx = 1;
    	c.gridy = 1;
    	c.gridwidth = 2;
    	c.gridheight = 2;
    	c.fill = GridBagConstraints.BOTH;
    	gridbag.setConstraints(btn6, c);
        }
    }
    

    The program looks like

    Note that Button 6 would normally be smaller than the space it is allocated, so fill is set to BOTH to force it to fill all of this space.

    Relatively ending rows and colums

    With relative placement of components, you can add components to the right of or below the previous component. There is also a mechanism within GridBagConstraints to allow the end of a row, or the bottom of a column to be specified. Setting gridWidth to REMAINDER makes this component the last in a row, whereas setting gridHeight to REMAINDER makes this the last in a column.

    The more I use this manager, the less I use this method. It seems much easier to use absolute positioning.

    Setting gridWidth to RELATIVE makes this component the last but one in this row. Similarly, setting gridHeight to RELATIVE makes this component the last but one in its column. I have never used this this. The possibilities for specifying inconsistent geometry seem to explode with this method!

    Weight

    The discussion so far has been in terms of placing components within cells. The size of a cell is calculated as not smaller than the biggest object that must fit inside it. When an object occupies a space larger than its preferred size, then the fill attribute specifies how it fills this space.

    There may be external constraints that act on sizes. For example, the container with a GridBagLayout may be managed by another layout manager such as GridLayout that forces the size of this container. How are these external size requests passed to the components?

    For example, in the last article we looked at aLabelledTextField, where a Label was put to the left of a TextField. The constraints on sizes were that the Label was kept at a constant size (the width of the text) whereas the TextField would stretch to fill the remaining space. This was done using a BorderLayout manager, but should be (and can be) also done with GridBagLayout.

    The fields weightx and weighty control how the manager resizes the components in response to external constraints. A weight of 0.0 means no external resizing is done. This is the default value.

    In the earlier examples, the default value was used, so the externally set size of the container was ignored. What the layout manager does in this case is to use its own internal calculations, and then place the group of objects in the center of its space.

    If we specify an object to have a weight of more than zero in a direction then the manager can resize the object to fill its available space. To take the LabelledTextField example, here is an implementation using GridBagLayout:

    import java.awt.*;
    
    public class LabelledTextField extends Panel {
        Label label;
        TextField text;
    
        public LabelledTextField(String l, int cols) {
    	GridBagLayout gridbag = new GridBagLayout();
    	setLayout(gridbag);
    
    	GridBagConstraints constraints = new GridBagConstraints();
    
    	label = new Label(l);
    	text = new TextField(cols);
    	add(label);
    	add(text);
    
    	// set resizing
    	gridbag.setConstraints(label, constraints);
    	constraints.weightx = 1.0;
    	constraints.fill = GridBagConstraints.HORIZONTAL;
    	gridbag.setConstraints(text, constraints);
       }
    
        public String getText() {
    	return text.getText();
        }
    }
    

    Using this within a program looks like

    Each component in a layout can have its own widthx and widthy. However, when it comes to laying out the components the cells in any row will all be the same size, and the cells in any column will all be the same size. So GridBagLayout needs to calculate row weights and column weights. It finds a row weight by taking the maximum value of all the x-weights in the row, and the column weight as the maximum of all the y-weights for that column.

    If there is more than one column and at least one of these has a non-zero weight, then any extra space will need to be distributed. The following example has three columns with weightx respectively of 1, 2 and 4.

    import java.awt.*;
    
    public class Weight extends Frame {
    
        public static void main(String argv[]) {
    	new Weight().show();
        }
    
        public Weight() {
    	GridBagLayout gridbag = new GridBagLayout();
    	setLayout(gridbag);
    
    	GridBagConstraints constraints = new GridBagConstraints();
    
    	Button  btn1 = new Button("Button 1");
    	add(btn1);
    	constraints.weightx = 1;
    	constraints.fill = GridBagConstraints.BOTH;
    	gridbag.setConstraints(btn1, constraints);
    
    	Button btn2 = new Button("Button 2");
    	add(btn2);
    	constraints.weightx = 2;
    	gridbag.setConstraints(btn2, constraints);
    
    	Button btn3 = new Button("Button 3");
    	add(btn3);
    	constraints.weightx = 4;
    	gridbag.setConstraints(btn3, constraints);
    
    	resize(300, 100);
        }
    }
    

    GridbagLayout distributes the extra space in proportion to the weights. To make this more concrete, suppose the preferred width of each button is 10 pixels, and the actual width available is 65 pixels. Then there are 65-30 = 35 pixels spare. The total weight of the row is 1+2+4 = 7. So Button 1 gets 1/7 of 35 i.e. 5 extra pixels to bring its width to 10+5 = 15 pixels. Button 2 gets 2/7 of 35 to bring its width to 10+10 = 20 pixels, and Button 3 gets 4/7 of 35 to bring its width to 10+20 = 30 pixels.

    To observe this resizing behaviour, the following applet (similar to the applets in the last article) may be used if you are running a Java-aware browser:

    Limitations and variations

    We have already mentioned that if a row contains no elements then its height is zero and nothing shows. There are other limitations as well. One other that I have come across is in trying to set a gridWidth or gridHeight that is too large. For example, if only one row is specified but a request is made for a height of two, then it will be shown with a height of only one.

    Layouts may display very differently with only a minor change in code. The following three layouts show versions that differ in small ways. In the first layout weightx and fill use default values. In the second layout weightx is set to 1.0. In the third layout weightx is set to 1.0 and fill to HORIZONTAL.

    The variants look like

    Conclusion

    This article has discussed the GridBagLayout manager in depth. The manager allows a tremendous amount of freedom to build complex arrangements. However it is not easy to learn, and a large amount of time will be needed to determine the best way to layout any complex arrangement.

    The next article in this series will probably be on dialogs. Some possibilities for other articles include designing layouts, menus, applets vs applications, the new event model, adding native widgets, interacting with the window manager or browser, and images. In the previous articles I have been choosing topics on what I found lacking in the existing documentation, so if you have any preferences, or other topics that you wish discussed let me know in the article evaluation comments. Thanks!

  • 相关阅读:
    eclipse-SDK-3.7-win32;eclipse-java-indigo-win32;eclipse-jee-indigo-win32 区别(ZZ)
    Marketplace Client- Download
    Log4J2基本配置
    Map 迭代 两种方法
    Python Argparse模块
    Python操作Memcached
    MySQL参数调优
    Nginx调优
    JavaScript知识点总结[部分]
    python optparser模块
  • 原文地址:https://www.cnblogs.com/aipan/p/6410388.html
Copyright © 2020-2023  润新知