Tutorial 6 Topics Event handling in Swing o Swing events o Event listeners o Register an event handler to an object o Implement the event-handling SwingApplication o GUI o Event handling o Multiple events o Adapter Java 2D and drawing editor o Basic shapes o Stroke and fill Tutorial problems Design problems Event handling in Swing Event handling is of fundamental importance to programs with a graphic user interface. It can be intimidating for beginning programmers. However, event handling is MUCH simpler than you thought. Here is a summary of the three key components of an event handling process: Event (click a button, press a key, etc.) Listener interface(ActionListener, WindowListner, etc.) Object (button, frame, textfield, etc.) who is “listening to” the event Swing Event Every time the user types a character or clicks a button, the Java virtual machine (JVM) generates an event. Here are a few examples of Swing events: Act that results in the event User clicks a button or presses Return while typing in a text field User closes a frame (main window) User presses a mouse button User moves the mouse over a component Component becomes visible Component gets the keyboard focus Table or list selection changes Listener type ActionListener WindowListener MouseListener MouseMotionListener ComponentListener FocusListener ListSelectionListener Event Listener Each event can trigger one or more listeners of that event. As we talked about last week, an event listener is a Java interface, which contains a collection of method declarations. The classes that implement the interface must define those methods. Here is a list of events, listeners, and methods: Event Listener Interface Listener methods WindowEvent WindowListener windowActivated(WindowEvent e) windowDeactivated(WindowEvent e) windowClosed(WindowEvent e) windowClosing(WindowEvent e) windowOpened(WindowEvent e) windowDeiconified(WindowEvent e) windowIconified(WindowEvent e) ActionEvent ItemEvent TextEvent FocusEvent ActionListener ItemListener TextListener FocusListener KeyEvent KeyListenmer actionPerformed(ActionEvent e) itemStateChanged(ItemEvent e) textValueChanged(TextEvent e) focusGained(FocusEvent e) focusLost(FocusEvent e) keyPressed(KeyEvent e) keyReleased(KeyEvent e) keyTyped(KeyEvent e) For example, when the user clicks a button, the ActionListener will be notified, which then triggers the actionPerformed method to be executed. Register an event handler for the object To listen to an event, an object must register to be that event’s listener. The following code creates a JButton and registers an ActionListener for it. JButton button = new JButton("I'm a Swing button!"); button.addActionListener(this); 3 Steps to Implement an Event Handler To implement an event handler, you must take the following three steps: 1. Implement a listener interface: public class MyClass implements ActionListener 2. Add the listener to an object: button.addActionListener(this) 3. Define the methods of the listener interface: public void actionPerformed(ActionEvent e){ ...//code that reacts to the action.. } Next we will demonstrate how it works using the SwingApplication example. SwingApplication The SwingApplication is an example we pulled from the Java Tutorial. It is a “buttonclick” counter - every time user clicks the button, the label is updated Last week, we talked about the graphic components of this application. In this section, we will study how it interfaces with the user. In other words, when user clicks a button, what will the application do? GUI Just to refresh our memory, here is the GUI section of the code: import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SwingApplication extends JFrame{ int numClicks = 0; JPanel pane = new JPanel(); JLabel label = new JLabel(“Number of button clicks: “ + numClicks); JButton button = new JButton("I'm a Swing button!"); //Constructor SwingApplicatin (){ super (“SwingApplication”); //set the frame title pane.setLayout(new GridLayout(0, 1)); pane.add(button); pane.add(label); this.getContentPane().add(pane, BorderLayout.CENTER); } public static void main(String[] args){ SwingApplication app = new SwingApplication(); app.pack(); app.setVisible(true); } } Event Handling Let's follow the steps we outlined in last section Event: Object: Interface: ActionEvent button ActionListener with the method actionPerformed Here is the code: 1. Implement a listener interface: public class SwingApplication extends JFrame implements ActionListener 2. Add the listener to the button (after it is created) button.addActionListener(this); 3. Define the methods of the listener interface: Public void actionPerformed (ActionEvent e) { numClicks ++; label.setText (“Number of button clicks: “ + numClicks); } Multiple Objects Listening What if there are multiple objects listening to the same event? How does Java determine which actionPerformed method to execute? For example, we have two buttons, b1 and b2. Both of them are registered as an ActionListener. If user clicks b1, a message “b1 is clicked” is printed on the label. If user clicks b2, the message “b2 is clicked” is printed. Therefore, we need to implement the actionPerformed method as follows: JButton b1 = new JButton (“B1”); b1.addActionListener (this); JButton b2 = new JButton (“B2”); b2.addActionListener (this); ………………………. Public void actionPerformed (ActionEvent e) { if (e.getSource() == b1) //which object is the event source? label.setText (“b1 is printed”); if (e.getSource() == b2) label.setText (“b2 is printed”); } Adapter Classes Now, lets go back to our SwingApplication. We need to implement another event – we want the application to exit when the user closes the window. Again, we will follow the steps: Event: Object: Interface: WindowEvent frame WindowListener with the method windowClosing …. Wait a minute; there are 7 methods in the WindowListener interface. As we mentioned earlier that the class implementing the interfaces should define ALL of the methods in that interface. This rule is fine for interfaces like ActionListener that has only one method. But WindowListener has 7, I mean 7, methods. Do I have to implement all of them, even though I only need one? The answer is yes and no. If you implement WindowListener, YES you have to implement ALL 7 methods. I know, typing code for six methods that don’t do anything is the kind of tedious busywork that nobody likes. To simplify this task, Java developed an adapter class for each listener interface that has more than one method. An adapter class implements all the methods in the interface but does nothing with them. Here is how to use an adapter. frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.exit(0); } } ); Here, we defined an anonymous inner class of type WindowAdapter as the parameter of addWindowListener (). You can learn more about inner classes from the textbook (p.281). Here, you only need to know how to use it. Java 2D and Drawing Editor The Java 2D API provides enhanced two-dimensional graphics, text, and imaging capabilities for Java programs. It supports line art, text, and images in a flexible, fullfeatured framework for developing richer user interfaces, sophisticated drawing programs and image editors. This section will build upon the lecture example with some additional features. Basic Shapes g2.draw(new Line2D.Double(x, y+rectHeight, x+rectWidth, y)); g2.draw(new Rectangle2D.Double(x, y, rectWidth, rectHeight)); g2.draw(new Ellipse2D.Double(x, y, rectWidth, rectHeight)); g2.draw(new RoundRectangle2D.Double(x, y, rectWidth, rectHeight, 10, 10)); g2.draw(new Arc2D.Double(x, y, rectWidth, rectHeight, 90, 135, Arc2D.OPEN)); Stroking and Filling Graphics We can easily apply fancy line styles and fill patterns to the graphics by changing the stroke and paint attributes of the Graphics2D context. Stroke enables you to specify different widths and dashing patterns for lines and curves. For example, the following example created a thick-line arc (see the above table): BasicStroke wideStroke = new BasicStroke(8.0f); g2.setStroke(wideStroke); g2.draw(new Arc2D.Double(x, y, rectWidth, rectHeight, 90, 135, Arc2D.OPEN)); Fill patterns are defined by the Paint interface. The Java 2D A PI provides three Paint implementations: Color, TexturePaint and GradientPaint. TexturePaint defines a fill pattern using a simple image fragment that is repeated uniformly. GradientPaint defines a fill pattern as a gradient between two colors. Here are two examples, one using Color and the other using GradientPaint g2.setPaint(Color.red); g2.fill(new Arc2D.Double(x, y, rectWidth, rectHeight, 90, 135, Arc2D.OPEN)); GradientPaint redtowhite = new GradientPaint(x,y,red,x+rectWidth, y,white); g2.setPaint(redtowhite); g2.fill (new Ellipse2D.Double(x, y, rectWidth, rectHeight)); Tutorial Problems Exercise 1: Answer the following questions Question 1: What is an event object? a) b) c) d) An event object represents one specific event, such as a mouse click. An event object is an object that listens for mouse clicks. An event object is a list of all the events that have happened in the system. An event object is what your program does in response to an event. Question 2: If there are several buttons in a frame, will each one generate its own events when the user clicks on it? a) b) c) d) Yes---each event is unique and is generated by a specific button. No---events are indistinguishable from each other. Yes---each button is allowed to generate one event. After that it is silent. No---only event listeners are unique. Question 3: Can a single listener object respond to several types of events from the same component? a) Yes---there is always only one listener in the entire program, so it has to respond to all types of events. b) No---there must be a specific listener object for each type of event from each component in a GUI. c) Yes---as long as it has an appropriate method for each type. d) No---a program can only respond to one type of event Exercise 2: The LabelCopy class has 2 labels, sourceLabel and targetLabel, and 1 button. Here is the code for creating the GUI. import javax.swing.*; public class LabelCopy extends JPanel{ JLabel sourceLabel, targetLabel; JButton copyButton; public LabelCopy(){ sourceLabel = new JLabel("Source Label"); targetLabel = new JLabel("Target label"); button = new JButton("Copy"); add(sourceLabel); add(button); add(targetLabel); } public static void main (String[] args){ JFrame frame = new JFrame (“Exercise 2”); LabelCopy pane = new LabelCopy(); frame.getContentPane().add(pane, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); } } Now, modify the LabelCopy class definition so that when user clicks the button, the text in the sourceLabel is copied to the targetLabel Design Problem Develop a simple integer calculator. It has two text fields, a label that displays the result, and 4 radio buttons (+, -, *, /). Here is how it works: § § § Input numbers in the text fields, e.g. 10 .. 10 Choose the operation by selecting one of the radio buttons, e.g. + The label will display the result based on the selected operation, e.g. 20 Note, what you get from the textfield is a string. You need to convert it to an int. Here is the code int firstInput = Integer.parseInt(string1);