Java KeyEvent confusion - java

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.

Related

Java - Selenium WebDriver - Not executing IF/ELSE statements when conditions appear to have been met

I've read through several questions/answers with similar sounding issues but I've not found a solution to my issue and have been racking my brain over this for the last few hours so here goes.
On the web form I'm writing tests for, there are several drop down lists and if the option "Don't know" is selected from any of them, a check box will be displayed and needs to be selected or the form cannot be submitted.
I'm storing the selected values as Strings and then have the clicking of the check box within an IF statement checking whether any of those drop down values is "Dont know" (the actual value in the drop down is recorded as "Dont know"):
String drpdwn_WAN = driver.findElement(By.id("idontknow4")).getAttribute("value");
String drpdwn_SFTPAuthMethod = driver.findElement(By.id("idontknow5")).getAttribute("value");
String drpdwn_SFTPCreds = driver.findElement(By.id("idontknow6")).getAttribute("value");
String drpdwn_Bandwidth = driver.findElement(By.id("idontknow7")).getAttribute("value");
String drpdwn_Data = driver.findElement(By.id("idontknow8")).getAttribute("value");
//click on the Understood check box (only appears when 'Don't know' option is selected)
if(drpdwn_WAN == "Dont know" || drpdwn_SFTPAuthMethod == "Dont know" || drpdwn_SFTPCreds == "Dont know" || drpdwn_Bandwidth == "Dont know" || drpdwn_Data == "Dont know"){
driver.findElement(By.name("understand")).click();
}
I've run through the code in debug mode and have confirmed that the drop down values are being correctly stored but even when at least one of the drop down values is "Dont know" it will not run the code within the IF statement and instead just ignore it.
I've written my test so that the options selected from the drop downs are randomised so need a lot of conditional logic to verify other elements on the page such as the check box. As such the above is only one example of the types of IF/ELSE statement I have in my code but it seems that all code contained within any IF/ELSE statements is not getting executed and is instead being ignored and passed over. Can anyone explain to me what it is that I'm doing wrong here and why the IF statements are seemingly not being executed?
This is the first time I've posted on here so apologies if any of the information is lacking or not clear. Also apologies if the solution to this is rather simple but I'm new to the world of Java development.
Thanks in advance for any help offered!
Having read stackoverflow.com/questions/513832/ it appears that I should have been using .equals() instead of == for string comparisons. Code worked as expected once I replaced == with .equals()
if(drpdwn_WAN.equals("Dont know") || drpdwn_SFTPAuthMethod.equals("Dont know") || drpdwn_SFTPCreds.equals("Dont know") || drpdwn_Bandwidth.equals("Dont know") || drpdwn_Data.equals("Dont know")){
driver.findElement(By.name("understand")).click();
}

JTextArea admin password control

Very new and inexperienced coder, I'm currently working on my first 'from - scratch' project which will be a simple POS (Point Of Sale) restaurant till application.
The till has an admin panel which allows the user to change the menu presets and prices and will require a password to access it.
I am sloppy and using a lot imports as I am as I said very new.
Please take a look at the following:
if (source == passwordSubmit){
if (logInPassword.getText() == adminPassword){
loginFrame.setVisible(false);
adminFrame.setVisible(true);
}
else logInPassword.append("Incorrect");
}
That code is within my ActionListener handler which lets the user enter text into the JTextArea called logInPassword and it compares the user text with the adminPassword preset string (currently set to Password as default)
But my code doesn't quite work... It's active as it gives me an "Incorrect" append into the logInPassword JTextArea but I'm typing in the correct password.
Do I need a getter or something?
Not sure what I'm missing.
use .equals()
if (source == passwordSubmit){
if (logInPassword.getText().equals(adminPassword){
loginFrame.setVisible(false);
adminFrame.setVisible(true);
}
else logInPassword.append("Incorrect");
}
When you use the == operator in Java, you are just comparing shallow reference values. The line source == passwordSubmit would work (since both should refer to the same object). However with strings, it is possible to have two string objects that equal the same in value. In that case, you have to do logInPassword.getText().equals(adminPassword) instead of logInPassword.getText() == adminPassword. The equals method compares by value of the strings.

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

Checking JTextField Characters

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.

A Question about JTextField in Java

I met a small problem when running a Java class that I wrote, though the design is pretty straightforward. I've created a JPanel, and I've added four JTextFields onto it and I've attached a button to this JPanel, too. Then, I've associated an ActionListener to this button being pressed. The code is like:
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
if (imageIdField.getText() == "" &&
captionField.getText() == "" &&
creditField.getText() == "" &&
titleField.getText()== "")
{
mediaXML = "";
results.clear();
results.put("error1", "more");
}
else
{ ....
}
}
The strange thing is after I've pressed the OK button, and I did input text in those four JTextFields, still it will fall in the IF branch as if I didn't input any text in any of these four fields.
I've been debugging this for a while, but no clue. Could anyone give me some hint like whether .getText() == "" is a valid way for testing no input?
Thanks in advance!
As has been mentioned, using == is not correct. For readability, try:
field.getText().isEmpty()
or
field.getText().trim().isEmpty()
Generally a bad idea to use == on Strings, or most other things. It checks that the objects are exactly the same instance, not that they have the same value. "" != new String("").
field.getText().equals("")
Or possibly better:
field.getText().isEmpty()
Use getText().equals("") instead of ==
Use == to check if it is the same object in memory, and .equals("YOUR STRING") to check if the content of the object is the same.
You should use .equals. Also, you might want to do something like this:
imageField.getText().trim().length() == 0 //The same for the others
or
imageField.getText().trim().isEmpty() //The same for the others
if you want to make sure that the user has actually written some characters instead of just white spaces.
== only checks whether the left hand side and the right hand side refer to the exact same instance of an object. And since "" translates to something like new String(""), it will always return false, if you compare it with a string that already exists.
If you want to compare whether two instances of a class have the same state you need to use equals(). In your case *.getText().equals(""). A more elegant method would to use the isEmpty() method of the String class.

Categories

Resources