Checking JTextField Characters - java

I have a program I've written for my kids to practice basic arithmetic. There is a JTextField on a JFrame where the student keys in the answer to a given math problem (like 8+8, they key in 16, Enter). This field accepts only integer values as entries by way of a DocumentFilter.
That part works just fine. What I want to do with this is to avoid having the user have to hit the enter key. Ideally, when the user keys in the first number (1), a check is done to see if 1 == 16. If not, nothing happens. When they subsequently type the 6, the text field displays the number 16. I want to run a check to verify if 16 == 16, and then handle the entry as if the user had also hit the Enter key.
txtAnswer.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
respondToAnswer(isTimed);
} else {
/* Check if the correct answer has been entered */
System.out.println(txtAnswer.getText());
//int userAnswer = Integer.parseInt(txtAnswer.getText());
//if (userAnswer == correctAnswer {
// respondToAnswer(isTimed);
//}
}
};
});
This code isn't quite working. It's as if it is one character behind. What I mean by that is when the user hits the '1' key (in my 8+8=16 example), the console output is an empty string. When they hit the '6' key, the output is '1'. If they then hit another integer key, the output is '16'. It's always one digit behind. Because of this, I cannot capture the entire contents of the text field to see if it matches the correct answer.
Anyone see what I am missing?
Thanks!

Use a DocumentListener for that instead of a KeyListener. In all three events, you will have access to the actual text content.
To listen for the Enter on JTextField, us an ActionListener
Side note: you should almost never need a KeyListener. On JTextComponent, always rely on a DocumentListener. For all the others, use appropriate Swing Key bindings. KeyListener is really a low level API.

You should use DocumentListener for this purpose. keyPressed is probably fired before the text in the field is updated.
See How to Write a Document Listener for details and examples.

Related

How to ensure that a JTextField input meets requirements?

So I'm making a module that has three JTextField windows corresponding for 24 bit RGB color values "R", "G" and "B" with buttons for decrement/increment. The module is supposed to take these values and display the color. I did that and it works, but I need to ensure some details about the inputs and I don't know how to. These details are:
if you enter a value outside of 0 and 255 it will be treated as 0
if you click a decrement button when the value is 0 it won't drop it to -1
if you click an increment button when the value is 255 it won't rise to 256. I have no idea how to do it. I tried to google it but
I can't find what I need. I'd appreciate some guidance
EDIT:
I tried to add some if statements to the ActionPerformed method but all it does is returns a whole bunch of errors when I run the module and try the value out of range
EDIT2: for example, I had this but it doesn't work :
#Override
public void actionPerformed(ActionEvent e) {
String r,g,b;
if (e.getSource() == tf1) {
r = tf1.getText();
this.r =Integer.parseInt(r);
if (this.r < 0 && this.r > 255)
this.r =0;
color(); }
I have nothing for my buttons because I have completely no idea how to
This sounds like you might need some data validation from your input sources. We can't see your code, but one way to validate would be have your getters/setters generated for your variables. (Depending on the editor you have, these can be generated rather quickly). Within the values setter - you should be able to do some data validation.
If you post some code, you might get more meaningful feedback.
More on getters and setters in Java: https://www.codejava.net/coding/java-getter-and-setter-tutorial-from-basics-to-best-practices
EDIT:
Now that you've posted code. Change the && to || and that should take care of your issue.
It is still better to data validate this with a getter/setter.

Java getInputMap() for the enter key on numpad

So in my calculator program, I would like to set up the equals operation where it the mathematical problem could be computed by pressing the enter key (on the main keyboard) or by pressing the enter key (on the numpad). I know the numbers are VK_NUMPAD0 - VK_NUMPAD9, VK_ADD, VK_SUBTRACT, VK_MULTIPLY, VK_DIVIDE. However I can't seem to find one for the enter key. VK_ENTER is for the keyboards enter key. I also looked at KeyEvent.KEY_LOCATION_NUMPAD, but not sure how to add it to my code to get it to work. I have a method called SetupKeyInput() that takes some parameters that adds the key bindings for the inputmap and actionmap.
private void SetupKeyInput(JButton component, int keyStroke, int mask) {
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(keyStroke, mask), "hmm");
component.getActionMap().put("hmm", new MyButtonEvents(component));
}
So, I can call the function like this
SetupKeyInput(buttonEquals, KeyEvent.VK_ENTER, 0); // Only works for keyboard enter
What am i missing for the numpad enter? I also tried this
SetupKeyInput(buttonEquals, KeyEvent.VK_ENTER, KeyEvent.KEY_LOCATION_NUMPAD);

Java Swing: KeyBinding for KEY_TYPED event

I've been trying to learn keybinds by rewriting problems from my book that I've previously solved using KeyListener. The problem that I'm struggling to solve using keybinds requires me to record a message that's been typed and to display it on the panel.
The way it was solved using KeyListener is simply by recording characters with unicodes using the keyTyped() method and reading modifier/non-Unicode keys with keyPressed. If KeyEvent.VK_ENTER matches the keycode from the keyevent, then it displays the string on the panel.
~~~~~~~~
I thought that it can be solved in a similar way with KeyBinds. It says in the KeyEvent docs that KeyEvent.KEY_TYPED is fired every time a character is entered. I assumed that it meant every character with a corresponding Unicode being typed like how it works in KeyListener.
Later on, I realized that I have no idea how to retrieve the character since the Oracle tutorial on KeyBinds says that the KeyEvent is consumed when actionPerformed() is invoked.
This is the code that I THOUGHT would enable me to record typed keys to a StringBuilder using KeyBindings:
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.KEY_TYPED, 0), "recordTypedKey");
getActionMap().put("recordTypedKey", addCharToString);
Is there a way to obtain the characters that would invoke KeyListener's keyTyped() method besides adding a key to every one of them and using a separate Action event to record them?
Is there a way to obtain the characters that would invoke KeyListener's keyTyped() method besides adding a key to every one of them and using a separate Action event to record them?
I do not believe there is a global KeyStroke you can pass to the InputMap that will work similar to a KeyListener, as KeyBindings work on an individual key basis. You can however create a single Action and bind keys to it by looping over the char values you wish to process - in the ActionListener implementation you can obtain the value of the key via getActionCommand. For example to deal with a-z:
AbstractAction action = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
};
//loop over the ascii char values
for ( char a = 'A'; a <= 'Z'; a++ ){
panel.getInputMap().put(KeyStroke.getKeyStroke(Character.toString(a)), "recordTypedKey");
}
panel.getActionMap().put("recordTypedKey", action);
You can add modifiers if needed...for example to deal with the shift key (eg upper case),
panel.getInputMap().put(KeyStroke.getKeyStroke("shift " + Character.toString(a)), "recordTypedKey");

Key listener java - number limitation

I've got an app in JFrame. Here is part of the code:
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String input = text.getText();
int number = Integer.parseInt(text.getText());
if(number>0)
{
for(int i=0; i<liczba; i++)
{
new NewWindow();
}
}
}
});
This action creates new windows in app where number of windows depend on number we've inputted. I need to make sure it IS a number (not a letter or something). I also know the key listener must be used and the symbol inputted has to be between some values of ASCII which represent numbers. But I don't know how to do this exackly. Any solutions?
I also know the key listener must be used
No a KeyListener does not need to be used. That is probably the oldest solution and was used in AWT. Swing has newer and better API's which you should be using.
You could use a JSpinner, JFormattedTextField or a DocumentFilter.
Read the Swing Tutorial. You should check out sections on:
How to Use a Spinner
How to use Formatted Text Fields
How to Write a DocumentFilter
Any one of the above is a better solution than using a KeyListener.

Java KeyEvent confusion

I have a program which is a mock inventory system with quite a few JTextField's and some regular expressions which some of those fields must comply with. Also, some fields cannot be null(obviously) or an empty String. In order to assist the user to input data, I've added some ImageIcon's to show if the input data is valid or invalid. (a green check or red x) and I setVisibility() as the user types via KeyEvents.
With that said, here is the confusion. I have a block which I'm pretty sure doesn't have a bug in it, but I've found that there's some odd things happening:
I'm only calling my updateIcons() method in response to keyTyped() - my overrides for the others are empty. Now, when a key is typed, the text is printed on the screen before the key is released, so you would think that an input field that simply requires at least one character to NEVER fail the validity check because if keyTyped() is the only entry point to my updateIcons() method, there should always be at least one character by the time the key is released and thus registered as a "key typed". However, it seems to be firing an event before the key even gets registered to the System. Something which makes this even more odd is if I call my updateIcons() method twice in a row from the overridden keyTyped() method, the program STILL fails the check for empty string. BUT if I call it for keyPressed(), keyReleased(), and keyTyped() all for the same event, presto; valid data. Could this possibly be caused by the instability/bugginess of AWT?
Here is the updateIcons() method in case it is something I overlooked, but since I'm getting such odd results I don't think its a bug on my end.
//called from keyTyped
//formInputIcons is a 2D array[8][2] where the first dimension represents
//the form input field, and the second dimension is the ImageIcons for that field
//public final Pattern upcRegex = Pattern.compile("^\\d{12}$");
//public final Pattern anyNumRegex = Pattern.compile("^\\d+$");
public void updateIcons(KeyEvent e){
if(e.getSource() == formAddInputs[0]){
formInputIcons[0][0].setVisible( ! (upcRegex.matcher(
((JTextField)e.getSource()).getText()).matches()));
formInputIcons[0][1].setVisible(upcRegex.matcher(
((JTextField)e.getSource()).getText()).matches());
}else if(e.getSource() == formAddInputs[1]){
formInputIcons[1][0].setVisible(((JTextField)e.getSource()).getText().equals(""));
formInputIcons[1][1].setVisible( ! ((JTextField)e.getSource()).getText().equals(""));
}else if(e.getSource() == formAddInputs[3]){
formInputIcons[3][0].setVisible(((JTextField)e.getSource()).getText().equals(""));
formInputIcons[3][1].setVisible( ! ((JTextField)e.getSource()).getText().equals(""));
}else if(e.getSource() == formAddInputs[4]){
formInputIcons[4][0].setVisible(((JTextField)e.getSource()).getText().equals(""));
formInputIcons[4][1].setVisible( ! ((JTextField)e.getSource()).getText().equals(""));
}else if(e.getSource() == formAddInputs[6]){
formInputIcons[6][0].setVisible( ! (anyNumRegex.matcher(
((JTextField)e.getSource()).getText()).matches()));
formInputIcons[6][1].setVisible(anyNumRegex.matcher(
((JTextField)e.getSource()).getText()).matches());
}else if(e.getSource() == formAddInputs[7]){
formInputIcons[7][0].setVisible( ! (anyNumRegex.matcher(
((JTextField)e.getSource()).getText()).matches()));
formInputIcons[7][1].setVisible(anyNumRegex.matcher(
((JTextField)e.getSource()).getText()).matches());
}
}
UPDATE: I'm an idiot - it works fine if I only call updateIcons() once from keyReleased() and leave keyPressed() and keyTyped() empty. I like to learn things though; could someone explain why keyTyped() is buggy in this usage but keyReleased() works fine or post a link please?
You need to be calling your update method from keyReleased(). I've made a simple JTextField which outputs the key and its getText() each time a key is pressed, and watch what happens:
keyPressed:c
text:
keyTyped:c
text:
keyReleased:c
text:c
keyPressed:a
text:c
keyTyped:a
text:c
keyReleased:a
text:ca
keyPressed:t
text:ca
keyTyped:t
text:ca
keyReleased:t
text:cat
You can see that the actual text of the JTextField is not updated by the keyTyped() or keyPressed() events.

Categories

Resources