Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
31
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 4

e.rejectDrop();

}

}catch (Exception ex) {} setBorder(BorderFactory.createLineBorder(Color.blue, 2));

}

public void dragEnter(DropTargetDragEvent e) { setBorder(BorderFactory.createLineBorder(Color.red, 3));

}

public void dragExit(DropTargetEvent e) { setBorder(BorderFactory.createLineBorder(Color.blue, 2));

}

public void dragOver(DropTargetDragEvent e){}

public void dropActionChanged(DropTargetDragEvent e) { }

public void setHandler(FoodCourt h) { handler = h;

}

public void setBorderColor(Color col) { setBorder(BorderFactory.createLineBorder(col, 2));

}

Click-handling routines are implemented through the FoodCourt interface with the assistance of the mouse event listeners. The Food class handleClick() method is invoked when a user clicks on the hamburger, hotdog, and pizza food items:

public void addClickHandler(FoodCourt h) { clickHandler = h;

}

public void mouseClicked(MouseEvent e) { if (clickHandler != null) {

clickHandler.handleClick();

}

}

public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {}

}

The CondimentPanel class generates a decorator object for the cheese item and associates a coin value with that object so that it can be passed along to the food item it is decorated with. A hamburger costs $1.35 alone, but will add to, or decorate, that cost by 35 cents if cheese is appended to it. The panel layout consists of a combination GridLayout manager called pictures, with the cheese image and label, added to a BoxLayout manager that combines this panel with a label component for presentation in the GUI display above the three different food items:

[CondimentPanel.java]

// package name and import statements omitted

156

Developing Effective User Interfaces with JFC

public class CondimentPanel extends JPanel {

private static Logger logger = Logger.getLogger(“CondimentPanel”);

JPanel pictures = null;

GridLayout pictureLayout = null;

Hashtable condimentPrices = new Hashtable();

public CondimentPanel(String title) { super(); setBackground(Color.white);

pictures = new JPanel(); pictureLayout = new GridLayout(1, 1); pictures.setLayout(pictureLayout);

pictures.setAlignmentX(CENTER_ALIGNMENT); pictures.setBorder(BorderFactory.createLineBorder(Color.red));

pictures.add(new FoodDecoratorGraphic(“Cheese”, “resources/Cheese.gif”, 0.35f));

condimentPrices.put(“Cheese”, new Float(0.35f));

JLabel label = new JLabel(title, SwingConstants.CENTER); label.setPreferredSize(new Dimension(200, 25)); label.setMinimumSize(new Dimension(200, 25)); label.setMaximumSize(new Dimension(200, 25)); label.setAlignmentX(CENTER_ALIGNMENT);

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

add(label);

add(pictures);

}

}

The Food class implements the FoodCourt interface so that the application can polymorphically discover the methods needed for processing during run time. The FoodItems class invokes this method three times for the three different food items displayed in the application (hamburger, hotdog, pizza):

[Food.java]

// package name and import statements omitted public class Food implements FoodCourt {

private static Logger logger = Logger.getLogger(“Food”); private FoodItems item = null;

private FoodGraphic graphic = null; private String name = null;

private float cost = 0.0f;

public Food(FoodItems fooditem, String name, String imageFile, float cost) { super();

item = fooditem; name = name; cost = cost;

157

Chapter 4

graphic = new FoodGraphic(this, imageFile, 100, 35); graphic.addClickHandler(this);

}

public String getName() { return name; }

public FoodGraphic getGraphic() { return graphic; }

public float getCost() { return cost; }

The addBehavior(String b) method takes the food item object reference and invokes the addMemberBehavior(String name, String b) method to aggregate the behavior of your only condiment item, cheese, with the food item it is being added to. If the food item alone is clicked by the user, the handle event method named handleClick() will add the food item description to the test area display using the static class DisplayPanel:

public void addBehavior(String b) { item.addMemberBehavior(name, b); }

public String getDescription() { return name; }

public void setGraphicHandler(FoodCourt h) { graphic.setHandler(h); }

