JavaFX stop KeyEvent after getting only one alpha numeric character - java

I am new to Java and am having trouble on getting some code working. I have a GUI with the letters A-Z. After a button click, I want to ask for a Keyevent to do a couple of things:
Only allow you to select a letter. Upper or lower case. If not wait for a response that is correct.
Then check the alphabet list to see if it has been pressed before. If it has then ask for another letter
If a new character is entered then strike it out on the alphabet and run the method that follows
Disable any further keys being pressed.
I have tried the following code:
private static void spinGame(){
switch (wheelResult)
{
case "1'
...
break;
case "2":
...
break;
default:
System.out.println("...");
newPhrase.gameB();
scene2.setOnKeyPressed((KeyEvent event) -> {
if (event.getText().isEmpty())
return;
char pressed = event.getText().toUpperCase().charAt(0);
userGuess=event.getText().charAt(0);
if ((pressed < 'A' || pressed > 'Z'))
return;
Text t = alphabet.get(pressed);
if (t.isStrikethrough())
return;
// mark the letter 'used'
else{t.setFill(Color.BLUE);
t.setStrikethrough(true);
System.out.println(userGuess);
}
int letterCount;
if ((userGuess == 'a') || (userGuess == 'e') || (userGuess == 'i') || (userGuess == 'o') || (userGuess == 'u')){
playerScores[currentPlayer] -= 250;
System.out.println("£250 docked from score for vowel use");
}
It goes wrong from here. I dont want keys to be pressed again and I don't the following method should run:
letterCount = newPhrase.makeGuess(userGuess);
...my method....;
})
I have no idea how to fix it. I tested and recorded the User guess is being selected but it does not proceed the method after and the key in input doesn't stop. I also feel that my coding for the alphanumeric stuff is wrong.

Your solution already caters for your requirements as you check for a valid letter and whether or not it is strike-through in your alphabet. So until they provide an unused letter, nothing will happen aside from the conditions being checked each time
To stop the key input I'd recommend using a ToggleButton or something similar so the user has to indicate when they want to guess. This means you can use other text based controls with a decreased probability of striking off letters in your alphabet accidentally. When they guess an unused letter you can reset the button, otherwise keep checking their input for a valid letter
Your method relating to the scoring system is only called when a vowel has been entered by the user. You can separate the score and input logic by creating a method and only providing valid unused letters to it, handling the game's scoring/phrase lookup logic there:
private void checkPhrase(char chosenLetter){
//Handle the Hangman-like logic here
boolean isVowel = vowels.indexOf(chosenLetter) >= 0;
if (isVowel) {
System.out.println("User provided a vowel");
}
}
This will make it easier to read and maintain your code as once you've determined that the letter hasn't been used you will only need to call it once. Whereas before you might have had duplication as it looks like it was only been executed for vowels
Below are the changes I made to your code when testing in case they are of use:
public class AlphabetGuess extends Application {
private String vowels = "AEIOU";
#Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Text> alphabet = FXCollections.observableArrayList();
for(char letter = 'A'; letter <= 'Z'; letter++){
alphabet.add(new Text(String.valueOf(letter)));
}
HBox alphabetContainer = new HBox(5);
alphabetContainer.setAlignment(Pos.CENTER);
alphabetContainer.getChildren().addAll(alphabet);
ToggleButton button = new ToggleButton("Listen for guess");
button.setSelected(false);
VBox root = new VBox(20, alphabetContainer, button);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 500, 100);
scene.setOnKeyPressed(event -> {
//If the button isn't selected, don't process the input
if (event.getText().isEmpty() || !button.isSelected()) {
return;
}
char userGuess = event.getText().toUpperCase().charAt(0);
if ((userGuess < 'A' || userGuess > 'Z')) {
return;
}
//This will cause letters A-Z to become 0-25 allowing the list to be indexed
Text text = alphabet.get(userGuess - 'A');
if (text.isStrikethrough()) {
System.out.println(userGuess + " has already been guessed");
return;
} else {
text.setFill(Color.BLUE);
text.setStrikethrough(true);
checkPhrase(userGuess);
}
//Un-select button which will cause this event to reject incoming keys
button.setSelected(false);
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void checkPhrase(char chosenLetter){
//Handle the Hangman-like logic here
boolean isVowel = vowels.indexOf(chosenLetter) >= 0;
if (isVowel) {
System.out.println("User provided a vowel");
}
//ToDo: Implement
}
}

Related

Checking which button user pressed and checking the button text

I am a noob in Java and programing and I am making an app where the user is trying to guess a city based on a picture. The user sees a picture of the city and has three buttons under the picture with different answers in them. The pictures are randomized from an array and the buttons text changes so that atleast one of the buttons has the correct answer. I want a TextView with "correct" to show if user is correct and one with "incorrect" to show if user is wrong. The text is showing up when pressing any button and not when the button with the correct text is pressed. So this is what I have tried and am stuck on. And yes I know I have many mistakes in my code, such as names of methods and so. I will change these later.
I have three booleans that are set to false, they are representing which button is pressed. You will understand more later.
Boolean test1 = false;
Boolean test2 = false;
Boolean test3 = false;
In main i have three buttons and they all call on the checkanswer function. Also they all turn their own boolean to true there, which u will se why soon. Example of one of the buttons.
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
test1 = true;
checkanswer();
}
});
So here is the checkanswer function
public void checkanswer() {
DisplayRandomImage();
//Giving three strings random city names from the "cities" array.
Random rndBtnTxt = new Random();
String randomCity1 = cities[rndBtnTxt.nextInt(cities.length)];
String randomCity2 = cities[rndBtnTxt.nextInt(cities.length)];
String randomCity3 = cities[rndBtnTxt.nextInt(cities.length)];
//Setting the random city names to the three different buttons.
btn1.setText(randomCity1);
btn2.setText(randomCity2);
btn3.setText(randomCity3);
//takes the picked image from the "DisplayRandomImage" method.
String str = String.valueOf(pickedImg);
//Tells what to call the different pictures, they are known as numbers make sure they are given names instead.
if (pickedImg == 0)
str = "venice";
if (pickedImg == 1)
str = "new york";
//If-statement checking so that atleast one button has the correct answer.
if (randomCity1 != str || randomCity2 != str || randomCity3 != str) {
Random rndbtn = new Random();
Button x = btnArray.get(rndbtn.nextInt(btnArray.size()));
//Sets one of the three buttons so that it has the correct answer.
x.setText(str);
}
//See where the correct answer is
String buttonText1 = btn1.getText().toString();
String buttonText2 = btn2.getText().toString();
String buttonText3 = btn3.getText().toString();
//check if the button that the user pressed has the correct answer
if (test1.equals(true) && buttonText1.equals(str)){
CorrectAnswer();
test1 = false;
}
if (test2.equals(true) && buttonText2.equals(str)){
CorrectAnswer();
test2 = false;
}
if (test3.equals(true) && buttonText3.equals(str)){
CorrectAnswer();
test3 = false;
}
else
WrongAnswer();
}
I am not sure what I am doing wrong here. For example the "test1" is set to True when I press "btn1" and if "buttontext1" equals to the same as "str" does it should work. But for some reason it seems randomised which of the three buttons calls for the CorrectAnswer method. What am I doing wrong here?
Can we see CorrectAnswer? Also,
right off the bat, I noticed that instead of using test1, test2 and test3 to indicate which button was pressed, you can just pass some sort of argument into checkAnswer, like int button.
So onClick would look like this for the first button, and subsequent buttons by incrementing the 1:
public void onClick(View v) {
checkanswer(1);
}
and checkanswer would look like this:
public void checkanswer(int button) {
... (previous stuff) ...
//check if the button that the user pressed has the correct answer
if (button == 1 && buttonText1.equals(str)){
CorrectAnswer();
}
if (button == 2 && buttonText2.equals(str)){
CorrectAnswer();
}
if (button == 3 && buttonText3.equals(str)){
CorrectAnswer();
}
else
WrongAnswer();
}
So try this out.
Its pretty hard to tell where the bug is, if you only show us pieces of the full code.
Mistakes could be e.g. in CorrectAnswer()...
I would recommend binding onlick-listeners to your buttons instead of changing booleans.
Check this out here: https://developer.android.com/reference/android/widget/Button
Additionally I noticed another mistake:
randomCity1 != str || randomCity2 != str || randomCity3 != str
This will return true if at least one of the Strings does not contain the right answer
You probably want to enter the if-Statement, when there isnt already a button with the correct answer.This is what you would like to use:
randomCity1 != str && randomCity2 != str && randomCity3 != str
EDIT: Check out the answer of Barcode for another example of using onClicklisteners.
Thank you both for answering the question, i have found a way to complete this problem:
public void testingMethod(int button){
switch(button){
case 1:
if (buttonText1 == str)
CorrectAnswer();
else
WrongAnswer();
break;
case 2:
if (buttonText2 == str)
CorrectAnswer();
else
WrongAnswer();
break;
case 3:
if (buttonText3 == str)
CorrectAnswer();
else
WrongAnswer();
break;
}
}
And since you were wondering how the method CorrectAnswer looked like here it is, yes I know it's probably unnecessary having this method but I am noob after all.
public void CorrectAnswer() {
findViewById(R.id.txtIncorrect).setVisibility(View.GONE);
findViewById(R.id.txtCorrect).setVisibility(View.VISIBLE);
}

