JavaFX equivalent to java.awt.EventQueue - java

Does JavaFX contain an equivalent to java.awt.EventQueue? For my application I need to intercept all GUI related events such as mouse and keyboard input, and so far I haven't been able to find a way to do it without attaching listeners to every GUI element.

This isn't quite the same as the question in your title, but to intercept all events, you can add an EventFilter to the Scene:
scene.addEventFilter(Event.ANY, new EventHandler<Event>() {
#Override
public void handle(Event event) {
System.out.println(event);
}
});
If you need to veto the event, call event.consume()

Related

Run some code when a popup closes in my swing app

In my app I display a popup using JPopupMenu. I want to run some code when this popup closes (either directly, programmatically or when escape key is pressed). For windows I can attach a WindowListener but JPopupMenu doesn't have any corresponding feature, and SwingUtilities.windowForComponent returns the root window of the app. How do I implement this?
How about adding a PopupMenuListener to it? Something like:
jpopMenu.addPopupMenuListener(new PopupMenuListener
{
public void popupMenuCanceled(PopupMenuEvent popupMenuEvent)
{
//here the code you want to be executed at close
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent){}
public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {}
}
This should be automatically executed when you cancel/close the popMenu. I didn't add code to the other two methods, but feel free to play with them if needed.

Why Handler doesn't work while Listener does his job?

I struggle to catch events after famous DOM.appendChild. After many attempts of use handlers I found this answer where #Ă•zbek did the job via listener.
And now I don't get it why "listener" works while "handler" not.
As an example in code:
Button button = new Button("Test button");
DOM.appendChild(getElement(), button.getElement());
button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
GWT.log("this doesn't work");
}
});
DOM.sinkEvents(button.getElement(), Event.ONCLICK);
DOM.setEventListener(button.getElement(), new EventListener() {
public void onBrowserEvent(Event event) {
GWT.log("this works perfectly!");
}
});
the listener will be working but handler not.
So where is difference beetwen them?
And how to force handler to work?
Is there are some way to do this on handlers ?
I'm trying to understand the difference between listeners and handlers. I read these answers which shows that there is no big difference but I still don't get it
Button is a Widget not an element, and if you add it as an element to the dom you would lose the events. You can either append it to the RootPanel:
RootPanel.get().add(button) if you want to use the handler.
if you want to use the element not the widget you can use DOM.createButton(), and use the listener.
setEventListener of widgets is only called when they are "attached" (to a parent widget, which is itself attached, or delayed until it is attached), and you never "attach" the button.
With an explicit serEventListener you completely bypass the widget internals (and lifecycle). You could actually just use a ButtonElement in this case.
TL;DR: don't do that, it's a symptom of a broken design.

How does the GWT sinkEvent functionality works?

I have a simple GWT setup for testing:
<g:HTMLPanel ui:field="container" width="500px" height="300px">
<g:Label ui:field="inner" text="hello"></g:Label>
</g:HTMLPanel>
With handlers added:
container.addDomHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
Window.alert("click on container");
}
}, ClickEvent.getType());
inner.addDomHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
Window.alert("click on inner");
}
}, ClickEvent.getType());
Each of these addHandler calls, as we know from the sources,
DOM.sinkEvents(Element elem, int eventBits)
inside, and the latter, according to docs, "Sets the current set of events sunk by a given element. These events will be fired to the nearest {#link EventListener} specified on any of the element's parents."
But in fact, if you click on inner div the click will be fired to its parent div in any of the 3 ways:
if I have not set any ClickHandlers on child
if I have set handlers on child
if I have set the handlers, but cleared the sinking of ClickEvent with
DOM.sinkEvents(inner.getElement(), DOM.getEventsSunk(getElement()) & ~Event.getTypeInt(ClickEvent.getType().getName()));
Why this happens and what is the true role of sinking the events?
Why adding a Handler is related to sinking events, i.e. to firing the same event to parent of the given element?
Is it possible to prevent all handlers, added to the given widget from calling without removing them explicitely? I.e. is there a way to stop processing all events on some widget?
First, sinkEvent is about adding the native event handler on the element, as explained in the GWT wiki.
What you're seeing is event bubbling, which is how events work in browsers: there are 2 phases when dispatching an event: the capture phase (not implemented in old IEs) allows any ancestor element to catch the event before it reaches its target, then in the bubbling phase the event bubbles up the DOM hierarchy. So if you listen for clicks on the HTMLPanel, you'll also receive the bubbling click events from the Label.
You can prevent that by listening to the event at the Label level and calling stopPropagation() so it doesn't bubble up to the HTMLPanel.

How to add global action event listener?

