Skip to content

Instantly share code, notes, and snippets.

@TomasMikula
Last active March 2, 2019 22:51
Show Gist options
  • Save TomasMikula/54bf9ce95ce6bc2f3a56 to your computer and use it in GitHub Desktop.
Save TomasMikula/54bf9ce95ce6bc2f3a56 to your computer and use it in GitHub Desktop.
Detecting when the mouse stays still over a node in JavaFX
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.InputEvent;
public abstract class MouseStationaryEvent extends InputEvent {
private static final long serialVersionUID = 1L;
private static final End DEFAULT_END = new End(null, null);
public static final EventType<MouseStationaryEvent> ANY =
new EventType<>(InputEvent.ANY, "MOUSE_STATIONARY_ANY");
public static final EventType<MouseStationaryEvent> MOUSE_STATIONARY_BEGIN =
new EventType<>(ANY, "MOUSE_STATIONARY_BEGIN");
public static final EventType<MouseStationaryEvent> MOUSE_STATIONARY_END =
new EventType<>(ANY, "MOUSE_STATIONARY_END");
static final MouseStationaryEvent beginAt(Point2D screenPos) {
return new Begin(null, null, screenPos);
}
static final MouseStationaryEvent end() {
return DEFAULT_END;
}
private static class Begin extends MouseStationaryEvent {
private static final long serialVersionUID = 1L;
private final Point2D screenPos;
public Begin(Object source, EventTarget target, Point2D screenPos) {
super(source, target, MOUSE_STATIONARY_BEGIN);
this.screenPos = screenPos;
}
@Override
public Point2D getPosition() {
if(source instanceof Node) {
return ((Node) source).screenToLocal(screenPos);
} else if(source instanceof Scene) {
return getScenePosition();
} else {
return null;
}
}
@Override
public Point2D getScenePosition() {
Scene scene;
if(source instanceof Node) {
scene = ((Node) source).getScene();
} else if(source instanceof Scene) {
scene = (Scene) source;
} else {
return null;
}
return screenPos.subtract(
scene.getX() + scene.getWindow().getX(),
scene.getY() + scene.getWindow().getY());
}
@Override
public Point2D getScreenPosition() {
return screenPos;
}
@Override
public Begin copyFor(Object newSource, EventTarget newTarget) {
return new Begin(newSource, newTarget, screenPos);
}
}
private static class End extends MouseStationaryEvent {
private static final long serialVersionUID = 1L;
public End(Object source, EventTarget target) {
super(source, target, MOUSE_STATIONARY_END);
}
@Override
public Point2D getPosition() { return null; }
@Override
public Point2D getScenePosition() { return null; }
@Override
public Point2D getScreenPosition() { return null; }
@Override
public End copyFor(Object newSource, EventTarget newTarget) {
return new End(newSource, newTarget);
}
}
private MouseStationaryEvent(
Object source,
EventTarget target,
EventType<? extends MouseStationaryEvent> type) {
super(source, target, type);
}
public abstract Point2D getPosition();
public abstract Point2D getScenePosition();
public abstract Point2D getScreenPosition();
}
import static javafx.scene.input.MouseEvent.*;
import static org.reactfx.EventStreams.*;
import java.time.Duration;
import javafx.event.Event;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import org.reactfx.EventStream;
import org.reactfx.Subscription;
import org.reactfx.util.Either;
public class MouseStationaryHelper {
private final Node node;
private final EventStream<Either<Point2D, Void>> stationaryEvents;
private Subscription installed = null;
public MouseStationaryHelper(Node node, Duration delay) {
this.node = node;
EventStream<MouseEvent> mouseEvents = eventsOf(node, MouseEvent.ANY);
EventStream<Point2D> stationaryPositions = mouseEvents
.successionEnds(delay)
.filter(e -> e.getEventType() == MOUSE_MOVED)
.map(e -> new Point2D(e.getX(), e.getY()));
EventStream<Void> stoppers = mouseEvents.supply((Void) null);
stationaryEvents = stationaryPositions.or(stoppers).distinct();
}
public EventStream<Either<Point2D, Void>> events() {
return stationaryEvents;
}
public void install() {
if(installed == null) {
installed = stationaryEvents.<Event>map(either -> either.unify(
pos -> MouseStationaryEvent.beginAt(node.localToScreen(pos)),
stop -> MouseStationaryEvent.end()))
.subscribe(evt -> Event.fireEvent(node, evt));
}
}
public void uninstall() {
if(installed != null) {
installed.unsubscribe();
installed = null;
}
}
}
@TomasMikula
Copy link
Author

This gist is referenced from Detecting when the mouse stays still over a node.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment