I believe I have encountered a bug within the JavaFX API, but I'm not sure. So the following snippet behaves normally, but when I add an alert.show(); or alert.showAndWait();, the program opens three different alert dialogues. Here's the code:
private void datePickerOnHiding(JFXDatePicker datePicker, JFXCheckBox chkBox) {
int counter = 0;
boolean entered = false;
if (datePicker.getValue().isBefore(LocalDate.now()) ||datePicker.getValue().isEqual(LocalDate.now())) {
if ((eventHiddenCounter % 2) == 0) {
System.out.println("HAHA");//Testing
txtfMessage.setVisible(true);
txtfMessage.setText("Please select a future date.");
Alert alert = new Alert(AlertType.WARNING, "Please select a future date.");
alert.showAndWait();
datePicker.setValue(null);
counter ++;
entered = true;
}
} else {
txtfMessage.setVisible(false);
chkBox.setSelected(true);
}
//Testing
System.out.println("" + eventHiddenCounter + ": " + ((eventHiddenCounter % 2) == 0));
System.out.println("COUNTER: " + counter + "\nENTERED: " + entered);
entered = false;
eventHiddenCounter ++;
}
Here's the ouput with the alert.showAndWait commented out:
HAHA
0: true
COUNTER: 1
ENTERED: true
Here it is with it included (the bug):
HAHA
HAHA
HAHA
0: true
COUNTER: 1
ENTERED: true
1: false
COUNTER: 1
ENTERED: true
2: true
COUNTER: 1
ENTERED: true
I am quite perplexed--why is this happening, and what can I do to get around it?
By the way, the goal is to prevent the user from picking a date equal to or before the current day.
The date picker creates a popup and your alert is also a popup window.
The most likely reason (I can't be sure because I have no idea how datePickerOnHiding() is being called) is that the two popups are having race condition. When you try to show the alert, you are triggering the datePickerOnHiding() because it is trying to hide again.
If you want to stop user from selecting invalid values, you need to trigger this method after the datepicker popup is already closed (i.e. hidden).
Jai's answer is helpful, but I just disabled the days I didn't want using DayCells.
See:
http://o7planning.org/en/11085/javafx-datepicker-tutorial
javafx datepicker how to customize
I used the first one.
Edit: I figured out what was causing the repetition.
The focus shifts in the scene after the Alert dialogue is closed in the closing event listener. I have a similar (read: same) dialogue for a focus-lost listener (they fire under the same conditions), so the dialogues appeared to be the same, despite having different origins. Essentially, the focus kept oscillating to and from the node with the focus listener, causing numerous Alert popups for one error.
I realized my mistake after changing the AlertType of the closing listener Alert.
Simple fix - I made an externalRequest boolean flag, and I changed the focusListener event handler to do nothing if the externalRequest flag was true. Worked like a charm.
Related
I've decided to programm a search system for finding students and teachers in a school via GUI. It is an OOP and need some tweaking here and there, but there is one issue which doesn't seem logical to me. When I'm searching for a teacher, I have to type there name or surname into a JTextField and press the Search button which runs a method that loops through an ArrayList of teacher-objects and checks if their names match with the one in the Textfield. Then it checks if these teachers have multiple subjects and grades and it goes through nested if-statements. After the teacher is found, their information is displayed on a GUI with several Texfields. Theoretically if the name I typed into the TextField doesn't match one from the teacher objects, a Error Message should pop-up saying the teacher I'm looking for isn't in the system. But even though I type in the correct name and get all the information displayed, it sends me to the Error Message everytime. I tried to fix it with a break statement but that didn't work either. Can someone please help me with this.
Here is the code I'm talking about:
public void lehrerSuche()
{
String lehrername = tfSuchfeldLehrer.getText();
for(int i = 0; i < td.getFachliste(0).getListenLaengeLehrerListe();i++)
{
if(td.getFachliste(0).getLehrerliste(i).getName().equals(lehrername) || td.getFachliste(0).getLehrerliste(i).getNachname().equals(lehrername))
{
if(td.getFachliste(0).getLehrerliste(i).isMehrerefaecher() && td.getFachliste(0).getLehrerliste(i).isMehrereklassen())
{
tfNameLehrer.setText(td.getFachliste(0).getLehrerliste(i).getName() + " " + td.getFachliste(0).getLehrerliste(i).getNachname());
tfKürzelLehrer.setText(td.getFachliste(0).getLehrerliste(i).getKuerzel() + ".");
tfKlasse_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getKlasse().getBezeichnung());
tfKlasse_2Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getKlass2().getBezeichnung());
tfFach_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getFach().getFachbezeichnung());
tfFach_2Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getFach2().getFachbezeichnung());
}
if(td.getFachliste(0).getLehrerliste(i).isMehrerefaecher() == false && td.getFachliste(0).getLehrerliste(i).isMehrereklassen())
{
tfNameLehrer.setText(td.getFachliste(0).getLehrerliste(i).getName() + " " + td.getFachliste(0).getLehrerliste(i).getNachname());
tfKürzelLehrer.setText(td.getFachliste(0).getLehrerliste(i).getKuerzel() + ".");
tfKlasse_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getKlasse().getBezeichnung());
tfKlasse_2Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getKlass2().getBezeichnung());
tfFach_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getFach().getFachbezeichnung());
}
if(td.getFachliste(0).getLehrerliste(i).isMehrerefaecher() && td.getFachliste(0).getLehrerliste(i).isMehrereklassen()==false)
{
tfNameLehrer.setText(td.getFachliste(0).getLehrerliste(i).getName() + " " + td.getFachliste(0).getLehrerliste(i).getNachname());
tfKürzelLehrer.setText(td.getFachliste(0).getLehrerliste(i).getKuerzel() + ".");
tfKlasse_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getKlasse().getBezeichnung());
tfFach_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getFach().getFachbezeichnung());
tfFach_2Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getFach2().getFachbezeichnung());
}
if(td.getFachliste(0).getLehrerliste(i).isMehrerefaecher() == false && td.getFachliste(0).getLehrerliste(i).isMehrereklassen()==false)
{
tfNameLehrer.setText(td.getFachliste(0).getLehrerliste(i).getName() + " " + td.getFachliste(0).getLehrerliste(i).getNachname());
tfKürzelLehrer.setText(td.getFachliste(0).getLehrerliste(i).getKuerzel() + ".");
tfKlasse_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getKlasse().getBezeichnung());
tfFach_1Lehrer.setText(td.getFachliste(0).getLehrerliste(i).getFach().getFachbezeichnung());
}
break;
}
else
{
switchPanels_3(panelErrorLehrer);
}
}
}
I've uploaded my project to GitHub. Methods and variables are written in German, so I'm really sorry if you can't understand what I have written. If u have questions please hit me up. I use Eclipse to code.
This link should direct you to my GitHub:
https://github.com/Gonzo-CR/Home-Projects.git
If the link doesn't work, look for Gonzo-CR on GitHub and check out my Home-projects repository where I uploaded all the files.
For better undestanding these are the Object oriented classes:
Person(Abstract)
Schueler
Lehrer
Fach
Schulklasse
Spezial
Sprecher
GUI classes:
Suchsystem
Testdaten(A class which generates all my objects)
The problem is likely that if td.getFachliste(0).getLehrerliste(i).getName().equals(lehrername) is not true the very first time the loop runs, switchPanels_3(panelErrorLehrer); will be triggered - regardless of whether the condition is met on a later iteration of the loop.
What you need is to check a sentinel value after the loop finishes - e.g.:
bool lehrerGefunden = false;
for(int i = 0; i < td.getFachliste(0).getListenLaengeLehrerListe();i++){
if(td.getFachliste(0).getLehrerliste(i).getName().equals(lehrername) || td.getFachliste(0).getLehrerliste(i).getNachname().equals(lehrername)){
//etc.
lehrerGefunden = true;
break;
}
}
if(!lehrerGefunden){
switchPanels_3(panelErrorLehrer);
}
That way, you check every entry in the list before deciding whether to show the error.
I am building a simple game of 21. Everything comes together okay, but when I click on the Button that I have assigned to my 'Stand' function, none of the if-statement blocks trigger event though I am meeting conditions of one or the other depending on what cards have already been dealt. I have tested all variations of the statements and I want to have some insight, or a second pair of eyes to see something I do not.
I have tested the function multiple times, and re-written it multiple times. I've tested the function with just that statement present, and it still does not trigger.
This is the function in question:
//when player hits stand button
public void Stand(TextField playerNum, TextField dealerNum, TilePane b, Button hit, Button stand, Button deal, TextField handsLostNum, TextField handsWonNum) {
//obtain current final scores when player stands
playerFinal = Integer.parseInt(playerNum.getText());
dealerFinal = Integer.parseInt(dealerNum.getText());
if (playerFinal > dealerFinal) {
hit.setVisible(false);
stand.setVisible(false);
deal.setVisible(true);
playerNum.setText("YOU WIN!");
dealerNum.setText("YOU WIN!");
handsWon += 1;
String temp = Integer.toString(handsWon);
handsWonNum.setText(temp);
}
if (dealerFinal > playerFinal) {
hit.setVisible(false);
stand.setVisible(false);
deal.setVisible(true);
playerNum.setText("YOU LOSE!");
dealerNum.setText("YOU LOSE!");
handsLost += 1;
String temp = Integer.toString(handsLost);
handsLostNum.setText(temp);
}
if (dealerFinal == playerFinal) {
playerNum.setText("DRAW! PLAY AGAIN!");
dealerNum.setText("DRAW! PLAY AGAIN!");
hit.setVisible(false);
stand.setVisible(false);
deal.setVisible(true);
}
handsWon = 0;
handsLost = 0;
} //END STAND METHOD
And the condition that helps to meet it is here:
//method to add scores to text fields
public void addScores(int pScore, int dScore, TextField playerNum, TextField dealerNum) {
//ADD PLAYER SCORE
String playerScore = playerNum.getText();
int playerCurrent = Integer.parseInt(playerScore);
int newCurrent = playerCurrent + dScore;
String newScore = Integer.toString(newCurrent);
playerNum.setText(newScore);
//ADD DEALER SCORE
String dealerScore = dealerNum.getText();
int dealerCurrent = Integer.parseInt(dealerScore);
int newDealCurrent = dealerCurrent + pScore;
String newDealScore = Integer.toString(newDealCurrent);
dealerNum.setText(newDealScore);
}
I add the scores to text fields and then pull them again later in the project. Yet, even when the values are meeting the conditions of being larger than the opponents value, the statement does not trigger.
The expected result is when I click on the 'Stand' button, the statement is triggered and then the variable that adds to the total tally is activated.
Try putting System.out in every step to check if it is actually getting there. Put one as the first statement in the Stand method like: System.out.println("In Stand method");
Then put more of those before the if statements and inside them like:
System.out.format("Before: playerFinal : %s, dealerFinal: %s, playerFinal > dealerFinal: %d %n", playerFinal, dealerFinal, playerFinal > dealerFinal);
if (playerFinal > dealerFinal) {
System.out.format("In: playerFinal : %s, dealerFinal: %s, playerFinal > dealerFinal: %d %n", playerFinal, dealerFinal, playerFinal > dealerFinal);
Do that for each of the methods, to see if that method is actually running and what the values are.
If you see that the if statements are executing and the flow going into them, but you don't see any changes on the GUI elements, then try using:
Platform.runLater(() -> {
// Your GUI changes code
playerNum.setText("YOU WIN!");
dealerNum.setText("YOU WIN!");
});
Platform.runLater receives a runnable as an argument, and is the right way to update the GUI if you are using JavaFX.
Sometimes you may save the file and run it and the IDE would not actually compile it, running the old code. In that case, you can try restarting the IDE and trying again.
I'm making a simple quiz program. I need to display my Correct and Wrong it depends on the answer of the user. I think it is in the IF else. That's why I can't get it through. When I run it. I choose the correct answer. It is still displaying "Wrong!" and it counts it as correct. and Then change to different number. It is still displaying "Wrong!". I'm using checkbox as the multiple choice of the quiz.
Here's my code:
if(C1.getState()) // if the user chooses the checkbox c1
{
outputlabel.setText("Correct\n");
CorrectAnswer++; // it will count one point per correct answer.
}else
outputlabel.setText("Wrong!\n");
if(C13.getState()) // if the user chooses the checkbox C13
{
outputlabel.setText("Correct\n");
CorrectAnswer++;
}else
outputlabel.setText("Wrong!\n");
if(C19.getState()) // if the user chooses the checkbox C19
{
outputlabel.setText("Correct\n");
CorrectAnswer++;
}else
outputlabel.setText("Wrong!\n");
if(C21.getState()) // if the user chooses the checkbox C21
{
outputlabel.setText("Correct\n");
CorrectAnswer++;
}else
outputlabel.setText("Wrong!\n");
if(C27.getState()) // if the user chooses the checkbox C27
{
outputlabel.setText("Correct\n");
CorrectAnswer++;
}else
outputlabel.setText("Wrong!\n");
CorrectLabel.setText("Correct Answers: "+CorrectAnswer);
score =(CorrectAnswer*100)/5; // average of the quiz
if (score>=75)
{
scorelabel.setText("Grade: "+score+ "% ");
}else{
scorelabel.setText("Grade: "+score+"%.");
repaint();}
}
}
I'm not entirely sure what you're trying to do in the code. For each you're checking if it is set, and then you're setting the outputlabel value. So if the first checkbox is checked it will set the outputlabel text to "Correct". And if any of the other checkboxes are not checked it will then simply override what you did before and set the label to "Wrong".
Maybe you want separate outputlabels for each of the checkboxes?
You should have one final output label, after you check the state of all the correct answers. And based on the correct answers count, you can set the final output label.
I'm trying to find an appropriate ExpectedConditions method for this situation. I have a chart and I want to check the text in each row after re-sorting the chart. Problem is, when the chart is refreshing, the text still exists, it's just greyed out. So when I click a button to get the chart to be re-sorted, then look for the text that I'm looking for right away, the test fails because the text hasn't changed yet. I can't use visibilityOfElementLocated because the element is still visible when the chart is refreshing, I'm just waiting for the element to change.
Not sure if any of that makes sense!! It is a really difficult issue to explain.
A little background: I'm using Selenium Java and testing using Chrome. Here is my method thus far. It works fine, I just need to figure out how to make the program wait long enough for the chart to refresh WITHOUT using a sleep statement.
Thanks a bunch everyone! I know that wasn't as clear as it could be, but please let me know if you need any clarification.
public void Check_for_text_in_column(String text, String row, String column)
{
By by = By.xpath("//*[#id=\"table_Table_table_ktg\"]/tbody/tr[" + row + "]/td[" + column + "]/div/div/span");
WebDriverWait wait = new WebDriverWait(getWebDriver(), WAIT_TIME);
//This is the line that I need to change:
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
if(!element.getText().equals(text))
{
fail("\nDid not find text: " + text + "\nFound text: " + element.getText() + "\n");
}
}
Cheers!
You can replace
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
with
WebElement element = wait.until(ExpectedConditions.textToBePresentInElement(by, text));
EDIT:
Your WAIT_TIME is the timeout for your wait.
If the expected condition hasn't returned true before timing out according to your WAIT_TIME, then element will be null.
So, your check could look something like this:
if(element == null)
{
fail("\nDid not find text: " + text + "\nFound text: " + element.getText() + "\n");
}
EDIT:
Perhaps another option could be something like this:
public void Check_for_text_in_column(String text, String row, String column)
{
By by = By.xpath("//*[#id=\"table_Table_table_ktg\"]/tbody/tr[" + row + "]/td[" + column + "]/div/div/span");
WebDriverWait wait = new WebDriverWait(getWebDriver(), WAIT_TIME);
// your original find
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
// flag to set when text is found, for exiting loop
boolean hasText = false;
// counter for # of times to loop, finally timing out
int tries = 0;
// until text is found or loop has executed however many times...
while (hasText == false && tries < 20) {
// get the element
element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
// if text is not present, wait 250 millis before trying again
if(!element.getText().equals(text){
Thread.sleep(250);
tries++;
}
else{
// text found, so set flag to exit loop
hasText = true;
}
}
if(!element.getText().equals(text))
{
fail("\nDid not find text: " + text + "\nFound text: " + element.getText() + "\n");
}
}
I know you said you don't want sleep statements, but I assume you meant that you just don't want a single unnecessarily long one. Even ExpectedConditions are using sleep internally. They sleep for a few milliseconds between polling for changes - and that's exactly what this does, just without the ExpectedCondition type wrapper.
I am building a GWT component to behave much like the comments box here on stackoverflow, and other sites. I am trying to register listeners for KeyPress, Change and ONPASTE events that will update my status line with number of characters remaining, etc.
It works except it is always one character behind the actual number of characters in the text area. I set the max number of characters to 10. When I type the first character it still says, "10 characters remaining". It doesn't update the status line until I type the second character and then it is one off, it says 9 characters remaining when the second character is typed.
When I BACKSPACE or DELETE, it is also one off, when there are no characters it still says "9 characters remaining" until I press the BACKSPACE or DELETE a second time.
I am getting this behavior in both Firefox, Chrome and Internet Explorer on Windows. So I think I am not registering something correctly.
I know this has something to do with when the events are getting fired, but I have spend hours on trying to diagnose this behavior and have run out of ideas.
Here is where I am registering the event handlers, the complete code is BoundedTextAreaWithFeedback.
private void registerHandlers()
{
final BoundedTextAreaWithFeedback outer = this;
this.textArea.addChangeHandler(new ChangeHandler()
{
public void onChange(final ChangeEvent changeEvent)
{
outer.validate();
}
});
this.textArea.addKeyPressHandler(new KeyPressHandler()
{
public void onKeyPress(final KeyPressEvent keyPressEvent)
{
outer.validate();
}
});
this.panel.addFocusHandler(new FocusHandler()
{
public void onFocus(final FocusEvent focusEvent)
{
outer.textArea.setFocus(true);
}
});
// capture paste events
this.textArea.sinkEvents(Event.ONPASTE);
}
Here is the validate() method.
private boolean validate()
{
final boolean isValid;
final int len = this.textArea.getText().length();
if (len < this.minLength)
{
this.status.setText("Enter at least " + this.minLength + " characters.");
this.status.setStyleName("input-status-underflow");
isValid = false;
}
else if (len > this.maxLength)
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-overflow");
isValid = false;
}
else
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-ok");
isValid = true;
}
return isValid;
}
I just started adding every addXXXHandler() until one worked.
this.textArea.addKeyUpHandler(new KeyUpHandler()
{
public void onKeyUp(final KeyUpEvent event)
{
outer.validate();
}
});
Seems to have done the trick.
Here is the working code, CTRL-V and paste from context menu also work now.
Try using a DeferredCommand to execute the validation code. I believe the problem is that when the event is firing, they character is not yet added to the text area. The DeferredCommand will not execute until any pending event handlers have finished, allowing the length of the text to be calculated correctly.
See this question for an example of using a DeferredCommand.