How to add a global action event listener? I've tried
Toolkit.getDefaultToolkit ().addAWTEventListener (this, AWTEvent.ACTION_EVENT_MASK);
but it doesn't work.
(example) to listen for all MouseEvents and KeyEvents in a application you can use:
long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK
+ AWTEvent.MOUSE_EVENT_MASK
+ AWTEvent.KEY_EVENT_MASK;
Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
{
public void eventDispatched(AWTEvent e)
{
System.out.println(e.getID());
}
}, eventMask);
As this code executes on the Event Dispatch Thread you will need to make sure that it executes quickly to prevent the GUI from becoming unresponsive. The above approach is used here if you want to look at a working example.
See here for more information : Global Event listeners
And this for a thourough study : AWT Event Listener
Globally listening to Action Events does not work for Swing components like JButtons since they directly call their listeners instead of dispatching the event through the AWT event queue. Java bug 6292132 describes this problem.
Unfortunately, I know of no workaround short of registering the listener with every component.
There is Global Event Dispatcher in java swing which you could use. What it basically does is, intercept the event, do your custom logic and dispatch it to the actual component. For example, if you wish to intercept a mouse click event-
EventQueue eventQueue = java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
eventQueue.push(new EventQueue()
{
#Override
public void dispatchEvent(java.awt.AWTEvent awtEvent)
{
if((awtEvent instanceof MouseEvent && awtEvent.getID() == MouseEvent.MOUSE_CLICKED)
{
// do your custom logic here
}
}
super.dispatchEvent(awtEvent);
});
You can find more info on this here - Event Dispatchers

Easier Custom Events Handling in Java

In Java, everytime I want to create a new custom event, I usually do it by add 3 methods namely:
addDogEventListener(EventListener listener);
removeDogEventListener(EventListener listener);
dispatchDogEventListener(DogEvent event);
Then now if I want to dispatch another event, say CatEvent, I will have to create all these 3 methods again:
addCatEventListener(EventListener listener);
removeCatEventListener(EventListener listener);
dispatchCatEventListener(CatEvent event);
Then if I want to manage just one kind of CatEvent event, say Meow, I have to copy and paste all these 3 methods again?! Like addCatMeowEventListener();... etc?
And usually, I need to dispatch more than one kind of events. It will be very untidy to have the whole class filled with so many methods to transmit and handle the events. Not only that, these functions have very similar code, like loop through the EventListenerList, add event to the list, etc.
Is this how I should do event dispatching in Java?
Is there a way like I can do it like:
mainApp.addEventListener(CatEvent.MEOW, new EventHandler() { meowHandler(Event e) { });
mainApp.addEventListener(CatEvent.EAT, new EventHandler() { eatHandler(Event e) { });
myCat.addEventListener(DogEvent.BARK, new EventHandler() { barkHandler(Event e) { myCat.run() });
In this way, I can just handle the different types of CatEvent in different eventHandler class and functions and I don't have to keep creating different event listener methods for different events?
Maybe I am missing something out about Java's event handling but is there a neater way that I don't have to keep copy and paste the 3 methods plus creating so many different kind of event objects for every different kind of methods I want to dispatch?
Thanks!
The event handling strategy I have is to publish by type which may suit you.
I have a broker which can examine the listener for an annotation which marks a method as listening to events. Using this approach you only need to add methods when you want to handle a specific class of event.
interface Subscriber { // marker interface for OSGi
}
#interface SubscriberCallback { // marker annotation
}
class Broker {
// uses reflections to find methods marked with #SubscriberCallback
public void addSubscriber(Subscriber subscriber);
public void removeSubscriber(Subscriber subscriber);
public <T> void publish(T... events);
}
class MyListener implements Subscriber {
#SubscriberCallback
public void onDogEvent(DogEvent... dogEvents) {
// called for one or more dog events
}
#SubscriberCallback
public void onCatEvent(CatEvent catEvent) {
// called for each CatEvent including subsclass of CatEvent.
}
}
Then if I want to manage just one kind of CatEvent event, say Meow, (and EAT)
The "action" of the event (MEOW or EAT) should be data defined in the CatEvent. Then your event listening code would check the action type and do the appropriate processing.
Maybe take a look at the TableModelEvent to see how this is done. It handles "insert", "delete" and "update" events using the same event.
Also you could probably model a general event listener based on the PropertyChangeListener. A PropertyChangeListener is used to handle events when various properties change on a Swing component. For example when you invoke setForeground() or setBackground() or setFont() or setText() or setIcon. The PropertyChangeListener uses a getName() method to determine which property has been changed. So for the above methods the names would be "foreground", "background", "font", "text", "icon". See How to Use Property Changes Listeners for an example of how this might work.
In your case the names would be "cat" and "dog". This approach would only work if the GeneralEvent you create can contain information that is relevant to each of your events (ie. "meow" and "bark").

Categories

Resources