Tải bản đầy đủ (.pdf) (77 trang)

Professional Java JDK 6 Edition 2007 phần 4 ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.23 MB, 77 trang )

}
public interface Command {
public void execute();
}
The TestStrategy interface is implemented by the StartsWithAEIOU and AlphabeticChars classes
so the
CardLayoutPanel application can apply different string algorithms to the user-specified text.
Regular expression constructs are used to determine the patterns of the strings passed into the test
method:
public interface TestStrategy {
public boolean test(String s);
}
public class StartsWithAEIOU implements TestStrategy {
public boolean test(String s) {
if( s == null || s.length() == 0) return false;
return (s.toUpperCase().charAt(0) == ‘A’ ||
s.toUpperCase().charAt(0) == ‘E’ ||
s.toUpperCase().charAt(0) == ‘I’ ||
s.toUpperCase().charAt(0) == ‘O’ ||
s.toUpperCase().charAt(0) == ‘U’
);
}
}
public class convertUppercase implements TestStrategy {
public boolean test(String s) {
if( s == null || s.length() == 0 ) return false;
Pattern pattern = Pattern.compile(“[a-zA-Z]”);
Matcher match = pattern.matcher(s);
if (!match.find()) {
return false;
} else {


return (true);
}
}
}
// main routine omitted for brevity
}
Figure 4-14 represents the CardLayoutPanel application modeled in the previous source code. Users
can enter text in the card layout shown in the top panel and click either strategy pattern button to apply
the appropriate Strategy algorithm to that text. Results of those actions will be rendered in the card lay-
out below. All of the button components employ the
Command pattern to allow the application to deter-
mine at runtime the proper
execute() method to invoke based on the user’s navigations.
207
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 207
Figure 4-14
GroupLayout
The GroupLayout manager is a component of the NetBeans framework that is being considered for inclu-
sion in the SE 6 Java framework. The
GroupLayout manager is important in that it allows for horizontal
and vertical layout positioning in an independent, flexible manner.With this manager, layout groups can
be formed in both a sequential and parallel fashion. Sequentially, they are placed one after another, and in
parallel, they are placed on top of one another and are aligned with a common reference axis.
A sample pizza delivery placement component design is shown in Figure 4-15. This model incorporates
GroupLayout manager classes to position components on the user view. With this application, a user
specifies his or her name, the toppings desired, and the size of the pizza for delivery. When the user
makes the proper selections and clicks the order button, a receipt is generated with the user preferences.
All of the Swing components are instantiated and initialized at the onset of the
GroupLayoutPanel class

so they can be easily referenced by the
GroupLayoutPanel method for display rendering. All of the
user-selected data will be managed with a
JTree object:
package com.grouplayout;
import java.util.logging.Logger;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import org.jdesktop.layout.*;
public class GroupLayoutPanel extends JPanel implements ActionListener {
208
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 208
private JRadioButton largePizzaButton = new JRadioButton(“Large”);
private JRadioButton mediumPizzaButton = new JRadioButton(“Medium”);
private JRadioButton smallPizzaButton = new JRadioButton(“Small”);
private JLabel label = new JLabel(“Name:”);;
private JTextField textField = new JTextField();
private JCheckBox anchoviesCheckBox = new JCheckBox(“Anchovies”);
private JCheckBox mushroomsCheckBox = new JCheckBox(“Mushrooms”);
private JCheckBox onionsCheckBox = new JCheckBox(“Onions”);
private JCheckBox greenpeppersCheckBox = new JCheckBox(“Green Peppers”);
private JCheckBox sardinesCheckBox = new JCheckBox(“Sardines”);
private JCheckBox pepperoniCheckBox = new JCheckBox(“Pepperoni”);
private JButtonOrder orderButton = new JButtonOrder(“Order”);
private JButtonAllToppings allToppingsButton = new JButtonAllToppings(“All
Toppings”);
private JPanel results = new JPanel();

private JScrollPane scrollPane;
private JTree tree;
private DefaultMutableTreeNode root;
Figure 4-15
JTextField
GroupLayout
JTree
JCheckBox
JButton
(order)
JButton
(toppings)
JCheckBox JRadioButton
JCheckBox JCheckBox JRadioButton
Command pattern: execute()
JCheckBox JCheckBox JRadioButton
209
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 209
Results selected by the user will be reflected in a scroll pane to indicate all of the different dimensions
and toppings the user has chosen for the pizza delivery:
public GroupLayoutPanel() {
anchoviesCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
mushroomsCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
onionsCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
greenpeppersCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0,
0));
sardinesCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
pepperoniCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
results.setLayout(new GridLayout(0,1));