public void handleClick() {

DisplayPanel.write(getDescription() + “ “); DisplayPanel.write(“selected. That’ll cost you “ + getCost()); DisplayPanel.writeLine(“”);

}

}

The final class that will be discussed for the BoxLayoutPanel application is the FoodItems class. FoodItems implements its layout in a similar fashion to the CondimentPanel class. A GridLayout manager is crafted to accommodate the food item images, which is then added to a BoxLayout manager for the final presentation. The static helper component named Box.createVerticalGlue lets the application adjust when the parent container is resized by the user so that the box layout maintains its spacing:

[FoodItems.java]

// package name and import statements omitted public class FoodItems extends JPanel {

private static Logger logger = Logger.getLogger(“FoodItems”);

// declarations omitted for the sake of brevity [Please check download code] public FoodItems(BoxLayoutPanel p, Hashtable condimentPrices) {

super();

this.name = “Condiments”; this.panel = p;

this.condimentPrices = condimentPrices;

158

Developing Effective User Interfaces with JFC

members = new HashMap();

setBackground(new Color(204,204,102));

pictures = new JPanel(); pictureLayout = new GridLayout(3, 2); pictureLayout.setHgap(5); pictureLayout.setVgap(5); pictures.setLayout(pictureLayout);

pictures.setAlignmentX(CENTER_ALIGNMENT);

imagePanel = new JPanel(); imagePanel.setBackground(Color.white);

imagePanel.setLayout(new BoxLayout(imagePanel, BoxLayout.X_AXIS));

JLabel label = new JLabel(“”, SwingConstants.CENTER); label.setAlignmentX(CENTER_ALIGNMENT); label.setPreferredSize(new Dimension(200,20)); label.setMinimumSize(new Dimension(200,20)); label.setMaximumSize(new Dimension(200,20));

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

Component padding = Box.createRigidArea(new Dimension(100, 1));

This code segment illustrates how the Food objects are instantiated and manipulated by the addMember(FoodCourt fc) method that adds a new food item to the members collection class structure for future reference and to the pictures panel for visual rendering:

food = new Food(this, “Hamburger”, “resources/Hamburger1.gif”, 1.35f); addMember(food);

food = new Food(this, “Hotdog”, “resources/Hotdog1.gif”, 1.15f); addMember(food);

food = new Food(this, “Pizza”, “resources/Pizza1.gif”, 1.05f); addMember(food);

add(label);

add(padding);

add(pictures);

add(Box.createVerticalGlue());

}

public void addMember(FoodCourt fc) {

if (!members.containsKey(fc.getName())) { members.put(fc.getName(), fc); pictures.add(fc.getGraphic());

}

}

The addMemberBehavior(String n, String b) method outputs the food item description and cost to the static DisplayPanel text area component. The condimentPrices collection class is used to derive the cost of the cheese condiment, the only condiment in the BoxLayoutPanel application, so that its cost can be added to the cost of the food item:

159

Chapter 4

public void addMemberBehavior(String n, String b) {

Float condimentCost = (Float)condimentPrices.get(b.trim());

FoodCourt m = (FoodCourt) members.get(n); DisplayPanel.writeLine(“Adding “ +

b +

(“ + condimentCost + “) to “ +

m.getDescription() +

which costs $” + m.getCost() +

for a total cost of $” +

(m.getCost() + condimentCost.floatValue()));

}

// getName(), getGraphic() and getDescription() methods omitted for better clarity

public String getDescription(String n) { FoodCourt m = (FoodCourt) members.get(n); if (m != null) {

return m.getDescription();

}else { return “”;

}

}

public void setGraphicHandler(FoodCourt h) { graphic.setHandler(h);

}

}

The BoxLayoutPanel display is demonstrated in Figure 4-4. Users can drag and drop the cheese condiment on the three different food items to determine the total cost of the two products combined. Additionally, users can click on the individual food items to determine the cost of that single item. All events that are generated by mouse clicks or drag and drop operations are tracked by listener classes and logged to the text area display to track the users’ navigation activities. The Decorator pattern implementation in the BoxLayoutPanel application allows behaviors to be dynamically aggregated during run time.

160

