I'm a beginner and I've hit a bump in the road.
The problem I have is that my JTextArea
is not updating as my program is running. I ran a command line to see whether the value of the JTextArea
is changing. It turns out that it is but on the UI it remains the same until the end, then it shows the final change that I had made. Could you please help me find a solution to this problem?
Here follows the code where the problem arises. (In my ActionListener
.)
private class ButtonHandler implements ActionListener //Start of inner class for event handling of buttons
{
public void actionPerformed( ActionEvent event )
{//start method that prosesses the events for the buttons
if(event.getSource() == call)
{
do {
delay.myDelay(2000); //simply a Thread.sleep(I intend to repeat this a lot so I made a class for it.
elevatorFloor = eCall.calling();
eCall.setFloor(elevatorFloor);
System.out.println("getfloor in call= " +eCall.getFloor()); //Test yields correct value
eFloor = ind.level(eCall.getFloor()); //String that gives floor number
floorIndicator.setText(eFloor); //DOES NOT CHANGE IN GUI
String value = floorIndicator.getText();
System.out.println("Floorindicator is= " +value);//Test yields that the value is changing dynamically in command line
floorIndicator.updateUI(); //Stuff I found on the internet that didnt work
floorIndicator.revalidate();
floorIndicator.validate();
} while(eCall.getFloor() != eCall.getUserFloor());
delay.myDelay(2000);
doorImage.setIcon(door1);
}
}
}
In Java, the UI (drawing of components, events, etc) is handled by a special thread called the Event Dispatching Thread. Since this thread determines how quickly will your UI respond to events, it is important that you do only UI related operations on it.
Doing operations which might be blocking, such as Thread.sleep
are not recommended to be done in this thread since it blocks the execution of the thread and thus makes your application not respond to events in a timely manner. This is why in some of the comments, you where told that you are blocking the EDT.
In you case, looping can also be avoided since with each iteration, you are waiting for a period of two seconds (I am assuming to give the impression of the escalator moving between floors).
The solution to this, (one of them at least), would be to place the entire body of the do...while
loop in a separate thread. This thread will be then launched by the event handler. This solution would not block the event dispatching thread, but now there is another problem: Only the EDT can upload the UI, thus, the approach above on its own would not change the text.
For this purpose, Java provides a SwingWorker
class which allows code to queue items on the EDT.
Thus in short, your code would like something like so:
private class ButtonHandler implements ActionListener //Start of inner class for event handling of buttons
{
public void actionPerformed( ActionEvent event )
{//start method that prosesses the events for the buttons
if(event.getSource() == call)
{
//final int elFloor = eCall.calling(); i ran it without this and it worked
new Thread(new Runnable() {
@Override
public void run() {
do{
/*There is nothing wrong with calling Thread.sleep directly
*wrapping a one liner with your own implementation might cause
*more confusion
*/
delay.myDelay(2000);
//Not sure what is elevatorFloor
elevatorFloor = eCall.calling();
eCall.setFloor(elevatorFloor);
System.out.println("getfloor in call= " +eCall.getFloor()); //Test yields correct value
eFloor = ind.level(eCall.getFloor()); //String that gives floor number
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
floorIndicator.setText(eFloor); //DOES NOT CHANGE IN GUI
}
});
String value = floorIndicator.getText();
System.out.println("Floorindicator is= " +value);//Test yields that the value is changing dynamically in command line
}while(eCall.getFloor() != eCall.getUserFloor());
//delay.myDelay(2000);
doorImage.setIcon(door1);
}
}).start();
}
}
}
Note: The code above has not been tested and you might need to make additional changes, especially on how you can access the variables from within the thread scopes, but it should provide an overview of what you need to do.