System, but they may not be reproduced for publication



Yüklə 83 Mb.
Pdf görüntüsü
səhifə75/82
tarix19.04.2023
ölçüsü83 Mb.
#106251
1   ...   71   72   73   74   75   76   77   78   ...   82
Java A Beginner’s Guide, Eighth Edition ( PDFDrive )

listeners. With this approach, the listener simply waits until it receives an event. Once
an event arrives, the listener processes the event and then returns. The advantage of
this design is that the application logic that processes events is cleanly separated from
the user interface logic that generates the events. Therefore, a user interface element is
able to “delegate” the handling of an event to a separate piece of code. In the delegation
event model, a listener must register with a source in order to receive an event.
Let’s look at events, event sources, and listeners a bit more closely.
Events
In Java, an event is an object that describes a state change in an event source. It can be
generated as a consequence of a person interacting with an element in a graphical user
interface or generated under program control. The superclass for all events is
java.util.EventObject. Many events are declared in java.awt.event. Events
specifically related to Swing are found in javax.swing.event.
Event Sources
An event source is an object that generates an event. When a source generates an event,
it sends that event to all registered listeners. Therefore, in order for a listener to receive
an event, it must register with the source of that event. In Swing, listeners register with
a source by calling a method on the event source object. Each type of event has its own
registration method. Typically, events use the following naming convention:
public void addTypeListener(TypeListener el)
Here, Type is the name of the event and el is a reference to the event listener. For
example, the method that registers a keyboard event listener is called
addKeyListener( ). The method that registers a mouse motion listener is called
addMouseMotionListener( ). When an event occurs, the event is passed to all
registered listeners.
A source must also provide a method that allows a listener to unregister an interest in a
specific type of event. In Swing, the naming convention of such a method is this:
public void removeTypeListener(TypeListener el)


Again, Type is the name of the event and el is a reference to the event listener. For
example, to remove a keyboard listener, you would call removeKeyListener( ).
The methods that add or remove listeners are provided by the source that generates
events. For example, as you will soon see, the JButton class is a source of
ActionEvents, which are events that indicate that some action, such as a button press,
has occurred. Thus, JButton provides methods to add or remove an action listener.
Event Listeners
listener is an object that is notified when an event occurs. It has two major
requirements. First, it must have registered with one or more sources to receive a
specific type of event. Second, it must implement a method to receive and process that
event.
The methods that receive and process events applicable to Swing are defined in a set of
interfaces, such as those found in java.awt.event and javax.swing.event. For
example, the ActionListener interface defines a method that handles an
ActionEvent. Any object may receive and process this event if it provides an
implementation of the ActionListener interface.
There is an important general principle that must be stated now. An event handler
should do its job quickly and then return. In most cases, it should not engage in a long
operation because doing so will slow down the entire application. If a time­consuming
operation is required, then a separate thread should be created for this purpose.
Event Classes and Listener Interfaces
The classes that represent events are at the core of Swing’s event handling mechanism.
At the root of the event class hierarchy is EventObject, which is in java.util. It is the
superclass for all events in Java. The class AWTEvent, declared in the java.awt
package, is a subclass of EventObject. It is the superclass (either directly or indirectly)
of all AWT­based events used by the delegation event model. Although Swing uses the
AWT events, it also adds several of its own. As mentioned, these are in
javax.swing.event. Thus, Swing supports a large number of events. However, in this
chapter only three are used. They are shown here, along with their corresponding
listener.


The examples that follow illustrate the general procedures that you will use to these
handle events. However, the same basic mechanism applies to Swing event handling in
general. As you will see, the process is both streamlined and easy to use.
USE JBUTTON
One of the most commonly used Swing controls is the push button. A push button is an
instance of JButton. JButton inherits the abstract class AbstractButton, which
defines the functionality common to all buttons. Swing push buttons can contain text,
an image, or both, but this book uses only text­based buttons.
JButton supplies several constructors. The one used here is
JButton(String msg)
Here, msg specifies the string that will be displayed inside the button.
When a push button is pressed, it generates an ActionEvent. JButton provides the
following methods, which are used to add or remove an action listener:
void addActionListener(ActionListener al)
void removeActionListener(ActionListener al)
Here, al specifies an object that will receive event notifications. This object must be an
instance of a class that implements the ActionListener interface.
The ActionListener interface defines only one method: actionPerformed( ). It is
shown here:
void actionPerformed(ActionEvent ae)
This method is called when a button is pressed. In other words, it is the event handler
that is called when a button press event has occurred. Your implementation of
actionPerformed( ) must quickly respond to that event and return. As explained