Developing Effective User Interfaces with JFC

Figure 4-4

FlowLayout

The FlowLayout manager arranges components from left to right in the Container space; if the space on a line is exhausted, then the components that are part of this manager will flow to the next line. By default, all components of the FlowLayout manager are centered in a horizontal fashion on each line. Three different constructors can be invoked to instantiate a FlowLayout manager object. The first constructor requires no parameters while the second constructor requires an integer alignment value that indicates how components will be justified during construction. The last constructor method uses an integer alignment value like the aforementioned method, but also requires two integer values that specify horizontal and vertical gap values for pixel spacing.

The constructor methods for the FlowLayout manager are shown in the method summary table that follows.

Method

Description

 

 

public FlowLayout()

No parameters

public FlowLayout(int align)

Align parameter may be one of three class con-

 

stants: LEFT, RIGHT, or CENTER to indicate how

 

components will be justified

public FlowLayout

Where align indicates how the components will

(int align, int hGap, int vGap)

be justified and the hGap and vGap parameters

 

specify the horizontal and vertical pixels between

 

components

 

 

161

Chapter 4

The following FlowLayout example accepts a dollar value from the user and calculates the coin distribution using the Chain of Responsibility pattern. Figure 4-5 provides a high-level view of the FlowLayoutPanel application and how the Swing components are positioned on the FlowLayout panel.

FlowLayout

JButton

JTextField

JButton

Command pattern: execute()

Chain of Responsibility Pattern: Determines

coin distribution of user input

JLabel

If user expands panel to the right, the JLabel component will be positioned to the right of the Currency panel

Figure 4-5

Request processing in the FlowLayputPanel application is handled with the Chain of Responsibility pattern that accepts the dollar amount from the user and cascades downward from the four different coin handlers (QuarterHandler, DimeHandler, NickelHandler, PennyHandler) until all the coins have been accounted for in the dollar amount specified by the user.

Pattern

Benefits

Consequences

 

 

 

Chain of Responsibility

Reduces coupling by

Requests can go unhandled

 

allowing several objects

with improper chain

 

the opportunity to handle

configuration

 

a request

 

 

Distributes responsibilities

 

 

among objects

 

 

 

 

The FlowLayoutPanel class below illustrates how the FlowLayout manager can be implemented. This sample application implements the JFormattedTextField class to dictate how the data must be input by the user and the NumberFormat class to establish what that format will be. Two buttons are created as extensions to the JButton class, one for kicking off the Chain of Responsibility pattern named “Determine Coins” and the other for clearing the text in the coin display panel:

[FlowLayoutPanel.java]

// package name and import statements omitted