results.setPreferredSize(new Dimension(75, 75));
results.setBorder(BorderFactory.createLineBorder (Color.blue, 2));
results.setBackground(new Color(255, 255, 100));
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setSize(75, 75);
scrollPane.setPreferredSize(new Dimension(75, 75));
scrollPane.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder(“Pizza Order”),
BorderFactory.createEmptyBorder(5,5,5,5)),
scrollPane.getBorder()));
root = new DefaultMutableTreeNode(“Pizza Order”);
tree = new JTree(root);
scrollPane.getViewport().add( tree );
results.add(scrollPane);
Here is where the GroupLayout manager is instantiated and constructed to place the different Swing
components for display rendering. Notice that horizontal groups are established and embedded on one
another to get the grouping effect desired for presentation:
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
layout.setAutocreateGaps(true);
layout.setAutocreateContainerGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.add(label)
.add(layout.createParallelGroup(GroupLayout.LEADING)
.add(textField)
.add(layout.createSequentialGroup()

.add(layout.createParallelGroup(GroupLayout.LEADING)
.add(anchoviesCheckBox)
.add(onionsCheckBox)
.add(pepperoniCheckBox))
.add(layout.createParallelGroup(GroupLayout.LEADING)
210
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 210
.add(mushroomsCheckBox)
.add(greenpeppersCheckBox)
.add(sardinesCheckBox))
.add(layout.createParallelGroup(GroupLayout.LEADING)
.add(largePizzaButton)
.add(mediumPizzaButton)
.add(smallPizzaButton))) //)
.add(results))
.add(layout.createParallelGroup(GroupLayout.LEADING)
.add(orderButton)
.add(allToppingsButton))
);
Vertical groups are established with the setVerticalGroup method so they can be aligned properly
with previous horizontal group designations:
layout.linkSize(new Component[] { orderButton, allToppingsButton },
GroupLayout.HORIZONTAL);
layout.setVerticalGroup(layout.createSequentialGroup()
.add(layout.createParallelGroup(GroupLayout.BASELINE)
.add(label)
.add(textField)
.add(orderButton))
.add(layout.createParallelGroup(GroupLayout.LEADING)

.add(layout.createSequentialGroup()
.add(layout.createParallelGroup(GroupLayout.BASELINE)
.add(anchoviesCheckBox)
.add(mushroomsCheckBox)
.add(largePizzaButton))
.add(layout.createParallelGroup(GroupLayout.BASELINE)
.add(onionsCheckBox)
.add(greenpeppersCheckBox)
.add(mediumPizzaButton))
.add(layout.createParallelGroup(GroupLayout.BASELINE)
.add(pepperoniCheckBox)
.add(sardinesCheckBox)
.add(smallPizzaButton)))
.add(allToppingsButton))
.add(layout.createParallelGroup(GroupLayout.BASELINE)
.add(results))
);
Now that all of the layout positions have been defined, the listeners associated with the individual com-
ponents can be defined to track user event selections:
orderButton.addActionListener(this);
allToppingsButton.addActionListener(this);
largePizzaButton.addActionListener(this);
largePizzaButton.setActionCommand(“large pizza”);
mediumPizzaButton.addActionListener(this);
mediumPizzaButton.setActionCommand(“medium pizza”);
smallPizzaButton.addActionListener(this);
211
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 211
smallPizzaButton.setActionCommand(“small pizza”);

