Assuming you are doing something like
if (mouseEvent.getClickCount()==1)
etc, then it's probably not doing what you think. MouseEvent.getClickCount()
just returns the number of clicks that have occurred in a "small" region and in a "small" amount of time. "Small" is (deliberately) not defined.
So a double click is just two clicks. The first returns 1 for getClickCount()
, then second returns 2. Similarly, a triple click is three clicks: the first returns 1, the next 2, the third 3. You can test this with a very simple piece of code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ClickCountTest extends Application {
@Override
public void start(Stage primaryStage) {
Pane root = new Pane();
root.setOnMouseClicked(event -> System.out.println(event.getClickCount()));
primaryStage.setScene( new Scene(root, 250, 150) );
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you click, you'll see the output "1". If you double click, you'll see a "1" followed by a "2".
There's no built-in way to ignore the first click if it's part of a double (or triple) click. The issue, obviously, is that at the time of the first click, there's no way of knowing if another click is going to come without some kind of timing, which gets pretty complicated and would force a delay on responding to any mouse click.
There was some talk a while back about implementing an onClickSequenceFinished
type of event, so that instead of listening for mouse click events, you could listen for the click sequence finished event and then query that event to find the number of clicks. In the end, it was decided not to support this as the use case was not considered good UI programming practice.
The reason for that is that it's a pretty bad idea for, say, a double click to exclude the action of a single click. If the user is just too slow with their double click, then they will inadvertently invoke the single click action (twice). So if you are supporting both double click and single click actions, then the actions should be chosen so that it makes sense for the single-click action to be invoked any time the double-click action is invoked. The typical example is a ListView
, where double-clicking a list element opens a "details" editor, and single-clicking selects the item. It makes sense for the item being edited to also be selected, so the double-click action implies the single-click action.
Put another way, it's considered a bad design if a double click action is designed to exclude a single click action, and that idiom is not directly supported. You should consider using modifier keys instead of click counts for this kind of distinction.
Update:
If you really want to distinguish events by click count like this (and I really don't recommend it), then you can use something like a PauseTransition
to implement the timer. Something like:
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ClickCountTest extends Application {
@Override
public void start(Stage primaryStage) {
// This value may need tuning:
Duration maxTimeBetweenSequentialClicks = Duration.millis(500);
PauseTransition clickTimer = new PauseTransition(maxTimeBetweenSequentialClicks);
final IntegerProperty sequentialClickCount = new SimpleIntegerProperty(0);
clickTimer.setOnFinished(event -> {
int count = sequentialClickCount.get();
if (count == 1) System.out.println("Single click");
if (count == 2) System.out.println("Double click");
if (count == 3) System.out.println("Triple click");
if (count > 3) System.out.println("Multiple click: "+count);
sequentialClickCount.set(0);
});
Pane root = new Pane();
root.setOnMouseClicked(event -> {
sequentialClickCount.set(sequentialClickCount.get()+1);
clickTimer.playFromStart();
});
primaryStage.setScene( new Scene(root, 250, 150) );
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This is also probably a good use case for Tomas Mikula's ReactFX framework, (also see his blog post).