1 javafx click double-click tablerow
我正在尝试在 javafx 中创建一个表,允许用户单击一行以转到一页或双击该行以转到另一页。问题在于应用程序注册了单击事件,但没有等待查看是否有另一个双击。有没有办法让程序等待,看看是否有另一次点击?
到目前为止我所拥有的看起来类似于
TableView searchResults;
ObservableList<MovieRow> rows = FXCollections.observableArrayList();
private TableColumn<MovieRow, String> title;
title.setCellValueFactory(new PropertyValueFactory<>("mTitle"));
rows.add(new MovieRow("The cat in the hat"));
searchResults.setItems(rows);
searchResults.setRowFactory(tv -> {
TableRow<MovieRow> row = new TableRow<>();
row.setOnMouseClicked(event -> {
MovieRow tempResult = row.getItem();
if (event.getClickCount() == 1) {
System.out.println(tempResult.getMTitle + " was clicked once");
}else{
System.out.println(tempResult.getMTitle + " was clicked twice");
}
});
return row;
});
public class MovieRow{
private String mTitle;
public MovieRow(String title){
mTitle = title;
}
public String getMTitle() {
return mTitle;
}
}
Run Code Online (Sandbox Code Playgroud)
实际产量
single click: The cat in the hat was clicked once
double click: The cat in the hat was clicked once
Run Code Online (Sandbox Code Playgroud)
期望的输出
single click: The cat in the hat was clicked once
double click: The cat in the hat was clicked twice
Run Code Online (Sandbox Code Playgroud)
我只找到了自行处理双击或自行单击的结果,但没有同时处理两者,所以我不确定这是否可能。任何帮助将非常感激。谢谢。
作为 API 的一部分,您无法做到这一点:您只需自己编写代码“让程序等待,看看是否有另一次点击”。请注意,这意味着单击操作在执行之前必须稍微暂停;没有办法解决这个问题(你的程序无法知道将来会发生什么)。您可以考虑采用不同的方法(例如左按钮与右按钮)来避免这种稍微不方便的用户体验。
但是,解决方案可能如下所示:
public class DoubleClickHandler {
private final PauseTransition delay ;
private final Runnable onSingleClick ;
private final Runnable onDoubleClick ;
private boolean alreadyClickedOnce ;
public DoubleClickHandler(
Duration maxTimeBetweenClicks,
Runnable onSingleClick,
Runnable onDoubleClick) {
alreadyClickedOnce = false ;
this.onSingleClick = onSingleClick ;
this.onDoubleClick = onDoubleClick ;
delay = new PauseTransition(maxTimeBetweenClicks);
delay.setOnFinished(e -> {
alreadyClickedOnce = false ;
onSingleClick.run()
});
}
public void applyToNode(Node node) {
node.setOnMouseClicked(e -> {
delay.stop();
if (alreadyClickedOnce) {
alreadyClickedOnce = false ;
onDoubleClick.run();
} else {
alreadyClickedOnce = true ;
delay.playFromStart();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用它:
searchResults.setRowFactory(tv -> {
TableRow<MovieRow> row = new TableRow<>();
DoubleClickHandler handler = new DoubleClickHandler(
Duration.millis(500),
() -> {
MovieRow tempResult = row.getItem();
System.out.println(tempResult.getMTitle + " was clicked once");
},
() -> {
MovieRow tempResult = row.getItem();
System.out.println(tempResult.getMTitle + " was clicked twice");
}
);
handler.applyToNode(row);
return row ;
});
Run Code Online (Sandbox Code Playgroud)
我曾经遇到过同样的需求,并致力于开发自定义事件调度程序。@James_D 提供的解决方案干净、简单并且效果很好。但如果您想大规模推广此行为,您可以定义一个新的自定义鼠标事件和一个事件调度程序。
这种方法的优点是它的使用就像其他鼠标事件一样,并且可以在事件过滤器和处理程序中处理。
请检查以下演示和相应的代码:
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();
// THIS IS THE PART OF CODE SETTING CUSTOM EVENT DISPATCHER
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
728 次 |
| 最近记录: |