Я хотел бы узнать, удалось ли обнаружить двойной щелчок в JavaFX 2? и как?
Я хотел бы сделать другое событие между щелчком и двойным щелчком.
Спасибо
Я хотел бы узнать, удалось ли обнаружить двойной щелчок в JavaFX 2? и как?
Я хотел бы сделать другое событие между щелчком и двойным щелчком.
Спасибо
Да, вы можете обнаружить одиночные, двойные, даже множественные щелчки:
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");
}
}
}
});
MouseButton.PRIMARY
используется, чтобы определить, будет ли левая (обычно) кнопка мыши инициировать событие. Прочтите api getClickCount()
, чтобы сделать вывод, что, возможно, несколько кликов, кроме одного или двух. Однако мне трудно различать события одиночного и двойного кликов. Поскольку первый щелчок мышью двойного клика также увеличит одно событие.
Не работает, если вы хотите обрабатывать один клик и двойные щелчки, добавив
if(mouseEvent.getClickCount() == 2)
{
System.out.println("Doubleclicked");
}
else if(mouseEvent.getClickCount() == 1)
{
System.out.println("Single clicked");
}
Результаты в:
"Single clicked"
всегда запускается.
Вот еще один фрагмент кода, который можно использовать, если вам нужно различать однократный и двойной щелчок, и в любом случае нужно принять конкретное действие.
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.");
}
}
Ответ P. Pandey - это самый простой подход, который фактически отличает однократный и двойной щелчок, но для меня это не сработало. Во-первых, функция 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...
}
Вот как я реализовал двойной клик
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);
}
Придерживаясь лямбда-выражений Java SE 8, выглядело бы примерно так:
node.setOnMouseClicked(event -> {
if(event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
handleSomeAction();
}
});
Как только вы привыкнете к лямбда-выражениям, они станут более понятными, чем метод создания и переопределения исходного класса (x). -In мой opinion-
Поскольку по умолчанию невозможно различить одиночный и двойной щелчок, мы используем следующий подход:
По одному щелчку мы оборачиваем операцию по одному щелчку в сбрасываемом исполняемом файле. Этот исполняемый файл ожидает некоторое время (т.е. SINGLE_CLICK_DELAY
), прежде чем будет выполнен.
В то же время, если происходит второй щелчок, т.е. двойной щелчок, операция однократного нажатия прерывается и выполняется только операция двойного щелчка.
Таким образом, выполняется операция с одним или двумя щелчками, но не с обеими.
Ниже приведен полный код. Чтобы использовать его, нужно заменить только три строки 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 = new PauseTransition(Duration.millis(500));
singlePressPause.setOnFinished(e -> {
// single press
});
node.setOnMousePressed(e -> {
if (e.isPrimaryButtonDown() && e.getClickCount() == 1) {
singlePressPause.play();
}
if (e.isPrimaryButtonDown() && e.getClickCount() == 2) {
singlePressPause.stop();
// double press
}
});