JavaFX2单击并双击
我想知道是否有可能在JavaFX2中检测到双击?怎么做 我想在单击和双击之间创建不同的事件JavaFX2单击并双击,java,click,javafx,javafx-2,double-click,Java,Click,Javafx,Javafx 2,Double Click,我想知道是否有可能在JavaFX2中检测到双击?怎么做 我想在单击和双击之间创建不同的事件 谢谢是的,您可以检测到单次、双次甚至多次单击: myNode.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent mouseEvent) { if(mouseEvent.getButton().equals(MouseButton.P
谢谢是的,您可以检测到单次、双次甚至多次单击:
myNode.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
if(mouseEvent.getClickCount() == 2){
System.out.println("Double clicked");
}
}
}
});
myNode.setOnMouseClicked(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent MouseEvent){
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
if(mouseEvent.getClickCount()==2){
System.out.println(“双击”);
}
}
}
});
MouseButton.PRIMARY
用于确定事件是否触发鼠标左键(通常)。阅读getClickCount()
的api,得出可能存在多个单击计数而不是单次或双次的结论。然而,我发现很难区分单击事件和双击事件。因为双击的第一次单击计数也会引发一个事件。下面是我如何实现双击的
if (e.getEventType().equals(MouseEvent.MOUSE_CLICKED) && !drag_Flag) {
long diff = 0;
if(time1==0)
time1=System.currentTimeMillis();
else
time2=System.currentTimeMillis();
if(time1!=0 && time2!=0)
diff=time2-time1;
if((diff/1000)<=215 && diff>0)
{
isdblClicked=true;
}
else
{
isdblClicked=false;
}
System.out.println("IsDblClicked()"+isdblClicked);
if(e.getEventType().equals(MouseEvent.MOUSE_CLICKED)&!drag_标志){
长差=0;
如果(时间1==0)
time1=System.currentTimeMillis();
其他的
time2=System.currentTimeMillis();
if(time1!=0&&time2!=0)
差异=时间2-1;
如果((差值/1000)0)
{
isdbl=true;
}
其他的
{
isdbl=false;
}
System.out.println(“IsDblClicked()”+IsDblClicked);
}如果您必须区分单击和双击,并且在这两种情况下都必须执行特定操作,则可以使用另一段代码
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class DoubleClickDetectionTest extends Application {
boolean dragFlag = false;
int clickCounter = 0;
ScheduledThreadPoolExecutor executor;
ScheduledFuture<?> scheduledFuture;
public DoubleClickDetectionTest() {
executor = new ScheduledThreadPoolExecutor(1);
executor.setRemoveOnCancelPolicy(true);
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
if (e.getButton().equals(MouseButton.PRIMARY)) {
dragFlag = true;
}
}
});
root.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
if (e.getButton().equals(MouseButton.PRIMARY)) {
if (!dragFlag) {
System.out.println(++clickCounter + " " + e.getClickCount());
if (e.getClickCount() == 1) {
scheduledFuture = executor.schedule(() -> singleClickAction(), 500, TimeUnit.MILLISECONDS);
} else if (e.getClickCount() > 1) {
if (scheduledFuture != null && !scheduledFuture.isCancelled() && !scheduledFuture.isDone()) {
scheduledFuture.cancel(false);
doubleClickAction();
}
}
}
dragFlag = false;
}
}
});
}
@Override
public void stop() {
executor.shutdown();
}
private void singleClickAction() {
System.out.println("Single-click action executed.");
}
private void doubleClickAction() {
System.out.println("Double-click action executed.");
}
}
import java.util.concurrent.ScheduledFuture;
导入java.util.concurrent.ScheduledThreadPoolExecutor;
导入java.util.concurrent.TimeUnit;
导入javafx.application.application;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.input.MouseButton;
导入javafx.scene.input.MouseEvent;
导入javafx.scene.layout.StackPane;
导入javafx.stage.stage;
公共类DoubleClickDetectionTest扩展了应用程序{
布尔dragFlag=false;
int clickCounter=0;
ScheduledThreadPoolExecutor执行器;
计划的未来计划的未来;
公共双击检测测试(){
executor=新的ScheduledThreadPoolExecutor(1);
执行人。setRemoveOnCancelPolicy(真);
}
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
public void start(Stage primaryStage)引发异常{
StackPane root=新的StackPane();
原始阶段。设置场景(新场景(根,400400));
primaryStage.show();
setOnMouseDrawed(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent e){
if(例如getButton().equals(MouseButton.PRIMARY)){
dragFlag=true;
}
}
});
setOnMouseClicked(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent e){
if(例如getButton().equals(MouseButton.PRIMARY)){
if(!dragFlag){
System.out.println(++clickCounter+“”+e.getClickCount());
如果(如getClickCount()==1){
scheduledFuture=executor.schedule(()->singleClickAction(),500,时间单位为毫秒);
}否则如果(如getClickCount()>1){
if(scheduledFuture!=null&&!scheduledFuture.isCancelled()&&!scheduledFuture.isDone()){
scheduledFuture.cancel(false);
双击操作();
}
}
}
dragFlag=false;
}
}
});
}
@凌驾
公共停车场(){
executor.shutdown();
}
私有void singleClickAction(){
System.out.println(“执行的单击操作”);
}
私有void doubleClickAction(){
System.out.println(“双击操作已执行”);
}
}
潘迪的回答是最简单的方法,它实际上区分了单击和双击,但对我来说并不适用。首先,函数“currentTimeMillis”已经返回毫秒,因此将其除以1000似乎没有必要。下面的版本以一种更加一致的方式为我工作
@Override
public void handle(MouseEvent t) {
long diff = 0;
currentTime=System.currentTimeMillis();
if(lastTime!=0 && currentTime!=0){
diff=currentTime-lastTime;
if( diff<=215)
isdblClicked=true;
else
isdblClicked=false;
}
lastTime=currentTime;
System.out.println("IsDblClicked()"+isdblClicked);
//use the isdblClicked flag...
}
@覆盖
公共无效句柄(MouseEvent t){
长差=0;
currentTime=System.currentTimeMillis();
如果(lastTime!=0&¤tTime!=0){
差异=当前时间最后时间;
如果(diff遵循Java SE 8 lambda表达式,则如下所示:
node.setOnMouseClicked(event -> {
if(event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
handleSomeAction();
}
});
一旦您习惯了lambda表达式-它们最终比原始的类实例化和重写(x)方法更容易理解。-在我看来-由于默认情况下无法区分单击和双击,我们使用以下方法:
在单击时,我们将单击操作包装在一个可中止的runnable中。此runnable在执行之前等待一定时间(即,单击延迟
)
同时,如果发生第二次单击,即双击,则单键单击操作将中止,仅执行双击操作
这样,可以执行单击或双击操作,但不能同时执行这两种操作
以下是完整的代码。要使用它,只需将三行TODO
行替换为所需的处理程序
private static final int SINGLE_CLICK_DELAY = 250;
private ClickRunner latestClickRunner = null;
private class ClickRunner implements Runnable {
private final Runnable onSingleClick;
private boolean aborted = false;
public ClickRunner(Runnable onSingleClick) {
this.onSingleClick = onSingleClick;
}
public void abort() {
this.aborted = true;
}
@Override
public void run() {
try {
Thread.sleep(SINGLE_CLICK_DELAY);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!aborted) {
System.out.println("Execute Single Click");
Platform.runLater(() -> onSingleClick.run());
}
}
}
private void init() {
container.setOnMouseClicked(me -> {
switch (me.getButton()) {
case PRIMARY:
if (me.getClickCount() == 1) {
System.out.println("Single Click");
latestClickRunner = new ClickRunner(() -> {
// TODO: Single-left-click operation
});
CompletableFuture.runAsync(latestClickRunner);
}
if (me.getClickCount() == 2) {
System.out.println("Double Click");
if (latestClickRunner != null) {
System.out.println("-> Abort Single Click");
latestClickRunner.abort();
}
// TODO: Double-left-click operation
}
break;
case SECONDARY:
// TODO: Right-click operation
break;
default:
break;
}
});
}
使用PauseTransition的解决方案:
PauseTransition singlePressPause=新的PauseTransition(持续时间.millis(500));
单按Pause.setOnFinis
node.addEventFilter(CustomMouseEvent.MOUSE_DOUBLE_CLICKED, e->{..<code to handle double_click>..});
node.addEventHandler(CustomMouseEvent.MOUSE_DOUBLE_CLICKED, e->{..<code to handle double_click>..});
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class DoubleClickEventDispatcherDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
Rectangle box1 = new Rectangle(150, 150);
box1.setStyle("-fx-fill:red;-fx-stroke-width:2px;-fx-stroke:black;");
addEventHandlers(box1, "Red Box");
Rectangle box2 = new Rectangle(150, 150);
box2.setStyle("-fx-fill:yellow;-fx-stroke-width:2px;-fx-stroke:black;");
addEventHandlers(box2, "Yellow Box");
HBox pane = new HBox(box1, box2);
pane.setSpacing(10);
pane.setAlignment(Pos.CENTER);
addEventHandlers(pane, "HBox");
Scene scene = new Scene(new StackPane(pane), 450, 300);
stage.setScene(scene);
stage.show();
// SETTING CUSTOM EVENT DISPATCHER TO SCENE
scene.setEventDispatcher(new DoubleClickEventDispatcher(scene.getEventDispatcher()));
}
private void addEventHandlers(Node node, String nodeId) {
node.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> System.out.println("" + nodeId + " mouse clicked filter"));
node.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("" + nodeId + " mouse clicked handler"));
node.addEventFilter(CustomMouseEvent.MOUSE_DOUBLE_CLICKED, e -> System.out.println("" + nodeId + " mouse double clicked filter"));
node.addEventHandler(CustomMouseEvent.MOUSE_DOUBLE_CLICKED, e -> System.out.println(nodeId + " mouse double clicked handler"));
}
/**
* Custom MouseEvent
*/
interface CustomMouseEvent {
EventType<MouseEvent> MOUSE_DOUBLE_CLICKED = new EventType<>(MouseEvent.ANY, "MOUSE_DBL_CLICKED");
}
/**
* Custom EventDispatcher to differentiate from single click with double click.
*/
class DoubleClickEventDispatcher implements EventDispatcher {
/**
* Default delay to fire a double click event in milliseconds.
*/
private static final long DEFAULT_DOUBLE_CLICK_DELAY = 215;
/**
* Default event dispatcher of a node.
*/
private final EventDispatcher defaultEventDispatcher;
/**
* Timeline for dispatching mouse clicked event.
*/
private Timeline clickedTimeline;
/**
* Constructor.
*
* @param initial Default event dispatcher of a node
*/
public DoubleClickEventDispatcher(final EventDispatcher initial) {
defaultEventDispatcher = initial;
}
@Override
public Event dispatchEvent(final Event event, final EventDispatchChain tail) {
final EventType<? extends Event> type = event.getEventType();
if (type == MouseEvent.MOUSE_CLICKED) {
final MouseEvent mouseEvent = (MouseEvent) event;
final EventTarget eventTarget = event.getTarget();
if (mouseEvent.getClickCount() > 1) {
if (clickedTimeline != null) {
clickedTimeline.stop();
clickedTimeline = null;
final MouseEvent dblClickedEvent = copy(mouseEvent, CustomMouseEvent.MOUSE_DOUBLE_CLICKED);
Event.fireEvent(eventTarget, dblClickedEvent);
}
return mouseEvent;
}
if (clickedTimeline == null) {
final MouseEvent clickedEvent = copy(mouseEvent, mouseEvent.getEventType());
clickedTimeline = new Timeline(new KeyFrame(Duration.millis(DEFAULT_DOUBLE_CLICK_DELAY), e -> {
Event.fireEvent(eventTarget, clickedEvent);
clickedTimeline = null;
}));
clickedTimeline.play();
return mouseEvent;
}
}
return defaultEventDispatcher.dispatchEvent(event, tail);
}
/**
* Creates a copy of the provided mouse event type with the mouse event.
*
* @param e MouseEvent
* @param eventType Event type that need to be created
* @return New mouse event instance
*/
private MouseEvent copy(final MouseEvent e, final EventType<? extends MouseEvent> eventType) {
return new MouseEvent(eventType, e.getSceneX(), e.getSceneY(), e.getScreenX(), e.getScreenY(),
e.getButton(), e.getClickCount(), e.isShiftDown(), e.isControlDown(), e.isAltDown(),
e.isMetaDown(), e.isPrimaryButtonDown(), e.isMiddleButtonDown(),
e.isSecondaryButtonDown(), e.isSynthesized(), e.isPopupTrigger(),
e.isStillSincePress(), e.getPickResult());
}
}
}