public class FlowLayoutPanel extends JPanel implements ActionListener, PropertyChangeListener {

162

Developing Effective User Interfaces with JFC

private JFormattedTextField amountField; private NumberFormat amountDisplayFormat; private NumberFormat amountEditFormat;

// some GUI component initializations/declarations omitted for the sake of brevity private JButtonCoins coinButton = new JButtonCoins(“Determine Coins”);

private JButtonClear clearButton = new JButtonClear(“Clear”);

private QuarterHandler quarterHandler; private DimeHandler dimeHandler; private NickelHandler nickelHandler; private PennyHandler pennyHandler;

public FlowLayoutPanel() { setSize(700, 150);

//Coin Button coinButton.setActionCommand(“Coins”); coinButton.addActionListener(this);

//Clear button clearButton.setActionCommand(“clear”);

clearButton.addActionListener(this);

The FlowLayoutPanel constructor establishes the currency display format using the NumberFormat class, which is the abstract base class for all number formats. The setMinimumFractionDigits(int newValue) method sets the minimum number of digits permitted in the fraction portion of a number.

Once the format styles have been created, they can then be applied to the JFormattedTextField class used for rendering the dollar amount specified by the user. The PropertyChangeListener interface forces the application to deploy the propertyChange method (PropertyChangeEvent evt) to handle events when the dollar amount has been modified. The BorderLayout manager is applied to the topPanel component that organizes the coinButton, amountField, and clearButton components, which is added to the FlowLayout manager of the overall application by default:

amountDisplayFormat = NumberFormat.getCurrencyInstance(); amountDisplayFormat.setMinimumFractionDigits(0); amountEditFormat = NumberFormat.getNumberInstance();

amountField = new JFormattedTextField(new DefaultFormatterFactory (new NumberFormatter(amountDisplayFormat),

new NumberFormatter(amountDisplayFormat), new NumberFormatter(amountEditFormat)));

amountField.setValue(new Double(amount));

amountField.setColumns(10); amountField.addPropertyChangeListener(“value”, this);

topPanel.add(coinButton);

topPanel.add(amountField);

topPanel.add(clearButton);

messageText = new JLabel(“Coin Amounts”); results.add(messageText); results.setPreferredSize(new Dimension(400, 100));

163

Chapter 4

results.setBorder(BorderFactory.createLineBorder (Color.blue, 2)); results.setBackground(DIGIT_COLOR);

JPanel borderPanel = new JPanel(new BorderLayout()); borderPanel.setBorder(new TitledBorder(“Formatted Currency”));

borderPanel.add(topPanel, BorderLayout.CENTER); borderPanel.setSize(200,200);

add(borderPanel);

add(results);

The following code section implements the coin handlers that implement the Chain of Responsibility pattern to process all of the coins that are derived from the amount specified by the user in the GUI panel. The setSuccessor(TestHandler successor) method is used to specify the successor object along the chain of objects:

// setup chain of responsibility pattern implementation try {

quarterHandler = new QuarterHandler(); dimeHandler = new DimeHandler(); nickelHandler = new NickelHandler(); pennyHandler = new PennyHandler();

quarterHandler.setSuccessor( dimeHandler ); dimeHandler.setSuccessor( nickelHandler ); nickelHandler.setSuccessor( pennyHandler );

}catch( Exception e ) { e.printStackTrace();

}

}

public void propertyChange(PropertyChangeEvent e) { Object source = e.getSource();

amount = ((Number)amountField.getValue()).doubleValue();

}

public void actionPerformed(ActionEvent e) { Command obj = (Command)e.getSource(); obj.execute();

}

The JButtonCoins method implements the Command interface to invoke the execute() method of the class when the user clicks on the Determine Coins button. The dollar amount is read from the amountField component and passes that value to the quarterHandler object for coin processing. When all of the coins have been accounted for, the coin distribution will be displayed in the messageText component:

class JButtonCoins extends JButton implements Command {

public JButtonCoins(String caption) { super(caption); }

public void execute() {

amountField.setValue(new Double(amount));

164

Developing Effective User Interfaces with JFC

int coinAmount = (int)(amount * 100); quarterHandler.handleRequest(coinAmount); messageText.setText(“ QUARTERS= “ + quarterHandler.getCount() +

DIMES= “ + dimeHandler.getCount() +

NICKELS= “ + nickelHandler.getCount() +

PENNIES= “ + pennyHandler.getCount());

}

}

class JButtonClear extends JButton implements Command {

public JButtonClear(String caption) { super(caption); }

public void execute() {

amountField.setValue(new Double(0)); messageText.setText(“User cleared text: “);

}

}

public interface Command { public void execute();

}

// main method omitted for the sake of brevity

}

The TestHandler class is inherited by the individual coin handlers so that get/set successor methods can be used to determine the successor objects that are implemented along the chain of coin handlers:

[TestHandler.java]

// package name and import statements omitted public class TestHandler {

private TestHandler successor;

public void setSuccessor( TestHandler successor ) { this.successor = successor; } public TestHandler getSuccessor() { return successor; }

public void handleRequest(int coinAmount) { successor.handleRequest(coinAmount);

}

}

The QuarterHandler class inherits the successor classes from its superclass TestHandler and takes the coin amount to determine how many quarters can be found in the dollar total. The modulus % operator divides the coin amount by 25 to determine the number of quarters in the sum, and takes the remainder and passes it along the chain of coin handlers for dimes, nickels, and pennies. For all of the handlers, if a remainder of zero is discovered, then the chain processing is halted:

165

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]