setBorder(BorderFactory.createLineBorder (Color.blue, 2));
}
class JButtonOrder extends JButton implements Command {
public JButtonOrder(String caption) {
super(caption);
}
Polymorphic behavior is performed with the execute() method defined in the Command pattern interface
to finalize the user selections. With the
Command pattern, additional execute() method implementations
could be defined later to add behaviors needed to perform operations for your application because opera-
tions are decoupled from objects that invariably know which operations need to be executed when invoked:
public void execute() {
String s = “Name: (empty)”;
tree = new JTree(root);
DefaultMutableTreeNode items;
if (!textField.getText().equals(“”))
s = textField.getText();
items = new DefaultMutableTreeNode(s);
root.add(items);
s = “Size: None selected”;
if (largePizzaButton.isSelected())
s = “Size: Large pizza”;
else if (mediumPizzaButton.isSelected())
s = “Size: Medium pizza”;
else if (smallPizzaButton.isSelected())
s = “Size: Small pizza”;
items.add(new DefaultMutableTreeNode(s));
if (anchoviesCheckBox.isSelected()) items.add(new
DefaultMutableTreeNode(“anchovies”));
if (mushroomsCheckBox.isSelected()) items.add(new

DefaultMutableTreeNode(“mushrooms”));
if (onionsCheckBox.isSelected()) items.add(new
DefaultMutableTreeNode(“onions”));
if (greenpeppersCheckBox.isSelected()) items.add(new
DefaultMutableTreeNode(“peppers”));
if (sardinesCheckBox.isSelected()) items.add(new
DefaultMutableTreeNode(“sardines”));
if (pepperoniCheckBox.isSelected()) items.add(new
DefaultMutableTreeNode(“pepperoni”));
scrollPane.getViewport().add( tree );
tree.expandRow(0);
results.add(scrollPane);
}
}
212
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 212
In the following code, the Command pattern is revealed in all its glory to dictate behavior associated with
the All Toppings button. When the user clicks that button in the user display, the program knows that it
must invoke the
execute() method here to enable all of the checkbox components without explicitly
stating so. During run time, the application retrieves the proper object reference so the
execute()
method associated with that reference will be called:
class JButtonAllToppings extends JButton implements Command {
public JButtonAllToppings(String caption) {
super(caption);
}
public void execute() {
anchoviesCheckBox.setSelected(true);

mushroomsCheckBox.setSelected(true);
onionsCheckBox.setSelected(true);
greenpeppersCheckBox.setSelected(true);
sardinesCheckBox.setSelected(true);
pepperoniCheckBox.setSelected(true);
}
}
public interface Command {
public void execute();
}
Action events are monitored in the code that follows, in the actionPerformed method, to determine
pizza dimension selections from the size radio buttons or to execute the
Command pattern interface refer-
ence based on the user selection:
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals(“large pizza”)) {
logger.info(“Large pizza. Mama mia.”);
mediumPizzaButton.setSelected(false);
smallPizzaButton.setSelected(false);
} else if (e.getActionCommand().equals(“medium pizza”)) {
logger.info(“Want a drink with that? Big or Large?”);
largePizzaButton.setSelected(false);
smallPizzaButton.setSelected(false);
} else if (e.getActionCommand().equals(“small pizza”)) {
logger.info(“Take your pizza and go you cheapa-skate!”);
largePizzaButton.setSelected(false);
mediumPizzaButton.setSelected(false);
} else {
Command obj = (Command)e.getSource();
obj.execute();

}
}
public static void main(String args[]) {
JFrame frame = new JFrame(“GroupLayoutPanel”);
frame.addWindowListener(new WindowAdapter() {
213
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 213
public void windowClosing(WindowEvent e) {System.exit(0);}
});
frame.getContentPane().add(new GroupLayoutPanel(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
Figure 4-16 represents a sample visualization of the pizza delivery placement application. In it, the user
has placed selections for desirable toppings and size needs. Both the Order and All Toppings buttons
implement the
Command pattern interface so specific behaviors can be invoked when selected to call
proper
execute() method implementations.
With the
GroupLayout manager, arrangements occur both sequentially and in parallel to form hierarchi-
cal presentations. Components arranged in parallel are stacked on top of one another along a common
axis, whereas sequentially arranged components are placed after one another. Each dimension is defined
independently and can operate without consideration to the other dimensions. The only deficiency asso-
ciated with
GroupLayout usage is that each component needs to be defined twice in the layout during
implementation.
Figure 4-16

Mustang Release Desktop Enhancements
This chapter addresses a few of the new Java 6 SE Mustang features, namely system attribute collection,
splash screen inclusion, and AWT modifications that are part of new modality modes. Improved drag-
and-drop support and JTable sorting were shown in earlier sections of this chapter.
214
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 214
The following table outlines the four new AWT modality models introduced with the Java Mustang
release.
Modal Type Description
Mode-less Does not block any other window while it’s rendered on the
user display.
Document-modal Blocks all windows from the same document with the excep-
tion of those windows from its child hierarchy.
Application-modal Blocks all windows from the same application with the
exception of those windows from its child hierarchy.
Toolkit-modal Blocks all windows from the same toolkit with the exception
of those toolkits from its child hierarchy.
The following example demonstrates the
mode-less type of dialog creation, which means that the dia-
log box does not block any other window rendered on the user display. The intent of this new modality
inclusion is to scope dialog box displays so they cannot block operations from one another during pro-
gram operations.
The new Tray feature provides a shortcut capability that allows users to quickly invoke their applica-
tions for deployment from the desktop tray. Figure 4-17 is deployed when the desktop icon is clicked.
Along with the system tray integration, this application demonstrates the inclusion of several new capa-
bilities included in the Mustang release, specifically a splash screen pop-up, new Modal APIs, the ability
to obtain file system attributes, perform authentication operations upon invocation, and to append Java
components to a tabbed display.
Figure 4-17

This code segment is kicked off when the user clicks the icon in the desktop tray. New Modal capabilities
are demonstrated with the Frame and Dialog components. The new
Dialog class allows developers to
limit a dialog’s blocking capability when rendered. This feature circumvents previous versions of Java
that blocked input to other top-level windows that were part of an application and were not created
with the dialog box as its parent. Now dialog boxes can have a null parent that limits the scope of a dia-
log box’s modality:
package tray;
import java.awt.*;
import java.awt.datatransfer.*;
import java.io.*;
import java.sql.*;
215
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 215
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
public class TrayDemo
{
private static Frame frame;
private Font labelFont = new Font(“Arial”, 18, Font.PLAIN);
private Dialog dialog = new Dialog(frame, “Modeless Dialog”);
private Dialog dialog2 = new Dialog(frame, “Document-modal Dialog”,
Dialog.ModalityType.DOCUMENT_MODAL);
private JPanel tab, tab2;
private JLabel[] label = { new JLabel(“Question 1”), new JLabel(“Question 2”),
new JLabel(“Question3”) };

private JTabbedPane tabbedPane;
private Dialog dialogConsole = new Dialog(frame, “Modeless Dialog”);
private static Vector<String> v = new Vector<String>();
private JTextField urlTextfield = new JTextField(30);
private JTextField emailTextfield = new JTextField(30);
private JButton btnBrowser = new JButton();
private JButton btnEmail = new JButton();
private String username = “”, password =””;
Once the TrayDemo constructor attempts to invoke the splash screen pop-up by executing the get
SpashScreen()
method from the SplashScreen class, a check is performed to ensure that the system
tray can be placed on the system desktop. Passage through this check will allow the application to
retrieve an icon and place it in the system tray so users can invoke the application with the new desktop
icon. A
MouseListener class is initialized and instantiated so the application can be popped up when a
mouse click event on the desktop icon is detected:
public TrayDemo() {
final TrayIcon trayIcon;
final SplashScreen splash = SplashScreen.getSplashScreen();
if (splash == null) {
System.out.println(“SplashScreen.getSplashScreen() returned null”);
}
if (SystemTray.isSupported()) {
SystemTray tray = SystemTray.getSystemTray();
Image image = Toolkit.getDefaultToolkit().getImage(“tray.gif”);
MouseListener mouseListener = new MouseListener() {
public void mouseClicked(MouseEvent e) {
System.out.println(“Tray Icon - Mouse clicked!”);
frame = new Frame(“SDK 6 - Modal implementation”);
JTextComponent textComp = createTextComponent();

textComp.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder(“Text”),
BorderFactory.createEmptyBorder(5,5,5,5)),
216
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 216
textComp.getBorder()));
textComp.setEditable(false);
frame.add(textComp, BorderLayout.CENTER);
frame.addWindowListener(closeWindow);
frame.setSize(700, 500);
frame.setMenuBar(createMenuBar());
frame.setVisible(true);
}
public void mouseEntered(MouseEvent e) {
System.out.println(“Tray Icon - Mouse entered!”);
}
public void mouseExited(MouseEvent e) {
System.out.println(“Tray Icon - Mouse exited!”);
}
public void mousePressed(MouseEvent e) {
System.out.println(“Tray Icon - Mouse pressed!”);
}
public void mouseReleased(MouseEvent e) {
System.out.println(“Tray Icon - Mouse released!”);
}
};
ActionListener exitListener = new ActionListener() {

public void actionPerformed(ActionEvent e) {
System.out.println(“Exiting ”);
System.exit(0);
}
};
The PopupMenu class is instantiated so it can be passed to the trayIcon object that is attached to the
ActionListener object that tracks events from the application. Additionally, the trayIcon object is
attached to the
mouseListener object so events can be tracked from the desktop view:
PopupMenu popup = new PopupMenu();
MenuItem defaultItem = new MenuItem(“Exit”);
defaultItem.addActionListener(exitListener);
popup.add(defaultItem);
trayIcon = new TrayIcon(image, “Tray Demo”, popup);
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
trayIcon.displayMessage(“Action Event”,
“An Action Event Has Been Peformed!”,
TrayIcon.MessageType.INFO);
}
};
trayIcon.setImageAutoSize(true);
trayIcon.addActionListener(actionListener);
trayIcon.addMouseListener(mouseListener);
try {
tray.add(trayIcon);
} catch (AWTException e) {
217
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 217

System.err.println(“TrayIcon could not be added.”);
}
} else {
System.err.println(“System tray is currently not supported.”);
}
}
protected JTextComponent createTextComponent() {
JTextArea ta = new JTextArea();
ta.setLineWrap(true);
return ta;
}
private static WindowListener closeWindow = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
}
};
All of the menu bar options are constructed in the createMenuBar method for presentation to the user.
First, the menu items must be instantiated and initialized so that listener objects can be attached to them.
These listeners track system events triggered by the user to enable operations for execution:
protected MenuBar createMenuBar() {
MenuBar menubar = new MenuBar();
Menu menu = new Menu(“Tools”);
menubar.add(menu);
MenuItem displayAttributes = new MenuItem(“Display File System
Attributes”);
MenuItem consoleTest = new MenuItem(“Console test”);
MenuItem tabTest = new MenuItem(“JTabbedPane test”);
displayAttributes.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.setBounds(132, 132, 300, 200);

dialog.addWindowListener(closeWindow);
dialog.setLayout(new BorderLayout());
java.util.List<String> diskspace = new ArrayList<String>();
DefaultListModel listModel = new DefaultListModel();
JList list = null;
File[] roots = File.listRoots();
for (int i=0; i < roots.length; i++) {
diskspace.add((“root>” + roots[i] + “ Free space: “ +
roots[i].getFreeSpace() + “ bytes”));
diskspace.add((“root>” + roots[i] + “ Usable space: “ +
roots[i].getUsableSpace() + “bytes”));
}
for (String s : diskspace) {
listModel.addElement(s);
}
list = new JList(listModel);
JScrollPane listScrollPane = new JScrollPane(list);
dialog.add(listScrollPane, BorderLayout.CENTER);
218
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 218
dialog.setVisible(true);
}
});
menu.add(displayAttributes);
consoleTest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialogConsole.setBounds(132, 132, 300, 200);
dialogConsole.addWindowListener(closeWindow);
dialogConsole.setLayout(new BorderLayout());

login();
//dialogConsole.add( , BorderLayout.CENTER);
dialogConsole.setVisible(true);
}
});
menu.add(displayAttributes);
menu.add(consoleTest);
Figure 4-18 demonstrates a new Mustang enhancement to allows GUI developers to append Java com-
ponents to a tab display. Previously, users were only allowed to implement icons and text items to a tab.
The following sample display allows users to answer Yes or No for questions on the first two tabbed
panes from drop-down menus and to select answers from checkboxes on the last tabbed component.
Figure 4-18
Implementation of the tab menu item is demonstrated in the following code snippet. The
tabTest com-
ponent establishes the tabbed pane panel along with the questions and the drop-down menus and
checkboxes with the possible answers to those questions:
tabTest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JPanel testPanel = new JPanel(new BorderLayout());
testPanel.setBounds(0, 0, 700, 300);
dialog2.setBounds(100, 100, 700, 300);
dialog2.addWindowListener(closeWindow);
dialog2.setLayout(new BorderLayout());
tabbedPane = new JTabbedPane();
String[] questions = { “Did you like this race?”,
219
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 219
“Have you run a triathlon before?”,
“Do you like puppies and/or long walks on

the beach?” };
String[] answers = { “Yes”, “No”, “Undecided” };
// Create a combobox
JComboBox combo = new JComboBox();
combo.setBounds( 20, 35, 100, 20 );
for( int iCtr = 0; iCtr < answers.length; iCtr++ )
combo.addItem( answers[iCtr] );
JComboBox combo2 = new JComboBox();
combo2.setBounds( 20, 35, 100, 20 );
for( int iCtr = 0; iCtr < answers.length; iCtr++ )
combo2.addItem( answers[iCtr] );
JComboBox combo3 = new JComboBox();
combo3.setBounds( 20, 35, 160, 20 );
for( int iCtr = 0; iCtr < answers.length; iCtr++ )
combo3.addItem( answers[iCtr] );
JPanel tab1 = new JPanel();
tab1.add(label[0], BorderLayout.WEST);
tab1.add(combo, BorderLayout.EAST);
tabbedPane.addTab(“Tab1”, null, makeTextPanel(questions[0]),
“Tab1”);
New capabilities of the setTabComponent method are manifested in the following code segment, where
drop-down menus are used for both the tab1 and tab2 panels, and the tab2 panel implements the
longwalksButton checkbox along with the puppiesButton so users can select either or both of the
answers in response to the panel question:
tabbedPane.setTabComponentAt(0, tab1);
JPanel tab2 = new JPanel();
tab2.add(label[1], BorderLayout.WEST);
tab2.add(combo2, BorderLayout.EAST);
tabbedPane.addTab(“Tab2”, null, makeTextPanel(questions[1]),
“Tab2”);