Keymap Spacebar to Enter Key action in Java

I am trying to make it so that instead of hitting the enter key in my java program to make the enter action occur, I can instead hit the enter key while a custom method is running. At this point, I have looked into Hashmaps but am pretty confused if this going to do what I want. Any help would be greatly appreciated. It seems like this should be an easy thing to do, but for some reason I am just not getting a solution to it.
So, I am thinking my code will be something like this. Essentially, I am making a game of Hot Potato and I need to have the players take turn entering a character (e, d, and c for team 1 and o, k, and n for team 2). This will be involving a GUI interface as well. A have a while loop that will end once a timer reaches zero. What I would like is for the players to be able to put in a letter into a JTextField in the GUI and then simply press spacebar (as they will be sharing a keyboard). Once they enter the right letter (I made it randomized), they can hit spacebar and they will have "tossed the potato" to the other player.
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
KeyEvent.VK_ENTER;
}
}
I am working all of this out of the actionPerformed(ActionEvent ev) method. The fuller code looks like this. The if statement is commented out because I would like the game to start when the main button is pressed, but right now I get a ton of compilation errors when I uncomment the JButton and have it working with the String text that is the dialogue from the text you enter into a JTextField.
public void actionPerformed(ActionEvent ev) {
Object eventSource = ev.getSource();
String text = entryText.getText(); // text entered into JText
//JButton eventButton = (JButton) eventSource;
System.out.println(text);
//if (eventButton.equals(main))
{
int totalTime = 1000*(HotPotato.randNum());
long startTime = System.currentTimeMillis();
System.out.println(totalTime/1000);
Boolean p1Start = false;
String input = "";
while (System.currentTimeMillis() - startTime <= totalTime)
{
p1Start = !p1Start;
char a = HotPotato.randLetterBoth(p1Start);
String aString = String.valueOf(a);
while (!input.equals(aString))
{
System.out.print(aString); // temporary, shows test letter
input = theKeyboard.next();
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
KeyEvent.VK_ENTER;
}
}
}
}
if (p1Start)
{
System.out.print("Team 2 Wins!");
}
else
{
System.out.print("Team 1 Wins!");
}
setLabels();
myPicture.makeHotPotatoOn(myHotPotato.state());
myPicture.repaint();
}
}

