简体   繁体   中英

Java Swing GUI updating/changing from method - freezing in loop

basically, I have this code which was initially working with console i/o now I have to connect it to UI . It may be completely wrong, I've tried multiple things although it still ends up with freezing the GUI.

I've tried to redirect console I/O to GUI scrollpane, but the GUI freezes anyway. Probably it has to do something with threads, but I have limited knowledge on it so I need the deeper explanation how to implement it in this current situation.

This is the button on GUI class containing the method that needs to change this GUI.

public class GUI {
 ...
btnNext.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {

                controller.startTest(index, idUser);

        }
    });
 }

This is the method startTest from another class which contains instance of Question class.

public int startTest()  {

    for (int i = 0; i < this.numberofQuestions; i++) {
        Question qt = this.q[i];
            qt.askQuestion(); <--- This needs to change Label in GUI

        if(!qt.userAnswer())  <--- This needs to get string from TextField
            decreaseScore(1);    

    }

   return actScore();

}   

askQuestion method:

   public void askQuestion() {
    System.out.println(getQuestion());
    /* I've tried to change staticaly declared frame in GUI from there */


}   

userAnswer method:

 public boolean userAnswer() {
    @SuppressWarnings("resource")
    Scanner scanner = new Scanner(System.in);

    if( Objects.equals(getAnswer(),userInput) ) {
        System.out.println("Correct");
        return true;
    }

    System.out.println("False");            
    return false;

}

Thanks for help.

You're correct in thinking that it related to threads.

When you try executing code that will take a long time to process (eg. downloading a large file) in the swing thread, the swing thread will pause to complete execution and cause the GUI to freeze. This is solved by executing the long running code in a separate thread.

As Sergiy Medvynskyy pointed out in his comment, you need to implement the long running code in the SwingWorker class.

A good way to implement it would be this:

public class TestWorker extends SwingWorker<Integer, String> {

  @Override
  protected Integer doInBackground() throws Exception {
    //This is where you execute the long running
    //code
    controller.startTest(index, idUser);
    publish("Finish");
  }

  @Override
  protected void process(List<String> chunks) {
    //Called when the task has finished executing.
    //This is where you can update your GUI when
    //the task is complete or when you want to
    //notify the user of a change.
  }
}

Use TestWorker.execute() to start the worker.

This website provides a good example on how to use the SwingWorker class.

As other answers pointed out, doing heavy work on the GUI thread will freeze the GUI. You can use a SwingWorker for that, but in many cases a simple Thread does the job:

Thread t = new Thread(){
    @Override
    public void run(){
        // do stuff
    }
};
t.start();

Or if you use Java 8+:

Thread t = new Thread(() -> {
    // do stuff
});
t.start();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM