sirdan
sirdan

Reputation: 1028

While loop to repeat actionPerformed of a JButton

I've got a JFrame with some JButtons. The "update" button (named JButton1) executes a number of queries which fill a form. Now I'd like another JButton to be the "automatic update" (named JButton2), so I would like it to loop inside the JButton1ActionPerformed method, until JButton2 is no longer selected. When I press JButton2 the window freezes.

Is my code right? Do you think I would need a stop button?

private void jToggleButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                               

       long start = System.currentTimeMillis();
       if(jToggleButton2.isSelected()){
           start = System.currentTimeMillis();

            do{
                do{
                    jButton1ActionPerformed(evt);
                }
                while(System.currentTimeMillis()-start>3000);

            }
            while(jToggleButton2.isSelected()); 
       }

        if(jToggleButton2.isSelected()){
            jToggleButton2.setSelected(false);
        }


    }  

Upvotes: 1

Views: 1274

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

Swing is:

  • Single threaded; this means that you should not perform any long running or blocking operations within the context of the Event Dispatching Thread
  • Not thread safe; this means you should not update the UI or anything the UI might depend on outside of the EDT. It's also risky to try and address UI elements outside the EDT, as the thread model might return false values

Without more context to your problem, I might suggest using a Swing Timer. Two main reasons:

  1. The ActionListener is called within the context of the EDT, making it safe to update the UI from within in
  2. You can specify a delay between updates, which reduces the risk of overloading the EDT which will cause performance issues

For example...

private void jToggleButton2ActionPerformed(java.awt.event.ActionEvent evt) {

    long start = System.currentTimeMillis();
    if (jToggleButton2.isSelected()) {
        // You could use an instance field instead and determine
        // if the Timer is already running or not
        Timer timer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!jToggleButton2.isSelected()) {
                    ((Timer) e.getSource()).stop();
                    return;
                }
                jButton1ActionPerformed(evt);
            }
        });
        timer.start();

        // Just want to point out that this doesn't make sense
        // As if the button was selected, you'd still be in
        // your previous loop
        //if (jToggleButton2.isSelected()) {
        //  jToggleButton2.setSelected(false);
        //}
    }
}

Another solution might be to use a SwingWorker, which provides you with a means to perform long running or blocking operations off the EDT, but which also provides functionality to update the UI safely from within the EDT.

Take a look at:

for more details

Upvotes: 2

Antoniossss
Antoniossss

Reputation: 32507

Lets put aside that you should not crete Thread like I will show you (but use SwingWorker for example) you need to do something like this:

private void jToggleButton2ActionPerformed(java.awt.event.ActionEvent evt) {

       if(jToggleButton2.isSelected()){
          new Thread(new Runnable(){

          public void run(){
                  long start = null;
                  do{
                         start = System.currentTimeMillis();
                        jButton1ActionPerformed(evt);
                   }while(jToggleButton2.isSelected() &&jSystem.currentTimeMillis()-start>3000)
          }
          }).start();

    }  

Im not focusing on if your code is valid or not, its just shows how to run something in background, so you will not freeze your GUI.

Upvotes: -1

Related Questions