gpt4 book ai didi

java - 在 JavaFX 中重新触发消费事件

转载 作者:行者123 更新时间:2023-12-01 14:24:15 24 4
gpt4 key购买 nike

我正在开发一个允许用户扫描条形码的系统。条形码扫描器有效地像键盘一样工作,以超人的速度“输入”条形码的每个数字。为了这个例子,我们假设连续“击键”之间的大部分时间是 10 毫秒。

我首先实现了一个 EventHandler,它在应用程序的 Window 上监听数字 KeyEvent。当 KeyEvent 到达时,处理程序尚不知道它是由人输入的还是由条形码扫描器输入的(它从现在起知道 10 毫秒)。不幸的是,我必须现在做出决定,否则可能会锁定 JavaFX 的主线程,因此我会自动调用 keyEvent.consume() 以防止它被处理。

经过 10 毫秒后,计时器将唤醒并决定 KeyEvent 是否是条形码的一部分。如果是,则 KeyEvent 将连接在一起并由条形码处理逻辑处理。否则,我想让应用程序正常处理 KeyEvent

在我已经调用 keyEvent.consume() 之后,如何强制应用程序处理 KeyEvent

最佳答案

这是我对如何做到这一点的看法。

该解决方案的工作原理是过滤应用程序的关键事件,克隆它们并将克隆的事件放入队列中,然后使用过滤器中的原始事件。稍后处理克隆的事件队列。来自条形码阅读器的事件不会重新触发。不是来自条形码阅读器的事件将被重新触发,以便系统可以处理它们。数据结构跟踪事件是否已被处理,以便系统可以在事件过滤器中知道它是否真的必须拦截和使用事件或让它们传递给标准 JavaFX 事件处理程序。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

// delays event key press handling so that some events can be intercepted
// and routed to a bar code a reader and others can be processed by the app.
public class EventRefire extends Application {
public static void main(String[] args) { launch(args); }
@Override public void start(final Stage stage) throws Exception {
// create the scene.
final VBox layout = new VBox();
final Scene scene = new Scene(layout);

// create a queue to hold delayed events which have not yet been processed.
final List<KeyEvent> unprocessedEventQueue = new ArrayList();
// create a queue to hold delayed events which have already been processed.
final List<KeyEvent> processedEventQueue = new ArrayList();

// create some controls for the app.
final TextField splitterField1 = new TextField(); splitterField1.setId("f1");
final TextField splitterField2 = new TextField(); splitterField2.setId("f2");
final Label forBarCode = new Label();
final Label forTextField = new Label();

// filter key events on the textfield and don't process them straight away.
stage.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
@Override public void handle(KeyEvent event) {
if (event.getTarget() instanceof Node) {
if (!processedEventQueue.contains(event)) {
unprocessedEventQueue.add((KeyEvent) event.clone());
event.consume();
} else {
processedEventQueue.remove(event);
}
}
}
});

// set up a timeline to simulate handling delayed event processing from
// the barcode scanner.
Timeline timeline = new Timeline(
new KeyFrame(
Duration.seconds(1),
new EventHandler() {
@Override public void handle(Event timeEvent) {
// process the unprocessed events, routing them to the barcode reader
// or scheduling the for refiring as approriate.
final Iterator<KeyEvent> uei = unprocessedEventQueue.iterator();
final List<KeyEvent> refireEvents = new ArrayList();
while (uei.hasNext()) {
KeyEvent event = uei.next();
String keychar = event.getCharacter();
if ("barcode".contains(keychar)) {
forBarCode.setText(forBarCode.getText() + keychar);
} else {
forTextField.setText(forTextField.getText() + keychar);
refireEvents.add(event);
}
}

// all events have now been processed - clear the unprocessed event queue.
unprocessedEventQueue.clear();

// refire all of the events scheduled to refire.
final Iterator<KeyEvent> rei = refireEvents.iterator();
while (rei.hasNext()) {
KeyEvent event = rei.next();
processedEventQueue.add(event);
if (event.getTarget() instanceof Node) {
((Node) event.getTarget()).fireEvent(event);
}
}
}
}
)
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();

// layout the scene.
final GridPane grid = new GridPane();
grid.addRow(0, new Label("Input Field 1:"), splitterField1);
grid.addRow(1, new Label("Input Field 2:"), splitterField2);
grid.addRow(2, new Label("For App:"), forTextField);
grid.addRow(3, new Label("For BarCode:"), forBarCode);
grid.setStyle("-fx-padding: 10; -fx-vgap: 10; -fx-hgap: 10; -fx-background-color: cornsilk;");

Label instructions = new Label("Type letters - key events which generate the lowercase letters b, a, r, c, o, d, e will be routed to the barcode input processor, other key events will be routed back to the app and processed normally.");
instructions.setWrapText(true);
layout.getChildren().addAll(grid, instructions);
layout.setStyle("-fx-padding: 10; -fx-vgap: 10; -fx-background-color: cornsilk;");
layout.setPrefWidth(300);
stage.setScene(scene);
stage.show();
}
}

示例程序输出:

Sample program output

因为我使用时间轴,所以我的代码中的所有内容都在 FXApplicationThread 上运行,所以我不必担心我的实现中的并发性。在使用真正的条形码阅读器和条形码事件处理器的实现中,您可能需要一些额外的并发保护,因为可能会涉及多个线程。此外,您可能不需要我的代码中使用的时间线来模拟条形码系统的延迟处理。

关于java - 在 JavaFX 中重新触发消费事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11890128/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com