earlier, as a general rule, event handlers must not engage in long operations, because
doing so will slow down the entire application.
Using the ActionEvent object passed to actionPerformed( ), you can obtain several
useful pieces of information relating to the button­press event. The one used by this
chapter is the action command string associated with the button. By default, this is the
string displayed inside the button. The action command is obtained by calling
getActionCommand( ) on the event object. It is declared like this:
String getActionCommand( )
The action command identifies the button. Thus, when using two or more buttons
within the same application, the action command gives you an easy way to determine
which button was pressed.
The following program demonstrates how to create a push button and respond to
button­press events. 
Figure 16­2
shows how the example appears on the screen.
Figure 16­2 Output from the ButtonDemo program


Let’s take a close look at the new things in this program. First, notice that the program
now imports both the java.awt and java.awt.event packages. The java.awt package
is needed because it contains the FlowLayout class, which supports the flow layout
manager. The java.awt.event package is needed because it defines the
ActionListener interface and the ActionEvent class. Beginning with JDK 9, both
packages are in the java.desktop module.
Next, the class ButtonDemo is declared. Notice that it implements ActionListener.
This means that ButtonDemo objects can be used to receive action events. Next, a
JLabel reference is declared. This reference will be used within the
actionPerformed( ) method to display which button has been pressed.
The ButtonDemo constructor begins by creating a JFrame called jfrm. It then sets


the layout manager for the content pane of jfrm to FlowLayout, as shown here:
As explained earlier, by default, the content pane uses BorderLayout as its layout
manager, but for many applications, FlowLayout is more convenient. Recall that a
flow layout lays out components one row at a time, top to bottom. When one row is full,
layout advances to the next row. Although this scheme gives you little control over the
placement of components, it is quite simple to use. However, be aware that if you resize
the frame, the position of the components will change.
After setting the size and the default close operation, ButtonDemo( ) creates two
buttons, as shown here:
The first button will contain the text "Up", and the second will contain "Down".
Next, the instance of ButtonDemo referred to via this is added as an action listener
for the buttons by these two lines:
This approach means that the object that creates the buttons will also receive
notifications when a button is pressed.
Each time a button is pressed, it generates an action event and all registered listeners
are notified by calling the actionPerformed( ) method. The ActionEvent object
representing the button event is passed as a parameter. In the case of ButtonDemo,
this event is passed to this implementation of actionPerformed( ):
The event that occurred is passed via ae. Inside the method, the action command


associated with the button that generated the event is obtained by calling
getActionCommand( ). (Recall that, by default, the action command is the same as
the text displayed by the button.) Based on the contents of that string, the text in the
label is set to show which button was pressed.
One last point: Remember that actionPerformed( ) is called on the event­
dispatching thread as explained earlier. It must return quickly in order to avoid slowing
down the application.
WORK WITH JTEXTFIELD
Another commonly used control is JTextField. It enables the user to enter a line of
text. JTextField inherits the abstract class JTextComponent, which is the
superclass of all text components. JTextField defines several constructors. The one we
will use is shown here:
JTextField(int cols)
Here, cols specifies the width of the text field in columns. It is important to understand
that you can enter a string that is longer than the number of columns. It’s just that the
physical size of the text field on the screen will be cols columns wide.
When you press enter when inputting into a text field, an ActionEvent is generated.
Therefore, JTextField provides the addActionListener( ) and
removeActionListener( ) methods. To handle action events, you must implement
the actionPerformed( ) method defined by the ActionListener interface. The
process is similar to handling action events generated by a button, as described earlier.
Like a JButton, a JTextField has an action command string associated with it. By
default, the action command is the current content of the text field. However, this
default is seldom used. Instead, you will usually set the action command to a fixed value
of your own choosing by calling the setActionCommand( ) method, shown here:
void setActionCommand(String cmd)
The string passed in cmd becomes the new action command. The text in the text field is
unaffected. Once you set the action command string, it remains the same no matter
what is entered into the text field. One reason that you might want to explicitly set the
action command is to provide a way to recognize the text field as the source of an action
event. This is especially important when another control in the same frame also


