3

ユーザーがバーコードをスキャンできるシステムを開発しています。バーコード スキャナは効果的にキーボードのように動作し、バーコードの各桁を超人的な速度で「入力」します。この例では、連続する「キー ストローク」間のほとんどの時間が 10 ミリ秒であるとします。

アプリケーションのEventHandlerで数値をリッスンする を実装することから始めました。が到着したとき、ハンドラーはそれが人間によって入力されたのか、それともバーコード スキャナーによって入力されたのかをまだ知りません (今から 10 ミリ秒後に知ることができます)。残念ながら、ここで決定を下さなければ、JavaFX のメイン スレッドがロックされる危険性があるため、処理されないように自動的に呼び出しますKeyEventWindowKeyEventkeyEvent.consume()

10 ミリ秒が経過すると、タイマーが起動しKeyEvent、バーコードの一部であるかどうかを判断します。そうであった場合、KeyEventは連結され、バーコード処理ロジックによって処理されます。KeyEventそれ以外の場合は、アプリケーションに通常どおり処理させたいと考えています。

KeyEvent既に呼び出した後に、アプリケーションに強制的に処理させるにはどうすればよいkeyEvent.consume()ですか?

4

1 に答える 1

3

これがどのように行われるかについての私の見解です。

このソリューションは、アプリの主要なイベントをフィルター処理し、それらを複製して、複製したイベントをキューに配置し、フィルター内の元のイベントを消費することによって機能します。複製されたイベント キューは後で処理されます。バーコード リーダーからのイベントは再起動されません。バーコード リーダー以外からのイベントは、システムが処理できるように再起動されます。データ構造は、イベントがすでに処理されているかどうかを追跡します。これにより、システムは、本当にイベントをインターセプトして消費する必要があるのか​​、それとも標準の 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();
  }
}

プログラム出力の例:

サンプルプログラムの出力

タイムラインを使用しているため、コード内のすべてが FXApplicationThread で実行されるため、実装の同時実行について心配する必要はありません。実際のバーコード リーダーとバーコード イベント プロセッサを使用した実装では、複数のスレッドが関与する可能性があるため、同時実行保護を追加する必要がある場合があります。また、バーコード システムの遅延処理をシミュレートするために、私のコードで使用されているタイムラインが必要ない場合もあります。

于 2012-08-10T02:06:39.100 に答える