Search code examples
javaswingjtextfieldkeyevent

Custom JTextField bug when trying to process minus key


I made a custom JTextField to input numeric values. The class looks as follows:

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;

public class JNumberField extends JTextField {

    public JNumberField(int width, int height) {
        this();
        setPreferredSize(new Dimension(width, height));
    }

    public JNumberField() {
        setFont(new Font("Monospace", Font.BOLD, 23));
        setHorizontalAlignment(JTextField.HORIZONTAL);
    }

    @Override
    public void processKeyEvent(KeyEvent ev) {
        //Accepts digits, backspace, minus key and left/right arrow keys
        if (Character.isDigit(ev.getKeyChar()) || ev.getKeyCode() == KeyEvent.VK_BACK_SPACE || ev.getKeyCode() == KeyEvent.VK_MINUS || ev.getKeyCode() == KeyEvent.VK_LEFT || ev.getKeyCode() == KeyEvent.VK_RIGHT) {
            super.processKeyEvent(ev);
        }
        ev.consume();
    }

    public static void main(String[] args) {
        JOptionPane.showInputDialog(new JNumberField(300,50));
    }
}

All the keys are working except for the "-" key. I also printed the keycode that was pressed and it responded with 45 so the if statement is executed but it doesn't insert the - into the text field. Is this a bug or how can it be fixed? I also tried removing the if statement and just call the processKeyEvent method and then it works to insert the - sign...


Solution

  • First of all I totally agree with Andrew, there are better solutions to solving the problem. For example you can use:

    1. a JSpinner
    2. a JFormattedTextField
    3. a DocumentFilter - see: How to automatically update small letter characters to capital letter in Java JEditorPane?

    The reason the above solutions are better is because:

    1. you don't need to extend a class
    2. the solutions are more abstract

    Your solution is a low level solution, which means you need to understands the events that are generated when you press a key and how those events are handled by Swing.

    A more abstract solution is always better since you don't need to know the details. This is why the Swing API has evolved.

    In your case you are not understanding the difference between a "displayable" key event and a "non displayable" event.

    A text component is updated when the keyTyped event is generated which is only generated for "displayable" character like " numeric digits" and "-".

    A "keyTyped" event is not generated for using the arrow keys or backspace keys.

    So your logic needs to be changed to handle the "-" as a character (not a key code):

    //if (Character.isDigit(ev.getKeyChar()) || ev.getKeyCode() == KeyEvent.VK_MINUS ...
    if (Character.isDigit(ev.getKeyChar()) || ev.getKeyChar() == '-' ...