generates action events and you want to use the same event handler to process both
events. Setting the action command gives you a way to tell them apart. Also, if you don’t
set the action command associated with a text field, then by happenstance the contents
of the text field might match the action command of another component.
Ask the Expert
Q
: You explained that the action command associated with a text field
can be set by calling setActionCommand( ). Can I use this method to set
the action command associated with a push button?
A
: Yes. As explained, by default the action command associated with a push
button is the name of the button. To set the action command to a different value,
you can use the setActionCommand( ) method. It works the same for JButton
as it does for JTextField.
To obtain the string that is currently displayed in the text field, call getText( ) on the
JTextField instance. It is declared as shown here:
String getText( )
You can set the text in a JTextField by calling setText( ), shown next:
void setText(String text)
Here, text is the string that will be put into the text field.
The following program demonstrates JTextField. It contains one text field, one push
button, and two labels. One label prompts the user to enter text into the text field.
When the user presses 
ENTER
while focus is within the text field, the contents of the text
field are obtained and displayed within a second label. The push button is called
Reverse. When pressed, it reverses the contents of the text field. Sample output is
shown in 
Figure 16­3
.


Figure 16­3 Sample output from the TFDemo program


Much of the program will be familiar, but a few parts warrant special attention. First,
notice that the action command associated with the text field is set to "myTF" by the
following line:


After this line executes, the action command string will always be "myTF" no matter
what text is currently held in the text field. Therefore, the action command generated
by jtf will not accidentally conflict with the action command associated with the
Reverse push button. The actionPerformed( ) method makes use of this fact to
determine what event has occurred. If the action command string is "Reverse", it can
mean only one thing: that the Reverse push button has been pressed. Otherwise, the
action command was generated by the user pressing 
ENTER
while the text field had
input focus.
Finally, notice this line from within the actionPerformed( ) method:
As explained, when the user presses 
ENTER
while focus is inside the text field, an
ActionEvent is generated and sent to all registered action listeners, through the
actionPerformed( ) method. For TFDemo, this method simply obtains the text
currently held in the text field by calling getText( ) on jtf. It then displays the text
through the label referred to by jlabContents.
CREATE A JCHECKBOX
After the push button, perhaps the next most widely used control is the check box. In
Swing, a check box is an object of type JCheckBox. JCheckBox inherits
AbstractButton and JToggleButton. Thus, a check box is, essentially, a special type
of button.
JCheckBox defines several constructors. The one used here is
JCheckBox(String str)
It creates a check box that has the text specified by str as a label.
When a check box is selected or deselected (that is, checked or unchecked), an item
event is generated. Item events are represented by the ItemEvent class. Item events
are handled by classes that implement the ItemListener interface. This interface
specifies only one method, itemStateChanged( ), which is shown here:
void itemStateChanged(ItemEvent ie)
The item event is received in ie.


To obtain a reference to the item that changed, call getItem( ) on the ItemEvent
object. This method is shown here:
Object getItem( )
The reference returned must be cast to the component class being handled, which in
this case is JCheckBox.
You can obtain the text associated with a check box by calling getText( ). You can set
the text after a check box is created by calling setText( ). These methods work the
same as they do for JButton, described earlier.
The easiest way to determine the state of a check box is to call the isSelected( )
method. It is shown here:
boolean isSelected( )
It returns true if the check box is selected and false otherwise.
The following program demonstrates check boxes. It creates three check boxes called
Alpha, Beta, and Gamma. Each time the state of a box is changed, the current action is
displayed. Also, the list of all currently selected check boxes is displayed. Sample output
is shown in 
Figure 16­4
.
Figure 16­4 Sample output from the CBDemo program



The main point of interest in this program is the item event handler,
itemStateChanged( ). It performs two functions. First, it reports whether the check
box has been selected or cleared. Second, it displays all selected check boxes. It begins
by obtaining a reference to the check box that generated the ItemEvent, as shown
here:
The cast to JCheckBox is necessary because getItem( ) returns a reference of type
Object. Next, itemStateChanged( ) calls isSelected( ) on cb to determine the
current state of the check box. If isSelected( ) returns true, it means that the user
selected the check box. Otherwise, the check box was cleared. It then sets the
jlabChanged label to reflect what happened.