tabbedPane.setTabComponentAt(1, tab2);
JPanel tab3 = new JPanel();
tab3.add(label[2], BorderLayout.WEST);
tab3.add(combo3, BorderLayout.EAST);
JCheckBox puppiesButton = new JCheckBox(“Puppies”);
puppiesButton.setSelected(false);
JCheckBox longwalksButton = new JCheckBox(“Long walks”);
longwalksButton.setSelected(false);
JPanel checkPanel = new JPanel();
checkPanel.add(puppiesButton, BorderLayout.WEST);
checkPanel.add(longwalksButton, BorderLayout.EAST);
220
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 220
tabbedPane.addTab(“Tab3”, null, makeTextPanel(questions[2]),
“Tab3”);
tabbedPane.setTabComponentAt(2, checkPanel);
testPanel.add(tabbedPane, BorderLayout.NORTH);
dialog2.add(testPanel, BorderLayout.CENTER);
dialog2.setVisible(true);
}
});
menu.add(tabTest);
Here, new drag-and-drop functionality is implemented so users can add text to a JTextField compo-
nent and drag that text to a
JScrollPane drop area. Four different drop modes are listed in commented
text to outline what capabilities are available to users for drag-and-drop implementations, but the
TrayDemo application uses the DropMode.INSERT to enable text conveyance:
dndTest.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e) {
System.out.println(“DnD test ”);
JPanel testPanel = new JPanel(new BorderLayout());
testPanel.setBounds(0, 0, 700, 300);
dialog2 = new Dialog(frame, “Document-modal Dialog”,
Dialog.ModalityType.DOCUMENT_MODAL);
dialog2.setBounds(0, 0, 700, 300);
dialog2.addWindowListener(closeWindow);
dialog2.setLayout(new BorderLayout());
dialog2.setSize(700, 300);
final JList listDND = new JList();
listDND.setModel(new DefaultListModel());
// Drop modes:
// 1. DropMode.USE_SELECTION
// 2. DropMode.ON
// 3. DropMode.INSERT
// 4. DropMode.ON_OR_INSERT
listDND.setDropMode(DropMode.INSERT);
With the Java Mustang release, a new TransferHandler.TransferInfo inner class can be imple-
mented to capture the details of every transfer during drag-and-drop activities. The
canImport method
determines whether or not drag-and-drop operations can occur with a component. Data import opera-
tions are enabled with the
importData method:
listDND.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport
support)
{
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)
|| !support.isDrop())

221
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 221
return false;
JList.DropLocation dropLocation =
(JList.DropLocation)support.getDropLocation();
return dropLocation.getDropPoint() != null;
}
public boolean importData(TransferHandler.TransferSupport
support) {
if (!canImport(support))
return false;
JList.DropLocation dropLocation =
(JList.DropLocation)support.getDropLocation();
Transferable transferable = support.getTransferable();
String transferData;
try {
transferData =
(String)transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
e.printStackTrace();
return false;
}
When a user marks code in the textfield area, and drags it to the pane drop area, this code adds that text to
a vector collection and uses the
setListData method for data inclusion in the visualization component:
v.addElement(transferData);
listDND.setListData(v);
return true;
}

});
JLabel dragLabel = new JLabel(“Drag me:”);
JScrollPane pane = new JScrollPane(listDND);
final JTextField textfield = new JTextField();
textfield.setDragEnabled(true);
testPanel.add(dragLabel, BorderLayout.WEST);
testPanel.add(textfield, BorderLayout.CENTER);
testPanel.add(pane, BorderLayout.SOUTH);
dialog2.add(testPanel, BorderLayout.NORTH);
dialog2.setVisible(true);
}
});
menu.add(dndTest);
In this section of the source code, new Desktop API classes and methods are implemented to read
textfield data that is transferred to desktop classes for browser and email application invocation. The
isDesktopSupported method ensures that the Desktop API is available so the application can retrieve
an instance for method execution:
222
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 222
deskTest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(“deskTest selected ”);
dialog2 = new Dialog(frame, “Document-modal Dialog”,
Dialog.ModalityType.DOCUMENT_MODAL);
dialog2.setBounds(0, 0, 600, 100);
dialog2.addWindowListener(closeWindow);
dialog2.setLayout(new GridLayout(0,1));
JPanel desktopPanel = new JPanel(new GridLayout(0,3));
A button is enabled here to launch the user’s browser with the url text specified by the user in the

browser textfield:
btnBrowser.setText(“Browser”);
btnBrowser.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
URI uri = null;
try {
uri = new URI(urlTextfield.getText());
desktop.browse(uri);
} catch(Exception e) {
e.printStackTrace();
}
}
else
System.out.println(“Desktop not supported”);
}
});
An email button launches the host’s default email client with the text specified in the email textfield:
btnEmail.setText(“Email”);
btnEmail.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
String mailTo = emailTextfield.getText();
URI uri = null;
try {
if (mailTo.length() > 0) {
uri = new URI(“mailto”, mailTo, null);
desktop.mail(uri);

}
} catch(Exception e) {
e.printStackTrace();
}
}
else
223
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 223
System.out.println(“Desktop not supported”);
}
});
JLabel urlLabel = new JLabel(“URL:”);
JLabel emailLabel = new JLabel(“Email:”);
desktopPanel.add(urlLabel);
desktopPanel.add(urlTextfield);
desktopPanel.add(btnLaunchBrowser);
desktopPanel.add(emailLabel);
desktopPanel.add(emailTextfield);
desktopPanel.add(btnLaunchEmail);
dialog2.add(desktopPanel);
dialog2.setVisible(true);
}
});
menu.add(deskTest);
return menubar;
}
The login() method demonstrates new security capabilities introduced with the Mustang release so
developers can affiliate username/password schemes with Swing applications. If the user enters an
inappropriate username/password combination, a modal display will not be rendered to the user invok-

ing that component:
public void login() {
Console console = System.console ();
if (console == null) {
System.err.println (“console procurement unsuccessful.”);
return;
}
// Obtain username.
username = console.readLine (“Enter username: “);
// Obtain password.
password = new String (console.readPassword (“Enter password: “));
try {
System.out.println(“username, password= “ + username + “, “ +
password);
}
catch (Exception e) {
System.out.println(“Exception detected: “ + e.toString());
}
}
public static void main(String[] args) {
TrayDemo main = new TrayDemo();
}
}
224
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 224
Managing Navigation Flows in Swing
Applications
Installation wizards are common Swing applications to consign software applications and their libraries
to their file systems during their development or deployment tasks. Wizards typically perform initializa-

