Last active
March 2, 2019 22:51
-
-
Save TomasMikula/54bf9ce95ce6bc2f3a56 to your computer and use it in GitHub Desktop.
Detecting when the mouse stays still over a node in JavaFX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This gist is referenced from Detecting when the mouse stays still over a node.