Create a custom event in Java
You probably want to look into the observer pattern.
Here's some sample code to get yourself started:
import java.util.*;
// An interface to be implemented by everyone interested in "Hello" events
interface HelloListener {
void someoneSaidHello();
}
// Someone who says "Hello"
class Initiater {
private List<HelloListener> listeners = new ArrayList<HelloListener>();
public void addListener(HelloListener toAdd) {
listeners.add(toAdd);
}
public void sayHello() {
System.out.println("Hello!!");
// Notify everybody that may be interested.
for (HelloListener hl : listeners)
hl.someoneSaidHello();
}
}
// Someone interested in "Hello" events
class Responder implements HelloListener {
@Override
public void someoneSaidHello() {
System.out.println("Hello there...");
}
}
class Test {
public static void main(String[] args) {
Initiater initiater = new Initiater();
Responder responder = new Responder();
initiater.addListener(responder);
initiater.sayHello(); // Prints "Hello!!!" and "Hello there..."
}
}
Related article: Java: Creating a custom event
Java - Create a Custom event and listener
So I made a minimal example maybe that will help you:
You need an interface for your listener:
public interface MyEventListener
{
public void onMyEvent();
}
Then for your String you need some wrapper class that also handles your events
public class EventString
{
private String myString;
private List<MyEventListener> eventListeners;
public EventString(String myString)
{
this.myString = myString;
this.eventListeners = new ArrayList<MyEventListener>();
}
public void addMyEventListener(MyEventListener evtListener)
{
this.eventListeners.add(evtListener);
}
public void setValue(String val)
{
myString = val;
if (val.equals("hello world"))
{
eventListeners.forEach((el) -> el.onMyEvent());
}
}
}
You see that the myString
field is private and only accessible using the setValue
method. This is so we can see when our event condition triggers.
And then you only need some implementation of this, such as:
EventString temp = new EventString("test");
temp.addMyEventListener(() -> {
System.out.println("hello world detected");
});
temp.setValue("hello world");
How to create custom events in Java
I don't have an equivalent for the 'JsonObject' type, but other than that I think the following may work for you, using your own custom EventHandler functional interface, custom EventArgs class, and generic 'Event' helper class:
import java.util.*;
public class HighlightsObjectHandler
{
// Constants
private static final String JsonKeysHighlightsHolder = "Items",
JsonKeysHighlightUrl = "Url",
JsonKeysHighlightTranslationsHolder = "Traducoes",
JsonKeysHighlightTranslationLanguage = "Idioma",
JsonKeysHighlightTranslationText = "Titulo",
JsonKeysHighlightTranslationImage = "Imagem";
// Handlers
public Event<CustomEventHandler> HighlightsJsonChanged = new Event<CustomEventHandler>();
public Event<CustomEventHandler> HighlightsContentChanging = new Event<CustomEventHandler>();
public Event<CustomEventHandler> HighlightsContentChanged = new Event<CustomEventHandler>();
// Variables
private String _json;
// Properties
public final String getHighlightsJson()
{
return _json;
}
public final void setHighlightsJson(String value)
{
if (!_json.equals(value) && value != null)
{
_json = value;
OnHighlightsJsonChanged(CustomEventArgs.Empty);
ParseJson();
}
}
private boolean HighlightsUpdating;
public final boolean getHighlightsUpdating()
{
return HighlightsUpdating;
}
private void setHighlightsUpdating(boolean value)
{
HighlightsUpdating = value;
}
private ArrayList<HighlightObject> Highlights;
public final ArrayList<HighlightObject> getHighlights()
{
return Highlights;
}
private void setHighlights(ArrayList<HighlightObject> value)
{
Highlights = value;
}
// Methods
private void ParseJson()
{
//todo: no equivalent to 'JsonObject':
JsonObject jsonObject = null;
//todo: no equivalent to 'out' parameter:
if (JsonObject.TryParse(HighlightsJson, jsonObject))
{
OnHighlightsContentChanging(CustomEventArgs.Empty);
// Json parsing and other stuff...
// ... it shouldn't matter for this question.
OnHighlightsContentChanged(CustomEventArgs.Empty);
}
}
// Events
public final void OnHighlightsJsonChanged(CustomEventArgs eventArgs)
{
if (HighlightsJsonChanged != null)
{
for (CustomEventHandler listener : HighlightsJsonChanged.listeners())
{
listener.invoke(this, eventArgs);
}
}
}
public final void OnHighlightsContentChanging(CustomEventArgs eventArgs)
{
setHighlightsUpdating(true);
if (HighlightsContentChanging != null)
{
for (CustomEventHandler listener : HighlightsContentChanging.listeners())
{
listener.invoke(this, eventArgs);
}
}
}
public final void OnHighlightsContentChanged(CustomEventArgs eventArgs)
{
setHighlightsUpdating(false);
if (HighlightsContentChanged != null)
{
for (CustomEventHandler listener : HighlightsContentChanged.listeners())
{
listener.invoke(this, eventArgs);
}
}
}
// Constructors
public HighlightsObjectHandler()
{
setHighlights(new ArrayList<HighlightObject>());
}
}
@FunctionalInterface
public interface CustomEventHandler
{
void invoke(object sender, CustomEventArgs e);
}
public class CustomEventArgs
{
public static readonly CustomEventArgs Empty;
public CustomEventArgs()
{
}
}
//this is produced as a helper class by C# to Java Converter:
public final class Event<T>
{
private java.util.Map<String, T> namedListeners = new java.util.HashMap<String, T>();
public void addListener(String methodName, T namedEventHandlerMethod)
{
if (!namedListeners.containsKey(methodName))
namedListeners.put(methodName, namedEventHandlerMethod);
}
public void removeListener(String methodName)
{
if (namedListeners.containsKey(methodName))
namedListeners.remove(methodName);
}
private java.util.List<T> anonymousListeners = new java.util.ArrayList<T>();
public void addListener(T unnamedEventHandlerMethod)
{
anonymousListeners.add(unnamedEventHandlerMethod);
}
public java.util.List<T> listeners()
{
java.util.List<T> allListeners = new java.util.ArrayList<T>();
allListeners.addAll(namedListeners.values());
allListeners.addAll(anonymousListeners);
return allListeners;
}
}
Java custom event handler and listeners
Let's say your class that raises the event is called A
. And the class that needs to listen for the event is called B
. And the event is called SomeEvent
.
First, create an interface called SomeEventListener
:
public interface SomeEventListener {
void onSomeEvent ();
}
If there are arguments that you want to pass when the event occurs (typically something about the event), you can add it to the method.
Then in A
, you add a field:
private SomeEventListener listener;
and a method:
public void setSomeEventListener (SomeEventListener listener) {
this.listener = listener;
}
This way, B
can call setSomeEventListener
to set the listener.
When the event occurs, A
should call
if (listener != null) listener.onSomeEvent ();
And that's all there is to A
!
In B
, you need to implement the interface:
public class B implements SomeEventListener {
public void onSomeEvent () {
//do whatever you like when SomeEvent happens.
}
}
And you can listen for SomeEvent
like this:
someInstanceOfA.setSomeEventListener (this);
And after this call, all the SomeEvent
raised by A
can be listened by B
!
Using the Observable and Observer pattern, we can see that A
is an Observable and B
is an Observer.
That's easy!
How to Properly Set Up custom Event
Answer
You seem have everything set up correctly except for two problems.
You never add an
EventHandler
that listens for your event.Implementing an arbitrary interface will not make your object react to your custom event. The event processing system has no knowledge of your interface and doesn't even know you've implemented it. If you want your
onMyEvent()
method to be invoked when your event reaches the label, you would need to do something like:public MyLabel() {
//...
addEventHandler(MyEvent.MY_EVENT, event -> onMyEvent());
}Note I used
addEventHandler
so that the class itself doesn't rely on theonMyEvent
property. If you relied on the property then outside code could accidentally break your code by replacing theEventHandler
.This makes me wonder if the
MyEventListener
interface is really necessary. Couldn't you just do what you needed inside theEventHandler
?You never actually fire an instance of your
MyEvent
.You currently have:
btnSender.setOnAction(e -> MyEvent.fireEvent(lblReceiver, e));
This simply refires
e
(anActionEvent
) towardslblReceiver
. ThefireEvent
method is astatic
method declared byjavafx.event.Event
. Prefixing the method call withMyEvent
doesn't change what method is actually called here. Change that to the following:btnSender.setOnAction(e -> Event.fireEvent(lblReceiver, new MyEvent()));
// or...
btnSender.setOnAction(e -> lblReceiver.fireEvent(new MyEvent()));
// The second option is a convenience method and simply forwards to Event.fireEventIn order to actually fire an instance of your own event class at your label.
Fundamentals of Event Dispatching
There are two phases to event processing in JavaFX:
Capturing phase
- The first phase. Here the event travels from the start of its path down to the target. At each step along the way the appropriate event filters are invoked. Filters are added via methods such as
Node.addEventFilter(EventType,EventHandler)
.
- The first phase. Here the event travels from the start of its path down to the target. At each step along the way the appropriate event filters are invoked. Filters are added via methods such as
Bubbling phase
- The second phase. Here the event travels from the target back up to the start of the path. At each step along the way the appropriate event handlers are invoked. Handlers are added via methods such as
Node.addEventHandler(EventType,EventHandler)
and via properties such asNode.onKeyPressed
andButtonBase.onAction
.
- The second phase. Here the event travels from the target back up to the start of the path. At each step along the way the appropriate event handlers are invoked. Handlers are added via methods such as
And event processing consists of the following components:
javafx.event.Event
(and subclasses)The actual object passed around. Carries information related to the event (e.g. the cursor's location for
MouseEvent
s).An
Event
also carries the source. However, the source is dynamic; it will always be the object theEventHandler
currently handling the event was added to. So anEventHandler
added to aButton
will have theButton
as the event's source, but the same event will have the parent as it's source for anEventHandler
added to the parent. This behavior doesn't change even if you used the sameEventHandler
instance both times.
javafx.event.EventType
Refines the meaning of a class of
Event
. For example, aMouseEvent
with theMOUSE_PRESSED
type means, unsurprisingly, the mouse was pressed. AnEventType
has a supertype; this forms a hierarchy across all types for every kind of event. A handler registered for a supertype will also be notified of subtypes.You cannot have two or more
EventType
s with the same supertype and name. This is why instances are typicallypublic static final
fields of the corresponding event class.
javafx.event.EventHandler
- Handles any events its registered for. This is a functional interface (can be the target of a lambda expression or method reference). It's implementations of this interface that do the application-level work (i.e. do something when a button is fired).
javafx.event.EventDispatcher
Responsible for dispatching the event to the appropriate handlers. Each object capable of being the target of an event typically has its own dispatcher. For example, each
Window
,Scene
, andNode
instance has its ownEventDispatcher
instance (held in a property).Note: Outside highly specialized situations, you will never have to deal with this interface directly.
javafx.event.EventDispatchChain
Represents the path the event will take when it's fired at a target. Instances of this interface function as a stack of
EventDispatcher
s. When an event is fired, a new chain is created and configured based on the event's target. In the case of the scene graph and the target is aNode
, the stack consists of theEventDispatcher
s belonging to theWindow
, theScene
, and then eachNode
down to (parent to child) and including the target. The event travels down this chain (the capturing phase) and then back up this chain (the bubbling phase).Note: You will likely never need to use this interface directly.
javafx.event.EventTarget
The actual target of the event. The
EventTarget
interface has one method that is used to build theEventDispatchChain
. In other words, the target determines the path of the event. This is the first argument inEvent.fireEvent(EventTarget,Event)
.Note: You only need to use this interface if you're creating an object that can (obviously) be the target of events (and your object doesn't extend from an implementation of
EventTarget
).
Custom JavaFX events
You cannot. JavaFX uses javafx.event.Event
s or subtypes, so String
or even primitive int
can't be passed.
You could however create a custom subtype of Event
and add the parameters to this class.
Similarly only classes implementing javafx.event.EventHandler
can be registered as event handlers.
You could create a event handler class that delegates to your methods though:
public abstract class CustomEvent extends Event {
public static final EventType<CustomEvent> CUSTOM_EVENT_TYPE = new EventType(ANY);
public CustomEvent(EventType<? extends Event> eventType) {
super(eventType);
}
public abstract void invokeHandler(MyCustomEventHandler handler);
}
public class CustomEvent1 extends CustomEvent {
public static final EventType<CustomEvent> CUSTOM_EVENT_TYPE_1 = new EventType(CUSTOM_EVENT_TYPE, "CustomEvent1");
private final int param;
public CustomEvent1(int param) {
super(CUSTOM_EVENT_TYPE_1);
this.param = param;
}
@Override
public void invokeHandler(MyCustomEventHandler handler) {
handler.onEvent1(param);
}
}
public class CustomEvent2 extends CustomEvent {
public static final EventType<CustomEvent> CUSTOM_EVENT_TYPE_2 = new EventType(CUSTOM_EVENT_TYPE, "CustomEvent2");
private final String param;
public CustomEvent2(String param) {
super(CUSTOM_EVENT_TYPE_2);
this.param = param;
}
@Override
public void invokeHandler(MyCustomEventHandler handler) {
handler.onEvent2(param);
}
}
public abstract class MyCustomEventHandler implements EventHandler<CustomEvent> {
public abstract void onEvent1(int param0);
public abstract void onEvent2(String param0);
@Override
public void handle(CustomEvent event) {
event.invokeHandler(this);
}
}
Usage Example
Button btn = new Button("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
btn.fireEvent(new CustomEvent1(42));
btn.fireEvent(new CustomEvent2("Hello World"));
});
btn.addEventHandler(CustomEvent.CUSTOM_EVENT_TYPE, new MyCustomEventHandler() {
@Override
public void onEvent1(int param0) {
System.out.println("integer parameter: " + param0);
}
@Override
public void onEvent2(String param0) {
System.out.println("string parameter: "+param0);
}
});
How can i make custom event with property?
For Kotlin:
val MY_CUSTOM_EVENT =
EventType<Event>(Event.ANY, "MY_CUSTOM_EVENT" + UUID.randomUUID().toString())
var onOnlineClick = object : SimpleObjectProperty<EventHandler<Event>>() {
override fun getBean(): Any {
return this
}
override fun getName(): String {
return "onMyCustomEvent"
}
override fun invalidated() {
setEventHandler(MY_CUSTOM_EVENT, get())
}
}
fun onMyCustomEvent(): ObjectPropertyBase<EventHandler<Event>> {
return onMyCustomEvent
}
fun setOnMyCustomEvent(value: EventHandler<Event>) {
onMyCustomEvent.set(value)
}
fun getOnMyCustomEvent(): EventHandler<Event> {
return onMyCustomEvent.get()
}
Somewhere property
fun myProperty(): BooleanProperty {
return myCustomProperty ?: run {
myCustomProperty = object : SimpleBooleanProperty(false) {
override fun invalidated() {
fireEvent(Event(MY_CUSTOM_EVENT)) // <---this
}
override fun getBean(): Any {
return this
}
override fun getName(): String {
return "myProperty"
}
}
return myCustomProperty as SimpleBooleanProperty
}
}
Related Topics
How to Check If the User Is Pressing a Key
How to Decrypt File in Java Encrypted with Openssl Command Using Aes
Using Setdate in Preparedstatement
Differencebetween Serializable and Externalizable in Java
What Is the Easiest/Best/Most Correct Way to Iterate Through the Characters of a String in Java
Compiling a Java Program into an Executable
How to Import a .Cer Certificate into a Java Keystore
How to Use Java Property Files
How to Deal with a Slow Securerandom Generator
Java: Define Terms Initialization, Declaration and Assignment
The Best Way to Print a Java 2D Array
Httpurlconnection Doesn't Follow Redirect from Http to Https
How to Print Binary Tree Diagram in Java
Jtable Not Showing Up on Jframe (Java)
Multiple Wildcards on a Generic Methods Makes Java Compiler (And Me!) Very Confused