Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can read input from barcode scanner with JavaFX

Tags:

java

javafx

I have Barcode Scanner i can read the input in the when i focus on the text field without any problem just like keyboard.

My question how i can read the barcode input if i do no focus on the textfield in other word how make event listener to listen to the Barcode Scanner.

like image 871
Ali Mohammed Avatar asked Jul 20 '15 09:07

Ali Mohammed


2 Answers

It should work analog to the Java Swing solution presented here.

I assume the final character coming from the barcode scanner is ENTER. If not, you must check how to know when the barcode is done, e.g. by the expected length or by testing for summed up time between the key events or whatever.

The KeyEvents from your barcode scanner should come fast, so the time between two events should be rather short. To filter out manual typing, the StringBuffer is reset if events come too slow.

In your KeyListener, you can now implement this method:

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();
}

This is just a rough implementation which probably requires some fine tuning, but I've tested it in an FXML controller for a GridPane and for the barcode scanner I have it works.

Note: The KeyEvent.KEY_TYPED does not have the KeyCode set, so you cannot do this:

if (event.getCode().equals(KeyCode.ENTER)) {
//...
}
like image 69
AntiTiming Avatar answered Oct 11 '22 08:10

AntiTiming


I've wrote better solution based on @l00tr answer

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);
    }

You must to handle all control characters such as ctrl+v etc., 'cause sometimes users can paste value inside text field manually or from buffer with shortcuts. Besides, this solution follows for caret position and listen "backspace" event, and in case, when user removes any character from text field, this action also change buffer value. I see that the question and answer were posted 3 years ago, but I still leave my solution there, maybe it will be help for somebody in future =)

like image 33
Denis Makovsky Avatar answered Oct 11 '22 07:10

Denis Makovsky