The JFC Swing Tutorial: A Guide to Constructing GUIs (2nd Edition)
< Day Day Up > |
The SpringLayout [21] class was added in v1.4 to support layout in GUI builders. SpringLayout is very flexible and can emulate many of the features of other layout managers. [21] SpringLayout API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/SpringLayout.html. This section starts with a simple example showing all of the things you need to create your first spring layout ”and what happens when you forget them! Later it presents utility methods that let you lay out components in a couple of different grid types. Figures 24 through 26 show the SpringBox , SpringForm , and SpringCompactGrid examples, which illustrate three possible uses of SpringLayout . Figure 24. The SpringBox application uses SpringLayout to produce a layout similar to what BoxLayout or FlowLayout would produce.
Figure 26. SpringCompactGrid presents components in a grid without forcing all of them to be the same size .
Figure 25. The SpringForm application has five rows of label “text field pairs.
How Spring Layouts Work
Spring layouts do their job by defining relationships between the edges of components. For example, you might define the left edge of one component as a fixed distance (5 pixels, say) from the right edge of another one. By default, SpringLayout defines the width and height of a component (the distance between its left and right edges and between its top and bottom edges) as somewhere between its minimum and maximum sizes ”if possible, at its preferred size. Distances between edges are represented by Spring [22] objects. Each spring has four properties ”its minimum, preferred , and maximum values and its actual (current) value . The springs associated with each component are collected in a SpringLayout.Constraints [23] object, which is like a java.awt.Rectangle except that its values are Spring objects rather than integers. [22] SpringLayout API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/Spring.html. [23] SpringLayout.Constraints API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/SpringLayout.Constraints.html. Example: SpringDemo
public class SpringDemo1 { ... //Where the GUI is created: Container contentPane = frame.getContentPane() SpringLayout layout = new SpringLayout(); contentPane.setLayout(layout); contentPane.add(new JLabel("Label: ")); contentPane.add(new JTextField("Text field", 15)); ... frame.pack(); frame.setVisible(true); } Figure 27 shows what the GUI looks like when it first comes up. Figure 27. SpringDemo1 ”the GUI starts out so small because the parent has no initial size.
Figure 28 shows what it looks like when it's resized to be bigger. Figure 28. SpringDemo1 after it has been resized ”the components overlap because all are at (0,0).
Obviously, we have some problems. Not only does the frame come up too small, but even when it's resized the components are all located at (0,0). This happens because we didn't set any springs specifying the components' positions and the width of the container. One small consolation is that the components are at their preferred sizes ”we get that for free from the default springs created by SpringLayout for each component.
//Adjust constraints for the label so it's at (5,5). layout.putConstraint(SpringLayout.WEST, label, 5, SpringLayout.WEST, contentPane); layout.putConstraint(SpringLayout.NORTH, label, 5, SpringLayout.NORTH, contentPane); The first putConstraint call specifies that the label's west (left) edge should be 5 pixels from its container's west edge. This translates to an x coordinate of 5. The second putConstraint call sets up a similar relationship between the north (top) edges of the label and its container, resulting in a y coordinate of 5. Here's the code that sets up the location of the text field: //Adjust constraints for the text field so it's at //(<label's right edge> + 5, 5). layout.putConstraint(SpringLayout.WEST, textField, 5, SpringLayout.EAST, label); layout.putConstraint(SpringLayout.NORTH, textField, 5, SpringLayout.NORTH, contentPane); The first putConstraint call puts the text field's west (left) edge 5 pixels away from the label's east (right) edge. The second putConstraint call is just like the code that set the label's y coordinate, and it has the same effect for the text field. We still have the problem of the container coming up too small. But when we resize the window, the components are in the right place, as seen in Figure 29. Figure 29. SpringDemo2 , an improved application with all of the components in their correct positions.
Here's the code that sets the container's springs: layout.putConstraint(SpringLayout.EAST, contentPane, 5, SpringLayout.EAST, textField); layout.putConstraint(SpringLayout.SOUTH, contentPane, 5, SpringLayout.SOUTH, textField); The first putConstraint call puts the container's right edge 5 pixels to the right of the text field's right edge. The second one puts its bottom edge 5 pixels beyond the bottom edge of the tallest component (which, for simplicity's sake, we've assumed is the text field). Finally, the window comes up at the right size (see Figure 30). Figure 30. SpringDemo3 with the window (or "container") now at the correct initial size.
When we make the window larger, we can see the spring layout in action, distributing the extra space between the available components (Figure 31). In this case, the spring layout has given all of the extra space to the text field. Figure 31. A screenshot of SpringDemo3 after it has been enlarged.
Although it seems like it treats labels and text fields differently, SpringLayout has no special knowledge of any Swing or AWT components. Instead, it relies on the values of a component's minimum, preferred, and maximum size properties. The next section discusses how SpringLayout uses these properties and why they can cause uneven space distribution. Springs and Component Size
A SpringLayout object automatically installs springs for the height and width of each component it controls. These springs are essentially covers for the component's getMinimumSize , getPreferredSize , and getMaximumSize methods. By "covers" we mean not only that the springs are initialized with the appropriate values from these methods but also that they track those values. For example, the Spring object that represents the width of a component is a special kind of spring that simply delegates its implementation to the component's relevant size methods. That way it stays in sync with the size methods as the characteristics of the component change. When a component's getMaximumSize and getPreferredSize methods return the same value, SpringLayout interprets this as that the component shouldn't be stretched . JLabel and JButton are examples of components implemented this way, which is why the label in SpringDemo3 doesn't stretch. The getMaximumSize method of some components, such as JTextField , returns the value Integer.MAX_VALUE for the width and height of its maximum size, indicating that the component can grow to any size. For this reason, when the SpringDemo3 window is enlarged, SpringLayout distributes all of the extra space to the only springs that can grow ”those determining the size of the text field. Alternative Expressions
The SpringDemo examples used the SpringLayout method putConstraint to set the springs associated with each component. putConstraint is a convenience method that lets you modify springs without using the full SpringLayout API. Here, again, is the code from SpringDemo2 that sets the location of the label: layout.putConstraint(SpringLayout.WEST, label, 5, SpringLayout.WEST, contentPane); layout.putConstraint(SpringLayout.NORTH, label, 5, SpringLayout.NORTH, contentPane); Here's equivalent code that uses the SpringLayout.Constraints and Spring classes directly: SpringLayout.Constraints labelCons = layout.getConstraints(label); labelCons.setX(Spring.constant(5)); labelCons.setY(Spring.constant(5));
As the preceding code snippets imply, SpringLayout and SpringLayout.Constraints tend to use different conventions for describing springs. The SpringLayout API uses edges, which are specified by these constants:
The SpringLayout.Constraints class knows about edges, but only has Spring objects for the following properties:
Each Constraints object maintains the following relationships between its springs and the edges they represent: west = x north = y east = x + width south = y + height If you're confused , don't worry. The next section presents utility methods you can use to accomplish some common layout tasks without knowing anything about the SpringLayout API. Utility Methods for Grids
Because the SpringLayout class was created for GUI builders, setting up individual springs for a layout can be cumbersome to code by hand. This section presents a couple of methods you can use to install all of the springs needed to lay out a group of components in a grid. These methods emulate some of the features of the GridLayout , GradBagLayout , and BoxLayout classes. The two methods ” makeGrid and makeCompactGrid ”are defined in SpringUtilities. java . [28] Both work by grouping components into rows and columns and by using the Spring.max method to make a width or height spring that enlarges a row or column enough to fit all components in it. In the makeCompactGrid method, the same width or height spring is used for all components in a particular column or row, respectively. By contrast, in the makeGrid method, the width and height springs are shared by all components, forcing them to be all the same size. [28] You can find SpringUtilities.java here: JavaTutorial/uiswing/layout/example-1dot4/SpringUtilities.java .
Figure 32. The SpringGrid GUI.
Here's the code that creates and lays out the text fields in SpringGrid : JPanel panel = new JPanel(new SpringLayout()); ... for (int i = 0; i < 9; i++) { JTextField textField = new JTextField(Integer.toString(i)); ...//when i==4, put long text in the text field... panel.add(textField); } ... SpringUtilities.makeGrid(panel, 3, 3, //rows, cols 5, 5, //initialX, initialY 5, 5);//xPad, yPad Now let's look at an example, in the source file SpringCompactGrid.java , that uses the makeCompactGrid method instead of makeGrid (see Figure 33). This example displays lots of numbers to show off SpringLayout 's ability to minimize the space required. Figure 33. The SpringCompactGrid GUI.
JPanel panel = new JPanel(new SpringLayout()); int rows = 10; int cols = 10; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { int anInt = (int) Math.pow(r, c); JTextField textField = new JTextField(Integer.toString(anInt)); panel.add(textField); } } //Lay out the panel. SpringUtilities.makeCompactGrid(panel, //parent rows, cols, 3, 3, //initX, initY 3, 3); //xPad, yPad One of the handiest uses for makeCompactGrid is associating labels with components, where the labels are in one column and the components are in another (see Figure 34). Figure 34. SpringForm uses the makeCompactGrid method to associate labels with components.
String[] labels = {"Name: ", "Fax: ", "Email: ", "Address: "}; int numPairs = labels.length; //Create and populate the panel. JPanel p = new JPanel(new SpringLayout()); for (int i = 0; i < numPairs; i++) { JLabel l = new JLabel(labels[i], JLabel.TRAILING); p.add(l); JTextField textField = new JTextField(10); l.setLabelFor(textField); p.add(textField); } //Lay out the panel. SpringUtilities.makeCompactGrid(p, numPairs, 2, //rows, cols 6, 6, //initX, initY 6, 6); //xPad, yPad Because we're using a real layout manager instead of absolute positioning, the layout manager responds dynamically to changes in the components involved. For example, if the names of the labels are localized, the SpringLayout produces a configuration that gives the first column more or less room as needed. And, as Figure 35 shows, when the window is resized the flexibly sized components ”the text fields ”take all the excess space while the labels stick to what they need. Figure 35. SpringForm after it has been enlarged.
Our last example of the makeCompactGrid method, in SpringBox.java , shows some buttons configured to be laid out in a single row (see Figure 36). Figure 36. The SpringBox application.
Note that the behavior is almost identical to that of BoxLayout in the case of a single row. Not only are the components laid out as BoxLayout would arrange them but the minimum, preferred, and maximum sizes of the container that uses SpringLayout return the same results that BoxLayout would. The following is the call to makeCompactGrid that produces this layout: //Lay out the buttons in one row and as many columns //as necessary, with 6 pixels of padding all around. SpringUtilities.makeCompactGrid(contentPane, 1, contentPane.getComponentCount(), 6, 6, 6, 6); Let's look at what happens when we resize this window (see Figure 37). This is an odd special case that's worth noting, as you may run into it by accident in your first layouts. Figure 37. SpringBox after it has been enlarged.
Nothing moved! That's because none of the components (buttons) or the spacing between them was defined to be stretchable. In this case, the SpringLayout calculates a maximum size for the parent container that's equal to its preferred size, meaning that the parent container itself isn't stretchable. It might be less confusing if the AWT refused to resize a window that wasn't stretchable, but it doesn't. Maximum and minimum sizes for windows are "recommendations" that the AWT defies when given suitable user input. The layout manager can't do anything sensible here, because none of the components take up the required space. Instead of crashing, it just does nothing, leaving all of the components as they were. The SpringLayout API
The API for SpringLayout is larger than that for most layout managers. It's spread across three classes. Table 11 lists the constructors and methods for the SpringLayout class; Table 12, for the SpringLayout.Constraints class; and Table 13, for the Spring class. Also consult the API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/SpringLayout.html http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/SpringLayout.Constraints.html http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/Spring.html Table 11. SpringLayout Constructors and Methods
Table 12. SpringLayout.Constraints Constructors and Methods
Table 13. Spring Methods
Examples That Use SpringLayout
The following table lists some examples that use spring layout.
|
< Day Day Up > |