Finally, itemStateChanged( ) checks the selected state of each check box, building a
string that contains the names of those that are selected. It displays this string in the
jlabSelected label.
WORK WITH JLIST
The last component that we will examine is JList. This is Swing’s basic list class. It
supports the selection of one or more items from a list. Although often the list consists
of strings, it is possible to create a list of just about any object that can be displayed.
JList is so widely used in Java that it is highly unlikely that you have not seen one
before.
JList is a generic class that is declared as shown here:
class JList
Here, E represents the type of the items in the list.
JList provides several constructors. The one used here is
JList(E[ ] items)
This creates a JList that contains the items in the array specified by items.
Although a JList will work properly by itself, most of the time you will wrap a JList
inside a JScrollPane, which is a container that automatically provides scrolling for its
contents. Here is the constructor that we will use:
JScrollPane(Component comp)
Here, comp specifies the component to be scrolled, which in this case will be a JList.
When you wrap a JList in a JScrollPane, long lists will automatically be scrollable.
This simplifies GUI design. It also makes it easy to change the number of entries in a
list without having to change the size of the JList component.
A JList generates a ListSelectionEvent when the user makes or changes a selection.
This event is also generated when the user deselects an item. It is handled by
implementing ListSelectionListener, which is packaged in javax.swing.event.
This listener specifies only one method, called valueChanged( ), which is shown here:
void valueChanged(ListSelectionEvent le)


Here, le is a reference to the object that generated the event. Although
ListSelectionEvent does provide some methods of its own, often you will interrogate
the JList object itself to determine what has occurred. ListSelectionEvent is also
packaged in javax.swing.event.
By default, a JList allows the user to select multiple ranges of items within the list, but
you can change this behavior by calling setSelectionMode( ), which is defined by
JList. It is shown here:
void setSelectionMode(int mode)
Here, mode specifies the selection mode. It must be one of these values defined by the
ListSelectionModel interface (which is packaged in javax.swing):
SINGLE_SELECTION
SINGLE_INTERVAL_SELECTION
MULTIPLE_INTERVAL_SELECTION
The default, multiple­interval selection lets the user select multiple ranges of items
within a list. With single­interval selection, the user can select one range of items. With
single selection, the user can select only a single item. Of course, a single item can be
selected in the other two modes, too. It’s just that they also allow a range to be selected.
You can obtain the index of the first item selected, which will also be the index of the
only selected item when using single­selection mode, by calling getSelectedIndex( ),
shown here:
int getSelectedIndex( )
Indexing begins at zero. So, if the first item is selected, this method will return 0. If no
item is selected, –1 is returned.
You can obtain an array containing all selected items by calling getSelectedIndices(
), shown next:
int[ ] getSelectedIndices( )
In the returned array, the indices are ordered from smallest to largest. If a zero­length
array is returned, it means that no items are selected.


The following program demonstrates a simple JList, which holds a list of names. Each
time a name is selected in the list, a ListSelectionEvent is generated, which is
handled by the valueChanged( ) method defined by ListSelectionListener. It
responds by obtaining the index of the selected item and displaying the corresponding
name. Sample output is shown in 
Figure 16­5
.
Figure 16­5 Output from the ListDemo program


Let’s look closely at this program. First, notice the names array near the top of the
program. It is initialized to a list of strings that contain various names. Inside
ListDemo( ), a JList called jlst is constructed using the names array. As mentioned,
when the array constructor is used (as it is in this case), a JList instance is
automatically created that contains the contents of the array. Thus, the list will contain
the names in names.
Next, the selection mode is set to single selection. This means that only one item in this
list can be selected at any one time. Then, jlst is wrapped inside a JScrollPane, and
the preferred size of the scroll pane is set to 120 by 90. This makes for a compact, but
easy­to­use scroll pane. In Swing, the setPreferredSize( ) method sets the ideal size
of a component. Be aware that some layout managers are free to ignore this request,


but most often the preferred size determines the size of the component.
A list selection event occurs whenever the user selects an item or changes the item
selected. Inside the valueChanged( ) event handler, the index of the item selected is
obtained by calling getSelectedIndex( ). Because the list has been set to single­
selection mode, this is also the index of the only item selected. This index is then used
to index the names array to obtain the selected name. Notice that this index value is
tested against –1. Recall that this is the value returned if no item has been selected. This
will be the case when the selection event handler is called if the user has deselected an
item. Remember: A selection event is generated when the user selects or deselects an
item.
Try This 16­1
A Swing­Based File Comparison Utility
SwingFC.java
Although you know only a small amount about Swing, you can still put it to use to
create a practical application. In 
Try This 10­1
, you created a console­based file
comparison utility. This project creates a Swing­based version of the program. As you
will see, giving this application a Swing­based user interface substantially improves its
appearance and makes it easier to use. Here is how the Swing version looks:
Because Swing streamlines the creation of GUI­based programs, you might be
surprised by how easy it is to create this program.
1. Begin by creating a file called SwingFC.java and then enter the following comment
and import statements:


2. Next, begin the SwingFC class, as shown here:
The names of the files to compare are entered into the text fields defined by jtfFirst
and jtfSecond. To compare the files, the user presses the jbtnComp button.
Prompting messages are displayed in jlabFirst and jlabSecond. The results of the
comparison, or any error messages, are displayed in jlabResult.
3. Code the SwingFC constructor like this:


Most of the code in this constructor should be familiar to you. However, notice one
thing: an action listener is added only to the push button jbtnCompare. Action
listeners are not added to the text fields. Here’s why: the contents of the text fields are
needed only when the Compare button is pushed. At no other time are their contents
required. Thus, there is no reason to respond to any text field events. As you begin to


write more Swing programs, you will find that this is often the case when using a text
field.
4. Begin creating the actionPerformed( ) event handler, as shown next. This
method is called when the Compare button is pressed.
The method begins by confirming that the user has entered a file name into each of the
text fields. If this is not the case, the missing file name is reported and the handler
returns.
5. Now, finish actionPerformed( ) by adding the code that actually opens the files
and then compares them.


6. Finish SwingFC by adding the following main( ) method.
7. The entire Swing­based file comparison program is shown here:



USE ANONYMOUS INNER CLASSES OR LAMBDA
EXPRESSIONS TO HANDLE EVENTS
Up to this point, the programs in this chapter have used a simple, straightforward
approach to handling events in which the main class of the application has
implemented the listener interface itself and all events are sent to an instance of that
class. While this is perfectly acceptable, it is not the only way to handle events. For


example, you could use separate listener classes. Thus, different classes could handle
different events and these classes would be separate from the main class of the
application. However, two other approaches offer powerful alternatives. First, you can
implement listeners through the use of anonymous inner classes. Second, in some
cases, you can use a lambda expression to handle an event. Let’s look at each approach.
Anonymous inner classes are inner classes that don’t have a name. Instead, an instance
of the class is simply generated “on the fly” as needed. Anonymous inner classes make
implementing some types of event handlers much easier. For example, given a
JButton called jbtn, you could implement an action listener for it like this:
Here, an anonymous inner class is created that implements the ActionListener
interface. Pay special attention to the syntax. The body of the inner class begins after
the { that follows new ActionListener( ). Also notice that the call to
addActionListener( ) ends with a ) and a ; just like normal. The same basic syntax
and approach is used to create an anonymous inner class for any event handler. Of
course, for different events, you specify different event listeners and implement
different methods.
One advantage to using an anonymous inner class is that the component that invokes
the class’ methods is already known. For instance, in the preceding example, there is no
need to call getActionCommand( ) to determine what component generated the
event, because this implementation of actionPerformed( ) will only be called by
events generated by jbtn.
In the case of an event whose listener defines a functional interface, you can handle the
event by use of a lambda expression. For example, action events can be handled with a
lambda expression because ActionListener defines only one abstract method,
actionPerformed( ). Using a lambda expression to implement ActionListener
provides a compact alternative to explicitly declaring an anonymous inner class. For
example, again assuming a JButton called jbtn, you could implement the action
listener like this:


As was the case with the anonymous inner class approach, the object that generates the
event is known. In this case, the lambda expression applies only to the jbtn button.
Of course, in cases in which an event can be handled by use of a single expression, it is
not necessary to use a block lambda. For example, here is an action event handler for
the Up button in the ButtonDemo program shown earlier. It requires only an
expression lambda.
Notice how much shorter this code is compared with the original approach. It is also
shorter than it would be if you explicitly used an anonymous inner class.
In general, you can use a lambda expression to handle an event when its listener
defines a functional interface. For example, ItemListener is also a functional
interface. Of course, whether you use the traditional approach, an anonymous inner
class, or a lambda expression will be determined by the precise nature of your
application. To gain experience with each, try converting the event handlers in the
foregoing examples to lambda expressions or anonymous inner classes.

Yüklə 83 Mb.

Dostları ilə paylaş:
1   ...   71   72   73   74   75   76   77   78   ...   82




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə