1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
---
title: Handling Events with Listeners
order: 4
layout: page
---
[[application.events]]
= Handling Events with Listeners
Let us put into practice what we learned of event handling in
<<dummy/../../../framework/architecture/architecture-events#architecture.events,"Events
and Listeners">>. You can implement listener interfaces in a regular class, but
it brings the problem with differentiating between different event sources.
Using anonymous class for listeners is recommended in most cases.
[[application.events.anonymous]]
== Using Anonymous Classes
By far the easiest and the most common way to handle events in Java 6 and 7 is
to use anonymous local classes. It encapsulates the handling of events to where
the component is defined and does not require cumbering the managing class with
interface implementations. The following example defines an anonymous class that
inherits the [classname]#Button.ClickListener# interface.
[source, java]
----
// Have a component that fires click events
final Button button = new Button("Click Me!");
// Handle the events with an anonymous class
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
button.setCaption("You made me click!");
}
});
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.anonymous[on-line example, window="_blank"].
Local objects referenced from within an anonymous class, such as the
[classname]#Button# object in the above example, must be declared
[literal]#++final++#.
Most components allow passing a listener to the constructor, thereby losing a
line or two. However, notice that if accessing the component that is constructed
from an anonymous class, you must use a reference that is declared before the
constructor is executed, for example as a member variable in the outer class. If
it is declared in the same expression where the constructor is called, it
doesn't yet exist. In such cases, you need to get a reference to the component
from the event object.
[source, java]
----
final Button button = new Button("Click It!",
new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
event.getButton().setCaption("Done!");
}
});
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.constructor[on-line example, window="_blank"].
[[application.events.java8]]
== Handling Events in Java 8
Java 8 introduced lambda expressions, which offer a replacement for listeners.
You can directly use lambda expressions in place of listeners that have only one
method to implement.
For example, in the following, we use a lambda expression to handle button click
events in the constructor:
[source, java]
----
layout.addComponent(new Button("Click Me!",
event -> event.getButton().setCaption("You made click!")));
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.java8[on-line example, window="_blank"].
Java 8 is the future that is already here, and as Vaadin API uses event
listeners extensively, using lambda expressions makes UI code much more
readable.
Directing events to handler methods is easy with method references:
[source, java]
----
public class Java8Buttons extends CustomComponent {
public Java8Buttons() {
setCompositionRoot(new HorizontalLayout(
new Button("OK", this::ok),
new Button("Cancel", this::cancel)));
}
public void ok(ClickEvent event) {
event.getButton().setCaption ("OK!");
}
public void cancel(ClickEvent event) {
event.getButton().setCaption ("Not OK!");
}
}
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.java8differentiation[on-line example, window="_blank"].
[[application.events.classlistener]]
== Implementing a Listener in a Regular Class
The following example follows a typical pattern where you have a
[classname]#Button# component and a listener that handles user interaction
(clicks) communicated to the application as events. Here we define a class that
listens to click events.
[source, java]
----
public class MyComposite extends CustomComponent
implements Button.ClickListener {
Button button; // Defined here for access
public MyComposite() {
Layout layout = new HorizontalLayout();
// Just a single component in this composition
button = new Button("Do not push this");
button.addClickListener(this);
layout.addComponent(button);
setCompositionRoot(layout);
}
// The listener method implementation
public void buttonClick(ClickEvent event) {
button.setCaption("Do not push this again");
}
}
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.classlistener[on-line example, window="_blank"].
[[application.events.differentiation]]
== Differentiating Between Event Sources
If an application receives events of the same type from multiple sources, such
as multiple buttons, it has to be able to distinguish between the sources. If
using a regular class listener, distinguishing between the components can be
done by comparing the source of the event with each of the components. The
method for identifying the source depends on the event type.
[source, java]
----
public class TheButtons extends CustomComponent
implements Button.ClickListener {
Button onebutton;
Button toobutton;
public TheButtons() {
onebutton = new Button("Button One", this);
toobutton = new Button("A Button Too", this);
// Put them in some layout
Layout root = new HorizontalLayout();
root.addComponent(onebutton);
root.addComponent(toobutton);
setCompositionRoot(root);
}
@Override
public void buttonClick(ClickEvent event) {
// Differentiate targets by event source
if (event.getButton() == onebutton)
onebutton.setCaption ("Pushed one");
else if (event.getButton() == toobutton)
toobutton.setCaption ("Pushed too");
}
}
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.differentiation[on-line example, window="_blank"].
Other techniques exist for separating between event sources, such as using
object properties, names, or captions to separate between them. Using captions
or any other visible text is generally discouraged, as it may create problems
for internationalization. Using other symbolic strings can also be dangerous,
because the syntax of such strings is checked only at runtime.
|