tion activities, gather user directory designations, and perform post-installation tasks for clean-up
actions by leading users through a series of requests to ensure that applications and their libraries are
configured properly for operations. This last segment of the chapter demonstrates how an
InstallationWizard application can be developed using the State Pattern, a GoF behavioral pattern, to
delegate behaviors across objects during user navigations at runtime. Each state, or step, of the wizard is
encapsulated as an object, which is affiliated to a subclass of an abstract class for proper state manage-
ment. This same application could have easily been developed with the
CardLayout manager using its
first(), last(), previous(), and next() methods, but the intent was to show how you could man-
age those flows in a different fashion.
The following table outlines some of benefits and drawbacks of implementing both patterns in your
applications.
Pattern Benefits Consequences
Singleton Direct control over how many Inability to subclass an application
instances can be created. that implements it, which prevents
extendability.
Ensures that a class has only one
instance and enforces controlled
access to the sole instance.
State Allows an object to modify its Preponderance of classes to support
behavior when its state changes the different states of an
internally. application.
Localizes all behavior of a particular
state in a single object.
Polymorphically defines behaviors
and states of an object.
The individual panel display components represent state-specific behaviors that are derived from the
abstract
State class. The application maintains a pointer to the current state position in the installation
process and reacts to changes by the user as navigation is performed in a forward and backward direc-

