如何使用JavaFX从条形码扫描器读取输入

5

我有一个条形码扫描器,当我在文本框上聚焦时,我可以像键盘一样读取输入,没有任何问题。

我的问题是,如果我不在文本框上聚焦,我如何读取条形码输入,换句话说,如何添加事件监听器以监听条形码扫描器。

2个回答

4

我希望它能够类似于Java Swing解决方案 在这里介绍

我假设来自条形码扫描器的最后一个字符是ENTER。如果不是,您必须检查如何知道何时完成条形码,例如通过预期长度或通过测试键事件之间的累加时间等。

来自您的条形码扫描器的KeyEvents应该很快,因此两个事件之间的时间应该相当短。为了过滤手动输入,如果事件传递得太慢,则StringBuffer将被重置。

在您的KeyListener中,现在可以实现此方法:

private final StringBuffer barcode = new StringBuffer();
private long lastEventTimeStamp = 0L;

// ...

public void keyTyped(KeyEvent keyEvent) {
    long now = Instant.now().toEpochMilli();

    // events must come fast enough to separate from manual input
    if (now - this.lastEventTimeStamp > this.threshold) {
        barcode.delete(0, barcode.length());
    }
    this.lastEventTimeStamp = now;

    // ENTER comes as 0x000d
    if (keyEvent.getCharacter().charAt(0) == (char) 0x000d) {
        if (barcode.length() >= this.minBarcodeLength) {
            System.out.println("barcode: " + barcode);
        }
        barcode.delete(0, barcode.length());
    } else {
        barcode.append(keyEvent.getCharacter());
    }
    keyEvent.consume();
}

这只是一个粗略的实现,可能需要一些微调,但我已经在FXML控制器中为GridPane和条形码扫描器进行了测试。
注意:KeyEvent.KEY_TYPED没有设置KeyCode,所以你不能这样做
if (event.getCode().equals(KeyCode.ENTER)) {
//...
}

1

我根据 @l00tr 的答案写了更好的解决方案

public final class BarcodeAccumulator {

    public interface OnBarcodeListener {

        void onBarcodeScanned(String barcode);
    }

    private static final char BACKSPACE = '\b';
    private static final char CONTROL_V = 0x0016;
    private static final char CONTROL_Z = 0x001A;
    private static final char CARRIAGE_RETURN = 0x000d;

    private final StringBuffer buffer = new StringBuffer();

    private OnBarcodeListener barcodeListener;

    public void setBarcodeListener(OnBarcodeListener barcodeListener) {
        this.barcodeListener = barcodeListener;
    }

    public void accumulate(final TextField textField) {
        if (Objects.nonNull(textField)) {
            textField.setOnKeyTyped(event -> {
                for (char character : event.getCharacter().toCharArray()) {
                    if (Character.isISOControl(character)) {
                        if (textField.isFocused()) {
                            if (character == BACKSPACE) {
                                if (buffer.length() > textField.getCaretPosition()) {
                                    remove(textField.getCaretPosition());
                                }
                                break;
                            }
                            if (character == CONTROL_V) {
                                add(textField.getText());
                                break;
                            }
                            if (character == CONTROL_Z) {
                                clear();
                                add(textField.getText());
                                break;
                            }
                            if (character == CARRIAGE_RETURN) {
                                notifyListener(buffer.toString());
                                clear();
                                break;
                            }
                        }
                        continue;
                    }
                    add(String.valueOf(character));
                }
            });
        }
    }

    public void add(String character) {
        buffer.append(character);
    }

    public void remove(int position) {
        buffer.deleteCharAt(position);
    }

    public void clear() {
        buffer.delete(0, buffer.length());
    }

    private void notifyListener(String barcode) {
        if (Objects.nonNull(barcodeListener)) barcodeListener.onBarcodeScanned(barcode);
    }

你必须处理所有控制字符,例如ctrl+v等,因为有时用户可以手动或通过快捷键从缓冲区粘贴值到文本字段中。此外,该解决方案还遵循插入符位置并监听“退格”事件,在用户从文本字段中删除任何字符时,此操作也会更改缓冲区值。我看到问题和答案是3年前发布的,但我仍然留下我的解决方案,也许将来对某些人有帮助 =)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接