Blakes 21 Days Chapter 11 Document
Day 11, Arranging Components on a User Interface
- Top
- 313 If designing a graphical user interface (GUI) were comparable to painting, currently you could produce only one kind of art: abstract expressionism.
- You can put components on an interface, but you can't control where they go.
- 313 To arrange the components of a user interface in Java, you must use a set of classes called layout managers.
- 313 Today, you will learn how to use layout managers to arrange components in an interface.
- You will take advantage of the flexibility of Java's graphical user interface capabilities, which were designed to be presentable on the many platforms that support the language.
- 313 You also will learn how to put several layout managers to work on the same interface.
- This approach is for the many times when one layout manager doesn't suit the exact interface you seek to design.
Basic Interface Layout
- Top
- 314 As you learned yesterday, a GUI designed with Swing is a fluid thing.
- Resizing a window can wreak havoc on your interface, because components move to places on a container that you might not have intended.
- 314 This fludity is a necessary part of Java's support for different platforms,
- where there are subtle differences in how each platform displays things such as buttons, scrollbars, and other parts of a user interface.
- 314 With some programming languages, a component's location on a window is precisely defined by its (x,y) coordinate.
- Some Java development tools allow similar control over an interface thru the use of their own windowing classes,
- (and there's a way to do that in Java).
- reserve
- 314 When using Swing, a programmer gains more control over the layout of an interface by using layout managers.
- 314 The platform-independent nature of Swing provides flexibility at the cost of slower performance
- and a user interface look and feel that doesn't closely match the native look and feel of the operating system.
Laying Out an Interface
- Top
- 314 A layout manager determines how components will be arranged when they are added to a container.
- 314 The default layout manager for panels is the FlowLayout class.
- This class lets components flow from left to right in the order in which they are added to a container.
- When there's no more room, a new row of components begins immediately below the first, and the left-to-right order continues.
- 314 Java includes a bunch of general-purpose layout managers:
- BorderLayout, BoxLayout, CardLayout, FlowLayout, and GridLayout.
- To create a layout manager for a container, first call its constructor to create an instance of the class, as in this example:
- FlowLayout flo = new FlowLayout();
- After you create a layout manager, you designate it as the layout manager for a container by using the container's setLayout() method.
- The layout manager must be set before any components are added to the container.
- If no layout manager is specified, the container's default layout is used.
- The default is FlowLayout for panels and BorderLayout for frames.
- Top
- 315 The following statements represent the starting point for a frame that uses a layout manager to control the arrangement of all components that will be added to the frame:
import java.awt.*;
import havax.swing.*
public class Starter extends JFrame {
public Starter() {
super("Example Frame");
FlowLayout manager = new FlowLayout();
setLayout(manager);
// add components here
}
}
- Top
- 315 After the layout manager is set, you can start adding components to the container it manages.
- For some of the layout managers, such as FlowLayout, the order in which components are added is significant.
- You'll see this as you work with each of the managers.
Flow Layout
- Top
- 315 The FlowLayout class in the java.awt package is the simplest layout manager.
- It lays out components in rows in the same way that words are laid out on a page in English,
- from left to right until there's no more room at the right edge,
- and then on to the left edge on the next row.
- reserve
- 315 By default, the components in each row are centered when you use the FlowLayout() constructor with no arguments.
- If you want the components to be aligned along the left or right edge of the container,
- you can use the FlowLayout.LEFT or FlowLayout.RIGHT class variable as the constructor's only argument, as in the following statement:
- FlowLayout righty = new FlowLayout(FlowLayout.RIGHT);
- The FlowLayout.CENTER class variable specifies a centered alignment for components.
- Top
- 315 NOTE: If you need to align components for a non-English-speaking audience where left-to-right order does not make sense,
- you can use the FlowLayout.LEADING and FlowLayout.TRAILING variables.
- They set justification to the side of either the first component in a row or the last, respectively.
First Program
- Top
- 316 The Alphabet application, shown in Listing 11.1, displays six buttons arranged by the flow layout manager.
- Because the FlowLayout.LEFT class variable is used in the FlowLayout() constructor, the components are lined up along the left side of the application window.
- 316 Create this application in NetBeans in the com.java21days package.
Listing 11.1 The Full Text of Alphabet.java
- Top
- page 316-317
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Alphabet extends JFrame {
public Alphabet() {
super("Alphabet");
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
setSize(360, 120);
FlowLayout lm = new FlowLayout(FlowLayout.LEFT);
setLayout(lm);
JButton a = new JButton("Alibi");
JButton b = new JButton("Burglar");
JButton c = new JButton("Corpse");
JButton d = new JButton("Deadbeat");
JButton e = new JButton("Evidence");
JButton f = new JButton("Fugitive");
add(a);
add(b);
add(c);
add(d);
add(e);
add(f);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception e) {
System.err.println("Couldn't use the system "
+ "look and feel: " + e);
}
}
public static void main(String[] arguments) {
Alphabet frame = new Alphabet();
}
}
The Explanation
- Top
- 317 Figure 11.1 shows the application running.
Figure 11.1 - Six buttons arranged by a flow layout manager - goes here
- Top
- 317 The Alphabet application creates a flow layout manager in line 14 and sets it to manage the frame in line 15.
- The buttons added to the frame in lines 22 - 27 are arranged by this manager.
- 317 The manager uses the default gap of 5 pixels between each component on a row and a gap of 5 pixels between each row.
- You can change the horizontal and vertical gap between components with some extra arguments to the FlowLayout() constructor
- or by calling flow layout's setVgap(int) and setHgap(int) methods with the desired vertical or horizontal gap.
- Top
- 317 The FlowLayout(int, int, int) constructor takes the following three arguments, in order:
- The alignment, which must be one of five class variables of FlowLayout: CENTER, LEFT, RIGHT, LEADING, or TRAILING
- The horizontal gap between components, in pixels
- The vertical gap, in pixels
- 317 The following constructor creates a flow layout manager with centered components, a horizontal gap of 30 pixels, and a vertical gap of 10 pixels:
- FlowLayout flo = new FlowLayout(FlowLayout.CENTER, 30, 10);
Box Layout
- Top
- 317 The next layout manager can be used to stack components from top to bottom or from left to right.
- Box layout, managed by the BoxLayout class in the javax.swing package,
- improves on flow layout by ensuring that components always line up vertically or horizontally, regardless of how their container is resized.
- Top
- 318 A box layout manager must be created with two arguments to its constructor:
- the container it will manage
- and a class variable that sets up the vertical or horizontal alignment.
- 318 The alignment, specified with class variables of the BoxLayout class, can be X_AXIS for top-to-bottom vertical alignment.
- 318 The following code sets up a panel to use vertical box layout:
JPanel optionPane = new JPanel();
BoxLayout box = new BoxLayout(optionPane, BoxLayout.Y_AXIS);
optionPane.setLayout(box);
- 318 Components added to the container will line up on the specified axis and will be displayed at their preferred sizes.
- In horizontal alignment, the box layout manager attempts to give each component the same height.
- In vertical alignment, the manager attempts to give each one the same width.
Second Program
- Top
- 318 The Stacker application, shown in Listing 11.2, contains a panel of buttons arranged with box layout.
- 318 Create it in NetBeans in the com.java21days package.
Listing 11.2 The Full Text of Stacker.java
- Top
- page 318-319
package com.java21days;
import java.awt.*;
import javax.swing.*;
public class Stacker extends JFrame {
public Stacker() {
super("Stacker");
setSize(430, 150);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
// create top panel
JPanel cammandPane = new JPanel();
BoxLayout horizontal = new BoxLayout(commandPane,
BoxLayout.X_AXIS);
commandPane.setLayout(horizontal);
JButton subscribe = new JButton("Subscribe");
JButton unsubscribe = new JButton("Unsubscribe");
JButton refresh = new JButton("Refresh");
JButton save = new JButton("Save");
commandPane.add(subscribe);
commandPane.add(unsubscribe);
commandPane.add(refresh);
commandPane.add(save);
// create a bottom panel
JPanel textPane = new JPanel();
JTextArea text = new JTextArea(4, 70);
JScrollPane scrollPane = new JScrollPane(text);
// put them together
FlowLayout flow = new FlowLayout();
setLayout(flow);
add(commandPane);
add(scrollPane);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception e) {
System.err.println("Couldn't use the system "
+ "look and feel: " + e);
}
}
public static void main(String[] arguments) {
Alphabet frame = new Alphabet();
}
}
The Explanation
- Top
- 319 When the class is compiled and run, the output should resemble Figure 11.2
Figure 11.2 - A user interface with buttons arranged with the box layout manager - goes here
- Top
- 319 This application creates a JPanel container named commandPane in line 13,
- creates a box layout manager associated with that pane in lines 14- 15,
- and sets that manager for the panel in line 16.
- 319 The panel of buttons along the top edge of the interface is stacked horizontally.
- If the second argument to the box layout constructor was BoxLayout.Y_AXIS, the buttons would be arranged vertically instead.
Grid Layout
- Top
- 320 The grid layout manager arranges components into a grid of vertical columns and horizontal rows like the days on a 12-month calendar.
- Components are added first to the top row of the grid, beginning with the leftmost grid cell and continuing to the right.
- When all the cells in the top row are full, the next component is added to the leftmost cell in the second row of the grid,
- if there is a second row, and so on.
- 320 Grid layout managers are created with the GridLayout class, which belongs to the java.awt package.
- Two arguments are sent to the GridLayout constructor: the number of rows and the number of columns in the grid.
- 320 The following statement creates a grid layout manager with 10 rows and 3 columns:
- GridLayout gr = new GridLayout(10, 3);
- 320 As with flow layout, you can specify a vertical and horizontal gap between components with two extra arguments
- (or by calling the setHgap() or setVgap() methods).
- The following statement creates a grid layout with 10 rows and 3 columns, a horizontal gap of 5 pixels, and a vertical gap of 8 pixels:
- GridLayout gr2 = new GridLayout(10, 3, 5, 8);
- 320 The default gap between components arranged in grid layout is 0 pixels in both vertical and horizontal directions.
Third Program
- Top
- 320 For the next project, create the Bunch application in the com.java21days package, which is shown in Listing 11.3.
- The program creates a grid with 3 rows, 3 columns, and a 10-pixel gap between components in both the vertical and horizontal directions.
Listing 11.3 The Full Text of Bunch.java
- Top
- page 320-321
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Bunch extends JFrame {
public Bunch() {
super("Bunch");
setSize(260, 260);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
JPanel pane = new JPanel();
GridLayout family = new GridLayout(3, 3, 10, 10);
pane.setLayout(family);
JButton marcia = new JButton("Marcia");
JButton carol = new JButton("Carol");
JButton greg = new JButton("Greg");
JButton jan = new JButton("Jan");
JButton alice = new JButton("Alice");
JButton peter = new JButton("Peter");
JButton cindy = new JButton("Cindy");
JButton mike = new JButton("Mike");
JButton bobby = new JButton("Bobby");
pane.add(marcia);
pane.add(carol);
pane.add(greg);
pane.add(jan);
pane.add(alice);
pane.add(peter);
pane.add(cindy);
pane.add(mike);
pane.add(bobby);
add(pane);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception e) {
System.err.println("Couldn't use the system "
+ "look and feel: " + e);
}
}
public static void main(String[] arguments) {
Bunch frame = new Bunch();
}
}
The Explanation
- Top
- 321 Figure 11.3 shows this application
- 321 The Bunch application displays nine buttons in a grid.
- The buttons are added to a pane in lines 26 - 34, and the pane is added to the frame in line 35.
- 321 One thing to note about the buttons in Figure 11.3 is that they expanded to fill the space available to them in each cell.
- This is an important difference between grid layout and some of the other layout managers,
- which display components at a much smaller size by using the preferred size of those components.
Figure 11.3 - Nine buttons arranged in a 3 x 3 grid layout - goes here
Border Layout
- Top
- 322 The layout managers introduced so far have been fairly simple.
- The next one employs a more complex arrangement called border layout.
- 322 This layout is created by using the BorderLayout class in the java.awt package, which divides a container into five sections:
- north, south, east, west, and center.
- The five areas in Figure 11.4 show how these sections are arranged.
Figure 11.4 - Components arranged by a border layout manager - goes here
- Top
- 322 In border layout, the components represented by the four compass points fill their sections, and the center component gets all the space that's left over.
- Ordinarily, this results in an arrangement with a large central component and four smaller components around it.
- The preferred sizes of the components are not followed by the layout manager.
- 322 A border layout is created with either the BorderLayout() or BorderLayout(int, int) constructors.
- The first constructor creates a border layout with no gap between anu of the components.
- The second constructor uses arguments to specify the horizontal gap and vertical gap, in that order, and setVgap() and setHgap() also are available.
- Top
- 323 After you create a border layout and set it up as a container's layout manager,
- components are added using a call to the add() method that's different from the ones seen previously:
- The first argument is the component that should be added to the container.
- The second argument is a BorderLayout class variable that indicates the region of the border layout to which the component should be assigned.
- The class variables NORTH, SOUTH, EAST, WEST, and CENTER can be used for this argument.
- 323 The following statement adds a button called quitButton to the north portion of a border layout:
JButton quitButton = new JButton("Quit");
add(quitButton, BorderLayout.NORTH);
Fourth Program
- Top
- 323 The Border application, shown in Listing 11.4 creates the GUI shown earlier in Figure 11.4
- Create the Border class in the com.java21days package.
Listing 11.4 The Full Text of Border.java
- Top
- page 323-324
package com.java21days;
import java.awt.*;
import javax.swing.*;
public class Border extends JFrame {
public Border() {
super("Border");
setSize(240, 280);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
setLayout(new BorderLayout());
JButton nButton = new JButton("North");
JButton sButton = new JButton("South");
JButton eButton = new JButton("East");
JButton wButton = new JButton("West");
JButton cButton = new JButton("Center");
pane.add(nButton, BorderLayout.NORTH);
pane.add(sButton, BorderLayout.SOUTH);
pane.add(eButton, BorderLayout.EAST);
pane.add(wButton, BorderLayout.WEST);
pane.add(cButton, BorderLayout.CENTER);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception e) {
System.err.println("Couldn't use the system "
+ "look and feel: " + e);
}
}
public static void main(String[] arguments) {
Bunch frame = new Bunch();
}
}
The Explanation
- Top
- 324 The Border application is a frame that sets its layout manager in a new way in line 13.
- The call to the new BorderLayout() constructor returns a BorderLayout object, which then becomes the argument to the setLayout() method.
- 324 Line 13 is equivalent to the following two statements:
BorderLayout bl = new BorderLayout();
setLayout(bl);
- The advantage of the technique employed in line 13 is that there's no need to create a variable and assign the BorderLayout object to it.
- That object's never needed after the layout manager is designated for the frame.
- The application creates the five buttons in lines 14 - 18 and assigns them to positions in the border layout in lines 19 - 23.
- Top
- 324 TIP: When you run the application, increase the window size several times to see how the components respond.
- As the window becomes larger, the center component grows accordingly.
- The other components stay the same.
- This is an advantage of the grid and border layout managers.
Mixing Layout Managers
- Top
- 324 At this point, you might be wondering how Java's layout managers can be used on the GUIs you want to design for your own programs.
- Choosing a layout manager is an experience akin to Goldilocks checking out the home of the three bears:
- This one is too square! This one is too disorganized! This one is too strange!
- 325 To find the layout that is just right, you often have to combine more than one manager within the same interface.
- You can do so by putting several containers inside a larger container and giving each of the smaller containers its own layout manager.
- The container to use for these smaller containers is the panel, which is created from the JPanel class in the javax.swing package.
- Panels are simple containers used to group components.
- Keep in mind two things when working with panels:
- The panel is filled with components before it is put into a larger container.
- The panel has its own layout manager.
- Panels are created with a simple call to the constructor of the JPanel class, as shown in the following example:
- JPanel pane = new JPanel();
- You set the layout method for a panel by calling the setLayout() method on that panel.
- Here's how to create a layout manager and apply it to a JPanel object called pane:
FlowLayout flo = new FlowLayout();
pane.setLayout(flo);
- Top
- 325 You add components to a panel by calling the panel's add() method, which works the same for panels as it does for other containers.
- The following statements create a text field and add it to a JPanel object called pane:
JTextField nameField = new JTextField(80);
pane.add(nameField);
- 325 You'll see several examples of panel use in the rest of today's applications.
- 325 As you gain experience with layout managers, you get a feel for which ones to use in specific situations.
- For instance, border layout is good for putting a status line at the bottom and a toolbar at the top,
- and grid layout is effective for rows and columns of text fields and labels that take the same size.
Card Layout
- Top
- 325 A card layout manager differs from the other layout managers because it hides some components from view.
- A card layout is a group of containers or components displayed one at a time,
- in the same way that a blackjack dealer reveals one card at a time from a deck.
- Each container in the group is called a card.
- 326 If you have used a wizard in an installation program, you have seen card layout.
- Each step in the installation process has its own card.
- Often, a Next button advances from one card to the next.
- 326 The most common way to use a card layout is to use a panel container for each card.
- Components are added to the panels first, and then the panels are added to the container that employs card layout.
- Top
- 326 A card layout is created from the CardLayout class in the java.awt package with a simple constructor:
- CardLayout cc = new CardLayout();
- 326 The setLayout() method makes this the layout manager for the container, as in the following statement:
- 326 After you set a container to use the card manager, you must use the add(Component, String) method to add components.
- 326 The first argument to the add() method specifies the container or component that serves as a card.
- If it is a container, all components must be added to it before the card is added.
- 326 The second argument is a string that names the card.
- This can be anything you want to call the card, such as "Card 1", "Card 2", "Card 3", or some other naming scheme.
- Top
- 326 The following statement adds a panel object named options to a container and names this card "Options Card":
- add(options, "Options Card");
- 326 When a container using card layout is displayed for the first time, the visible card is the first card added to the container.
- 326 You can display subsequent cards by calling the show() method of the layout manager, which takes two arguments:
- The container holding the cards
- The name of the card
- 326 The following statement calls the show() method of a card layout manager called cc:
- cc.show(this, "Fact Card");
- Top
- 327 The this keyword would be used in a frame goverened by card layout.
- It refers to the object inside which the cc.show() statement appears.
- In this example, "Fact Card" is the name of the card to reveal.
- A card is added to the container that has been given this name.
- 327 When a card is shown, the previously displayed card is hidden automatically.
- Only one card in a card layout can be shown at a time.
- 327 In a program that uses the card layout manager, a card change generally is triggered by a user's action.
- For example, in an installation program, a user could choose a folder where the program should be saved and click the Next button to see the next card.
Using Card Layout in an Application - Fifth Program
- Top
- 327 The next project demonstrates both card layout and the use of different layout managers within the same GUI.
- 327 The SurveyWizard class is a panel that implements a wizard interface:
- a series of simple questions accompanied by a Next button that is used to see the subsequent question.
- The last question has a Finish button instead and is shown in Figure 11.5
Figure 11.5 - Using a card layout for a wizard-style interface - goes here
- Top
- 327 The easiest way to implement a card-based layout is to use panels.
- This project uses several panels:
- The SurveyWizard class is a panel that holds all the cards.
- The SurveyPanel helper class is a panel that holds one card.
- Each SurveyPanel object contains three panels stacked on top of each other
- 327 The SurveyWizard and SurveyPanel classes are both panels, the easiest component to use when working with card layout.
- Each card is created as a panel and is added to a containing panel that will be used to show them in sequence.
- Top
- 328 This takes place in the SurveyWizard() constructor,
- using two instance variables, a card layout manager, and an array of three SurveyPanel objects:
SurveyPanel[] ask = new SurveyPanel[3];
CardLayout cards = new CardLayout();
- The constructor sets the class to use the layout manager, creates each SurveyPanel object, and then adds it to the class:
setLayout(cards);
String question1 = "What is your gender?";
String() reap1 = { "female", "male", "not telling" };
ask[0] = new SurveyPanel(question1, reap1, 2);
add(ask[0], "Card 0");
- Top
- 328 Each SurveyPanel object is created with three arguments to the constructor:
- the text of the question,
- an array of possible responses,
- and the element number of the default answer.
- 328 In the preceding code, the question "What is your gender?" has the responses "female", "male", and "not telling".
- The response at position 2, "not telling", is set as the default.
- Top
- 328 The SurveyPanel constructor uses a label component to hold the question and an array of radio buttons to hold the responses:
SurveyPanel(Sting ques, String[] resp, int def) {
question = new JLabel(ques);
response = new JRadioButton[resp.length);
// more to come
}
- Top
- 328 The class uses grid layout to arrange its components into a grid with three vertical columns and one horizontal row.
- Each component placed in the grid is a panel.
- 328 First, a panel is created to hold the question label:
JPanel sub1 = new JPanel();
JLabel question1 = new JLabel(ques);
sub1.add(quesLabel);
- Top
- 328 The default layout for panels, flow layout with centered alignment, determines the placement of the label on the panel.
- 328 Next, a panel is created to hold the possible responses.
- A for loop iterates thru the string array that holds the text of each response.
- This text is used to create a radio button.
- The second argument of the JRadioButton() constructor determines whether it is selected.
- This is implemented with the following code:
JPanel sub2 = new JPanel();
for (int i = 0; i < resp.length; i++) {
if (def == i) {
response[i] = new JRadioButton(reap[i], true);
} else {
response[i] = new JRadioButton(reap[i], false);
}
group.add(response[i]);
sub2.add(response[i]);
}
- Top
- 329 The last panel holds the Next anf Finish buttons:
JPanel sub1 = new JPanel();
nextButton.setEnabled(true);
sub3.add(nextButton);
finalButton.setEnabled(true);
sub3.add(finalButton);
- Top
- 329 Now that the three panels have been fully set up,
- they are added to the SurveyPanel interface, which completes the work of the constructor method:
GridLayout grid = new GridLayout(3, 1);
setLayout(grid);
add(sub1);
add(sub2);
add(sub3);
- Top
- 329 There's one extra wrinkle in the SurveyPanel class,
- a method that enables the Finish button and disables the Next button when the last question has been reached:
void setFinalQuestion(boolean finalQuestion) {
if (finalQuestion) {
nextButton.setEnabled(false);
finalButton.setEnabled(true);
}
}
- Top
- 329 In a user interface that uses card layout, the display of each card usually takes place in response to an action by the user.
- 329 These actions are called events, which are covered on Day 12, "Responding to User Input."
- 330 A brief preview demonstrates how the SurveyPanel class is equipped to handle button clicks.
- 330 The class implements ActionListener, an interface in the java.awt.event package:
public class SurveyWizard extends JPanel implements ActionListener {
// more to come
}
- 330 This interface indicates that the class can respond to action events,
- which represent button clicks, menu choices, and similar user input.
- Top
- 330 Next, each button's addActionListener(Object) method is called:
ask[0].nextButton.addActionListener(this);
ask[0].finalButton.addActionListener(this);
- Listeners are classes that monitor specific kinds of user input.
- The argument to addActionListener() is the class that's looking for action events.
- Using this as the argument indicates that the SurveyPanel class handles this job.
- 330 The ActionListener interface includes only one method:
public void actionPerformed(Action evt) {
// more to come
}
- This method is called when a component being listened to generates an action event.
- In SurveyPanel, this method uses an instance variable that keeps track of which card to display:
- Every time a button is clicked and the actionPerformed() method is called, this variable is incremented,
- and the card layout manager's show(Container, String) method is called to display a new card.
- If the last card has been displayed, the Finish button is disabled.
Fifth Program
- Top
- 330 Listing 11.5 shows the full SurveyWizard class with the complete actionPerformed() method.
- Create a new empty Java file in NetBeans called SurveyWizard, assigning it to the com.java21days package.
Listing 11.5 The Full Text of SurveyWizard.java
- Top
- page 331-332
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SurveyWizard extends JFrame implements ActionListener {
int currentCard = 0;
CardLayout cards = new CardLayout();
SurveyPanel[] ask = new SurveyPanel(3);
public SurveyWizard() {
super();
setSize(240, 140);
setLayout(cards);
// set up survey
String question1 = "What is your gender?";
Sting[] resp1 = { "female", "male", "not telling" };
ask[0] = new SurveyPanel(question1, resp1, 2);
String question2 = "What is your age?";
Sting[] resp2 = { "Under 25", "25-34", "35-54",
"Over 54");
ask[1] = new SurveyPanel(question2, resp2, 1);
String question3 = "How often do you exercise each week?";
Sting[] resp3 = { "Never", "1-3 times", "More than 3" };
ask[2] = new SurveyPanel(question3, resp3, 1);
ask[2].setFinalQuestion(true);
addListeners();
}
private void addListeners() {
for (int i = 0; i < ask.length; i++) {
ask[i].nextButton.addActionListener(this);
ask[i].finalButton.addActionListener(this);
add(ask[i], "Card " + i);
}
}
public void actionPerformed(ActionEvent evt) {
currentCar++;
if (currentCard >= ask.length) {
System.exit(0);
}
cards.show(this, "Card " + currentCard);
}
}
class SurveyPanel extends JPanel {
JLabel question;
JRadioButton[] response;
JButton nextButton = new JButton("Next");
JButton finalButton = new JButton("Finish");
SurveyPanel(String ques, String[] resp, int def) {
super();
setSize(160, 110);
question = new JLabel(ques);
response = new JRadioButton[resp.length];
JPanel sub1 = new JPanel();
ButtonGroup group = new ButtonGroup();
JLabel quesLabel = new JLabel(ques);
sub1.add(quesLabel);
JPanel sub2 = new JPanel();
for (int i = 0; i < resp.length; i++) {
if (def == i) {
response[i] = new JRadioButton(reap[i], true);
} else {
response[i] = new JRadioButton(reap[i], false);
}
group.add(response[i]);
sub2.add(response[i]);
}
JPanel sub3 = new JPanel();
nextButton.setEnabled(true);
sub3.add(nextButton);
GridLayout grid = new GridLayout(3, 1);
setLayout(grid);
add(sub1);
add(sub2);
add(sub3);
}
void setFinalQuestion(boolean finalQuestion) {
if (finalQuestion) {
nextButton.setEnabled(false);
finalButton.setEnabled(true);
}
}
}
The Explanation
- Top
- 332 The SurveyWizard class is a JPanel component that creates a card layout manager as an instance variable in line 9
- and assigns it to the panel in line 15.
- This class lacks a main() method, so it must be added to another program's user interface to be tested.
Sixth Program
- Top
- 332 The SurveyFrame application, shown in Listing 11.6, contains a frame that displays a survey panel.
- Create it in NetBeans (package com.java21days).
Listing 11.6 The Full Text of SurveyFrame.java
- Top
- page 333
package com.java21days;
import java.awt.*;
import javax.swing.*;
public class SurveyFrame extends JFrame {
public SurveyFrame() {
super("Survey");
setSize(290, 140);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
SurveyWizard wiz = new SurveyWizard());
add(wiz);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
SurveyFrame frame = new SurveyFrame();
}
}
The Explanation
- Top
- 333 A SurveyWizard object is created in line 12 and is added to the frame in line 13.
- The running application was shown earlier in Figure 11.5
- reserve
Cell Padding and Insets
- Top
- 333 By default, no components have extra space around them
- (which is easiest to see in components that fill their cells).
- 333 The horizontal and vertical gaps that appear when you create a new layout manager
- are used to determine the amount of space between components in a panel.
- Insets, however, are used to determine the amount of space around the panel itself.
- The Insets class includes values for the top, bottom, left, and right insets, which then are used when the panel is drawn.
- 334 Insets determine the amount of space between the edges of a panel and that panel's components.
- 334 The following statement creates an Insets object that specifies 20 pixels of insets above and below and 13 pixels to the left and right:
- Insets whitespace = new Insets(20, 13, 20, 13);
- 334 You can establish insets in any container by overriding its getInsets() method and returning an Insets object, as in this example:
public Insets getInsets() {(Action evt) {
return new Insets(10, 30, 10, 30);
}
Summary
- Top
- 334 When it comes to designing a user interface in Java, you've seen today that abstract expressionism goes only so far.
- Getting the desired user interface layout in a Swing application requires the use of layout managers.
- 334 These managers require some adjustment for people who are use to more precise control over where components appear on an interface.
- 334 You now know how to use the five layout managers and panels.
- As you work with Swing, you'll find that it can approximate any kind of interface through the use of nested containers and different layout managers.
- 334 After you master the development of a user interface in Java,
- your programs can offer an interface that works on multiple platforms without modification.
Q & A
- Top | Back to Day 12 Expanantion of Fourth Program
- Q I really dislike working with layout managers; they're either too simplistic or too complicated.
- Even with a lot of tinkering, I can never get my user interface to look like I want it to.
- All I want to do is define the sizes of my components and put them at an (x,y) position on the screen.
- Can I do this ?
- A It's possible, but problematic.
- Java was designed in such a way that a program's GUI could run equally well on different platforms
- and with different screen resolutions, fonts, screen sizes, and the like.
- Relying on pixel coordinates can cause a program that looks good on one platform to be unusable on others.
- Layout disasters such as components overlapping each other or getting cut off by the edge of a container may result.
- Layout managers, by dynamically placing elements on the screen, get around these problems.
- Although there might be some differences in the end results on different platforms, they are less likely to be catastrophic.
- If none of that is persuasive, here's how to ignor my advice:
- Set the content pane's layout manager with null as the argument.
- Create a Rectangle object (from the java.awt package) with the (x,y) position, width, and height of the component as arguments.
- Finally, call the component's setBounds(Rectangle) method with that rectangle as the argument.
- The following application displays a 300x300 pixel frame with a Click Me button at the (x,y) position 10, 10 that is 120 pixels wide by 30 pixels tall:
Listing for Q&A The Text of Absolute.java
- Top
- page 335
import java.awt.*;
import javax.swing.*;
public class Absolute extends JFrame {
public Absolute() {
super("Example");
setSize(300, 300);
setLayout(null);
JButton myButton = new JButton("Click Me");
myButton.setBounds(new Rectangle(10, 10, 120, 30));
add(myButton);
setVisible(true);
}
public static void main(String[] arguments) {
Absolute frame = new Absolute();
}
}
- 335 You can find out more about setBounds() in the Component class.
Quiz - Questions
- Top | Review today's material by taking this three-question quiz.
- Whatis the default layout manager for a panel in Java ?
- None
- BorderLayout
- FlowLayout
- Which layout manager uses a compass direction or a reference to the center when adding a component to a container ?
- BorderLayout
- MapLayout
- FlowLayout
- If you want to create an installation wizard that has multiple steps, what layout manager should you use ?
- GridLayout
- CardLayout
- BorderLayout
Answers
- Top | Note A is 1, B is 2, and C is 3
- C. To keep a panel from using flow layout, you can set its layout manager to null.
- A. Border layout has class variables NORTH, EAST, WEST, and CENTER.
- B. Card layout enables components to be stacked like cards and displayed one at a time, making it well-suited to implement a wizard.
Certification Practice
- Top
- 336 The following question is the kind of thing you could expect to be asked on a Java programming certification test.
- Answer it without looking at today's material or using the Java compiler to test the code.
- The answer is available on the book's website at www.java21days.com
- Given:
import java.awt.*;
import javax.swing.*;
public class ThreeButtons extends JFrame {
public ThreeButtons() {
super("Program");
setSize(350, 225);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
JButton alpha = new JButton("Alpha");
JButton beta = new JButton("Beta");
JButton gamma = new JButton("Gamma");
// answer goes here
add(alpha);
add(beta);
add(gamma);
pack();
setVisible(true);
}
public static void main(String[] arguments) {
ThreeButtons b3 = new ThreeButtons();
}
}
- Which statement should replace // answer goes here to make the frame display all three buttons side by side ?
- content.setLayout(null);
- content.setLayout(new FlowLayout);
- content.setLayout(new GridLayout);
- content.setLayout(new BorderLayout);
Exercise
- Top
- To extend your knowledge of the subjects covered today, try the following exercises:
- Create a user interface that displays a calendar for a single month, including headings, for the seven days of the week and a title for the month across the top.
- Create an interface that incorporates more than one layout manager.