tion using the Previous and Next buttons on the GUI display (see Figure 4-19).
225
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 225
Figure 4-19
The InstallationWizard application implements two
JPanel components, componentPanel and
buttonPanel, to display the individual Swing visualizations for user input and the buttons used for
previous/next operations, respectively:
// [InstallationWizard.java]
// package name and import statements omitted
public class InstallationWizard implements ActionListener {
private static Logger logger = Logger.getLogger(“InstallationWizard”);
private static Frame frame;
private JPreviousButton previousButton = new JPreviousButton(“<< Previous”);
private JNextButton nextButton = new JNextButton(“Next >>”);
private JFinishButton finishButton = new JFinishButton(“Finish”);
private JPanel componentPanel;
private JPanel buttonPanel;
private Context context = new Context();
private static WindowListener closeWindow = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
}
};
InstallationWizard() {
frame = new Frame(“Installation Wizard”);
frame.setBounds(32, 32, 300, 200);
frame.addWindowListener(closeWindow);
frame.setSize(700,300);

frame.setLayout(new BorderLayout());
The application establishes a context reference that the application uses to determine proper panel visu-
alization flows. The
FlowLayout manager is used with the buttonPanel to position the buttons used
for directing the wizard flow. The context reference invokes the
getColor() method to set the back-
ground color of the panel component (the default color is Yellow) with the
setBackground(Color bg)
method. Additionally, the previousButton and finishButton components are disabled by the
setEnabled(Boolean b) method:
226
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 226
context = new Context();
componentPanel = new JPanel();
previousButton.addActionListener(this);
nextButton.addActionListener(this);
finishButton.addActionListener(this);
buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.add(previousButton);
buttonPanel.add(nextButton);
buttonPanel.add(finishButton);
getContentPane().add(componentPanel, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
// default is yellow
componentPanel.setBackground(context.getColor());
previousButton.setEnabled(false);
finishButton.setEnabled(false);
componentPanel.add(context.getPanel(), BorderLayout.CENTER);

componentPanel.setBackground(context.getColor());
componentPanel.validate();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
Command obj = (Command)e.getSource();
obj.execute();
}
public interface Command {
public void execute();
}
The JPreviousButton component manages all user requests when the user clicks the Previous button.
The
execute() method uses the application’s context reference to invoke the previous() and
getState() methods to set the application to its previous state. The removeAll() method of the
Container class is then used to remove all of the components from the container so the appropriate
panel display will be positioned in the user visualization:
class JPreviousButton extends JButton implements Command {
public JPreviousButton(String caption) { super(caption); }
public void execute() {
context.previous();
context.getState();
componentPanel.removeAll();
componentPanel.add(context.getPanel(), BorderLayout.CENTER);
componentPanel.setBackground(context.getColor());
componentPanel.validate();
nextButton.setEnabled(true);
227
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 227

finishButton.setEnabled(false);
if (context.getColor() == Color.yellow) {
previousButton.setEnabled(false);
} else {
previousButton.setEnabled(true);
}
}
}
The JNextButton component implements the same methods as the JPreviousButton component to
render the appropriate user display when the installation invokes the Next button on the GUI presenta-
tion. When the user invokes the Next button, all of the components on the panel display will be removed
using the
removeAll() method. Once the remove operation has been executed, the next color panel will
be discovered by using the reference state of the application using the context reference:
class JNextButton extends JButton implements Command {
public JNextButton(String caption) { super(caption); }
public void execute() {
context.next();
context.getState();
componentPanel.removeAll();
componentPanel.add(context.getPanel(), BorderLayout.CENTER);
componentPanel.setBackground(context.getColor());
componentPanel.validate();
previousButton.setEnabled(true);
if (context.getColor() == Color.blue) {
nextButton.setEnabled(false);
finishButton.setEnabled(true);
} else {
nextButton.setEnabled(true);
finishButton.setEnabled(false);

}
}
}
The FinishButton class is enabled when the user has reached the final panel display in the series of
four panel components:
class JFinishButton extends JButton implements Command {
public JFinishButton(String caption) { super(caption); }
public void execute() {
System.exit(1);
}
}
public static void main(String s[]) {
InstallationWizard st = new InstallationWizard();
}
}
228
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 228
The abstract State class is a generalized class used by the Context class to establish a blueprint needed
to describe the methods needed to handle the state flows in the wizard across the different panel dis-
plays. Two get methods,
getColor() and getPanel(), are used to retrieve color and panel values of
the individual
JPanel components implemented for display:
[State.java]
public abstract class State {
public abstract void handlePrevious(Context c);
public abstract void handleNext(Context c);
public abstract Color getColor();
public abstract JPanel getPanel();

}
The Context class sets the initial state to yellow, so the YellowState application will start the installa-
tion program and create objects for the four color applications: Blue, Green, Orange, and Yellow:
// [Context.java]
// package name and import statements omitted
public class Context {
private State state = null;
public BlueState blueState;
public GreenState greenState;
public OrangeState orangeState;
public YellowState yellowState;
public Context(State state) { this.state = state; }
public Context() {
// get instances for all panels
blueState = new BlueState();
greenState = new GreenState();
orangeState = new OrangeState();
yellowState = new YellowState();
state = getYellowInstance();
}
public State getState() { return state; }
public void setState(State state) { this.state = state; }
public void previous() { state.handlePrevious(this); }
public void next() { state.handleNext(this); }
public Color getColor() {
return state.getColor();
}
public JPanel getPanel() {
return state.getPanel();
}

The following methods are used to return references to the object instances of the four different panel
displays:
public BlueState getBlueInstance() {
return blueState.getInstance();
229
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 229
}
public GreenState getGreenInstance() {
return greenState.getInstance();
}
public OrangeState getOrangeInstance() {
return orangeState.getInstance();
}
public YellowState getYellowInstance() {
return yellowState.getInstance();
}
}
The YellowState class is the first panel display invoked by the Installation Wizard to start the install
process. The
YellowState constructor method initializes all of the different textfield components that
are used for data collection. The
getInstance() method creates a new YellowState instance for refer-
ence by other objects if the reference has not been created. If a reference value has already been estab-
lished, the reference will be returned to the object that references it:
// [YellowState.java]
// package name and import statements omitted
public class YellowState extends State {
// component declarations and initialization omitted for better clarity
static private YellowState _instance = null;

public YellowState() {
firstName = “”;
lastName = “”;
city = “”;
state = “”;
zipcode = “”;
generatePanel();
}
static public YellowState getInstance() {
if(null == instance) {
instance = new YellowState();
}
return instance;
}
The handlePrevious(Context c) and handleNext(Context c) methods invoke the setValues()
method to persist the values entered into the form display by the user. Once the data has been saved off
the local instance variables, the context reference is implemented to obtain the reference to the next panel
display. The
get<color>Instance() method acquires the Singleton instance generated in the individ-
ual panel components:
230
Part II: A Broad Understanding of Java APIs, Tools, and Techniques
09_777106 ch04.qxp 11/28/06 10:43 PM Page 230
public void handlePrevious(Context c) {
setValues();
c.setState(c.getBlueInstance());
}
public void handleNext(Context c) {
setValues();
c.setState(c.getOrangeInstance());

}
public Color getColor() { return (Color.yellow); }
public JPanel getPanel() {
return panelYellow;
}
public void generatePanel() {
log.info(“[YellowState:generatePanel]”);
panelYellow = new JPanel(new GridLayout(0,1));
panelYellow.setSize(200,200);
formPanel.add(fnameLabel);
formPanel.add(fnameTextfield);
formPanel.add(lnameLabel);
formPanel.add(lnameTextfield);
formPanel.add(cityLabel);
formPanel.add(cityTextfield);
formPanel.add(stateLabel);
formPanel.add(stateTextfield);
formPanel.add(zipcodeLabel);
formPanel.add(zipcodeTextfield);
Border etchedBdr = BorderFactory.createEtchedBorder();
Border titledBdr = BorderFactory.createTitledBorder(etchedBdr, “Registration
Form”);
Border emptyBdr = BorderFactory.createEmptyBorder(15,15,15,15);
Border compoundBdr=BorderFactory.createCompoundBorder(titledBdr, emptyBdr);
formPanel.setBorder(compoundBdr);
getValues();
panelYellow.add(formPanel);
}
The getValues() method sets the text in the various textfield components using the setText methods
that are part of the

JTextField class. The setValues() method retrieves the text from the textfield
components and saves them to the various instance variables associated with the panel display:
public void getValues() {
fnameTextfield.setText(firstName);
lnameTextfield.setText(lastName);
cityTextfield.setText(city);
stateTextfield.setText(state);
231
Chapter 4: Developing Effective User Interfaces with JFC
09_777106 ch04.qxp 11/28/06 10:43 PM Page 231

×