1

I have a JButton which performs an action when clicked. In the actionPerformed I want to update the button text before calling the NotifyObserver, which contains a big number of calculations. The problem is that the buttontext won't update until all the operations called by the NotifyObserver are done. Here's the JButton action code:

//Action for sinoButton
sinoButton.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        sinoButton.setText("Loading Sinogram"); //Set text while loading sinogram
        NotifyObserversSinogram(); //Notify observer and start sinogram calculation
    }
});

As you can see, the button text should be updated before the observers are notified. Any ideas on how to solve this?

Mordechai
  • 15,437
  • 2
  • 41
  • 82
JayJayPartay
  • 57
  • 1
  • 5
  • You would run expensive computations on another thread, so you can ask UI thread to update UI whenever you like. – kiwixz Apr 28 '15 at 11:51

4 Answers4

3

EDIT Since Swing is not thread safe you have to use Swingutilities:

JButton b = new JButton("Run query");
b.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    Thread queryThread = new Thread() {
      public void run() {
        runQueries();
      }
    };
    queryThread.start();
  }
});

// Called from non-UI thread
private void runQueries() {
  for (int i = 0; i < noQueries; i++) {
    runDatabaseQuery(i);
    updateProgress(i);
  }
}

private void updateProgress(final int queryNo) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      // Here, we can safely update the GUI
      // because we'll be called from the
      // event dispatch thread
      statusLabel.setText("Query: " + queryNo);
    }
  });
}

Here some more complete info about how it works: Threading with swing

Jose Luis
  • 3,307
  • 3
  • 36
  • 53
3

If NotifyObserversSinogram() does not do Swing specific computations, just drop it in another thread:

 public void actionPerformed(ActionEvent e) {
    sinoButton.setText("Loading Sinogram");
    new Thread() {
        public void run(){
            NotifyObserversSinogram();
        }
    }.start();
}

If it does, see SwingWorker.

Mordechai
  • 15,437
  • 2
  • 41
  • 82
2

Swing is a single threaded framework, the ActionListener is execute within the context of the Event Dispatching Thread, this will prevent the UI from been updated until the actionPerformed method exist

Now, you could use another thread to run your calculations in, but Swing is also not Thread safe.

A simple solution would be to use a SwingWorker, which has means by which you can update the UI safely, provide progress updates and also be notified when the worker is done

See Concurrency in Swing and Worker Threads and SwingWorker for more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0
JButton sinoButton = new JButton();
  //Action for sinoButton
    sinoButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            ((JButton)e.getSource()).setText("Loading Sinogram"); //Set text while loading sinogram

           /*Since this is time consuming operation running on EDT its causing the issue.
            * To fix it run the time consuming operation in a thread other than EDT
            * */
            new Thread(){
                public void run() {
                    NotifyObserversSinogram();
                };
            }.start();
        }
    });
Laxman
  • 2,643
  • 2
  • 25
  • 32