Inconsistency calling TextField text in setOnKeyTyped

I am making a typing test in Java with JavaFX. I want to compare the text that is being typed in a TextField to the defined random words. However, the TextField only updates with the letter just typed sometimes and not all the times. The following code is where this problem is occurring.
field.setOnKeyTyped(e -> {
String typingWord = field.getText();
if( typingWord.isEmpty() &&
e.getCharacter().charAt(0) == '\b' &&
!(typedWords.size() == 0) &&
typingWord.equals(previousWord)){
field.setText(typedWords.get(typedWords.size() - 1));
typedWords.remove(typedWords.size() - 1);
field.positionCaret(typingWord.length());
index--;
}
//compare random words to typed words
if (Character.isWhitespace(e.getCharacter().charAt(0))) {
typedWords.set(index, typingWord);
field.clear();
e.consume();
index++;
}
previousWord = field.getText();
});
Is this purely due to the speed of my computer or is it just a bug in JavaFX?
Sir i do not know what you want to do but i want to help, so in your onKeyPressed() or onKeyReleased(), it gives a KeyEvent that is e in your case, you can use that in place of Character.isWhitespace() & e.getCharacter().charAt(0) and also /b
To get your KeyCode
field.setOnKeyTyped(e -> {
KeyCode kc = e.getCode(); // your keycode here is the character you just pressed
now with the KeyCode you can check for a whole lot of goodies,without falling to character
equality checks
if(kc == KeyCode.BACK_SPACE) //checking for your backspace
if(kc.isWhitespaceKey()) // your enter, tabs, space etc
also you can make use of these methods
TextField.deletePreviousChar();,TextField.deleteNextChar(); that might save you all the selection before clearing. if you want to clear like 10 of them then loop it 10 times
lastly why do you check for emptiness & later check if its not empty

Trouble with creating Battleship using Java

The following block of code is supposed to check if the coordinates that the user entered are the coordinates of the ship. The ship is located on a two dimensional array at (1,1) and (1,2).
The problem started when I surrounded the getUserGuess method implementation with a while loop. The loop checks if the ship is still alive and will keep asking for the user to enter coordinates until the ship is sunk. However, as soon as the user enters either pair of the correct coordinates, the entire ship is sunk.
I have no idea why this keeps happening. As soon as I comment out the loop, the problem stops, but the loop is necessary.
Here is the method:
public void checkResult(String userGuess) {
while (frigateIsAlive == true) {
if (userGuess.equalsIgnoreCase(board[1][1])){
System.out.println("hit!");
numOfHitsOnFrigate++;
board[1][1] = " *";
createBoard();
}
if (userGuess.equalsIgnoreCase(board[1][2])) {
System.out.println("hit!");
numOfHitsOnFrigate++;
board[1][2] = " *";
createBoard();
}
else if (numOfHitsOnFrigate == 2) {
System.out.println("Enemy frigate has been sunk!");
frigateIsAlive = false;
break;
}
else {
System.out.println("miss!");
// try again
}
}
}
public String getUserGuess()
{ // takes the users guess
System.out.println("Choose a coordinate on the board to fire at");
int x = input.nextInt();
int y = input.nextInt();
String userGuess = board[x][y];
return userGuess;
}
Let me know if you need to see any other part of the code in order to better assist me.
This method is flawed :
If userGuess matches board[1][1], the loop will make you increment numOfHitsOnFrigate twice, and then you'll change frigateIsAlive to false and exit.
If userGuess matches board[1][2], the loop will make you increment numOfHitsOnFrigate infinite times and you'll never exit.
If userGuess doesn't match, the loop will never terminate, and keep printing miss! without getting new input.
You need to remove the loop, since this method checks a single userGuess, and change the conditions :
public void checkResult(String userGuess) {
if (userGuess.equalsIgnoreCase(board[1][1])){
System.out.println("hit!");
numOfHitsOnFrigate++;
board[1][1] = " *";
createBoard();
} else if (userGuess.equalsIgnoreCase(board[1][2])) {
System.out.println("hit!");
numOfHitsOnFrigate++;
board[1][2] = " *";
createBoard();
} else {
System.out.println("miss!");
// try again
}
if (numOfHitsOnFrigate == 2) {
System.out.println("Enemy frigate has been sunk!");
frigateIsAlive = false;
}
}
Based on what you wrote - I surrounded the getUserGuess method implementation with a while loop. - you have another loop which keeps getting input from the user. That other loop, whose code you haven't shown us, is necessary, since without it the game won't progress.
What you probably want (pseudo-code):
start (of a loop)
ask user for a guess
check result for the guess
sunk => stop / not sunk => continue to start
(i.e. you misplaced your while loop)

Ignoring focusLost(), SWT.Verify, or other SWT listeners in Java code

Outside of the actual SWT listener, is there any way to ignore a listener via code?
For example, I have a java program that implements SWT Text Widgets, and the widgets have:
SWT.Verify listeners to filter out unwanted text input.
ModifyListeners to wait for the correct number of valid input characters and automatically set focus (using setFocus())to the next valid field, skipping the other text widgets in the tab order.
focusLost(FocusEvent) FocusListeners that wait for the loss of focus from the text widget to perform additional input verification and execute an SQL query based on the user input.
The issue I run into is clearing the text widgets. One of the widgets has the format "####-##" (Four Numbers, a hyphen, then two numbers) and I have implemented this listener, which is a modified version of SWT Snippet Snippet179. The initial text for this text widget is " - " to provide visual feedback to the user as to the expected format. Only numbers are acceptable input, and the program automatically skips past the hyphen at the appropriate point.
/*
* This listener was adapted from the "verify input in a template (YYYY/MM/DD)" SWT Code
* Snippet (also known as Snippet179), from the Snippets page of the SWT Project.
* SWT Code Snippets can be found at:
* http://www.eclipse.org/swt/snippets/
*/
textBox.addListener(SWT.Verify, new Listener()
{
boolean ignore;
public void handleEvent(Event e)
{
if (ignore) return;
e.doit = false;
StringBuffer buffer = new StringBuffer(e.text);
char[] chars = new char[buffer.length()];
buffer.getChars(0, chars.length, chars, 0);
if (e.character == '\b')
{
for (int i = e.start; i < e.end; i++)
{
switch (i)
{
case 0: /* [x]xxx-xx */
case 1: /* x[x]xx-xx */
case 2: /* xx[x]x-xx */
case 3: /* xxx[x]-xx */
case 5: /* xxxx-[x]x */
case 6: /* xxxx-x[x] */
{
buffer.append(' ');
break;
}
case 4: /* xxxx[-]xx */
{
buffer.append('-');
break;
}
default:
return;
}
}
textBox.setSelection(e.start, e.start + buffer.length());
ignore = true;
textBox.insert(buffer.toString());
ignore = false;
textBox.setSelection(e.start, e.start);
return;
}
int start = e.start;
if (start > 6) return;
int index = 0;
for (int i = 0; i < chars.length; i++)
{
if (start + index == 4)
{
if (chars[i] == '-')
{
index++;
continue;
}
buffer.insert(index++, '-');
}
if (chars[i] < '0' || '9' < chars[i]) return;
index++;
}
String newText = buffer.toString();
int length = newText.length();
textBox.setSelection(e.start, e.start + length);
ignore = true;
textBox.insert(newText);
ignore = false;
/*
* After a valid key press, verifying if the input is completed
* and passing the cursor to the next text box.
*/
if (7 == textBox.getCaretPosition())
{
/*
* Attempting to change the text after receiving a known valid input that has no results (0000-00).
*/
if ("0000-00".equals(textBox.getText()))
{
// "0000-00" is the special "Erase Me" code for these text boxes.
ignore = true;
textBox.setText(" - ");
ignore = false;
}
// Changing focus to a different textBox by using "setFocus()" method.
differentTextBox.setFocus();
}
}
}
);
As you can see, the only method I've figured out to clear this text widget from a different point in the code is by assigning "0000-00"
textBox.setText("000000")
and checking for that input in the listener. When that input is received, the listener changes the text back to " - " (four spaces, a hyphen, then two spaces).
There is also a focusLost Listener that parses this text widget for spaces, then in order to avoid unnecessary SQL queries, it clears/resets all fields if the input is invalid (i.e contains spaces).
// Adding focus listener to textBox to wait for loss of focus to perform SQL statement.
textBox.addFocusListener(new FocusAdapter()
{
#Override
public void focusLost(FocusEvent evt)
{
// Get the contents of otherTextBox and textBox. (otherTextBox must be <= textBox)
String boxFour = otherTextBox.getText();
String boxFive = textBox.getText();
// If either text box has spaces in it, don't perform the search.
if (boxFour.contains(" ") || boxFive.contains(" "))
{
// Don't perform SQL statements. Debug statement.
System.out.println("Tray Position input contains spaces. Ignoring.");
//Make all previous results invisible, if any.
labels.setVisible(false);
differentTextBox.setText("");
labelResults.setVisible(false);
}
else
{
//... Perform SQL statement ...
}
}
}
);
OK. Often, I use SWT MessageBox widgets in this code to communicate to the user, or wish to change the text widgets back to an empty state after verifying the input. The problem is that messageboxes seem to create a focusLost event, and using the .setText(string) method is subject to SWT.Verify listeners that are present on the text widget.
Any suggestions as to selectively ignoring these listeners in code, but keeping them present for all other user input?
Thank you in advance for your assistance.
If you name the listener instead of using an anonymous one, you can add and remove it whenever you like.
Example:
// Adding focus listener to textBox to wait for loss of focus to perform SQL statement.
FocusAdapter focusTextBox = new FocusAdapter()
{
#Override
public void focusLost(FocusEvent evt)
{
// Get the contents of otherTextBox and textBox. (otherTextBox must be <= textBox)
String boxFour = otherTextBox.getText();
String boxFive = textBox.getText();
// If either text box has spaces in it, don't perform the search.
if (boxFour.contains(" ") || boxFive.contains(" "))
{
// Don't perform SQL statements. Debug statement.
System.out.println("Tray Position input contains spaces. Ignoring.");
//Make all previous results invisible, if any.
labels.setVisible(false);
differentTextBox.setText("");
labelResults.setVisible(false);
}
else
{
//... Perform SQL statement ...
}
}
};
You can then add the listener by doing this:
textBox.addFocusListener(focusTextBox);
Removal is as easy as this:
textBox.removeFocusListener(focusTextBox);
Just make sure to re-enable the listener after you've done what you've wanted to programmatically achieve, or your code will not act like you'd expect.
I didn't tested your code, but try method isFocusControl() in the listener to see if the user enters the text or you set the text with setText() when the focus is not in textBox.

Categories