0

So the title really says it all. I need the Thread to wait for the timer to finish before executing the next command in the method.

Code:

import javax.swing.Timer;

public class doesntMatter
{
    Timer timer;
    ActionListener timerTask;

    public doesntMatter
    {
         timerTask = new ActionListener()
         {
              @Override
              public void actionPerformed(ActionEvent e)
              {
                  //taskSomethingIdk
              }
         }
    }

    private void whatever
    {
        timer = new Timer(1000, timerTask);
        timer.setInitialDelay(0);
        timer.start();

        // here i need to wait for the timer to finish

        if(timerhasfrigginfinished)
             continueOrSomethingIdk
    }

}
  • Put it into the timer's ActionListener, to be done when it has completed repeating. – Hovercraft Full Of Eels Jan 15 '17 at 01:50
  • Define "when timer is done"? In most cases timers repeat, although you set them up not to. In any case, you could use an observer pattern or simply call some other predefined method when you're done – MadProgrammer Jan 15 '17 at 02:28

2 Answers2

1

Assuming that your timer repeats, inside the Timer's ActionListener check to see if it is running its last repeat, and if so, there, call the continueOrSomethingIdk() method.

Otherwise you're going to have to rig your own notification mechanism, a call-back so that the timer notifies any listeners that it has completed running.

For example:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class WhenTimerDone extends JPanel {
    private static final Color[] COLORS = { 
            Color.RED, Color.ORANGE, 
            Color.YELLOW, Color.GREEN,
            Color.BLUE, Color.CYAN };
    private static final String START = "Start";
    private static final String DONE = "Done";
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    public static final int TIMER_DELAY = 1000;
    private JLabel statusLabel = new JLabel(START);
    private StartAction startAction = new StartAction("Start!");

    public WhenTimerDone() {
        add(statusLabel);
        add(new JButton(startAction));
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    // this is the method called by the Timer's ActionListener when it is done
    public void done() {
        // reset all to baseline state
        statusLabel.setText(DONE);
        startAction.setEnabled(true);
        setBackground(null);
    }

    // ActionListener for the start button
    private class StartAction extends AbstractAction {

        public StartAction(String name) {
            super(name);
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // disables itself
            setEnabled(false);
            statusLabel.setText(START); // updates the status label

            // create and start a timer
            Timer timer = new Timer(TIMER_DELAY, new TimerListener());
            timer.setInitialDelay(0);
            timer.start();    
        }
    }

    // action listener for the timer
    private class TimerListener implements ActionListener {
        private int colorsIndex = 0;

        @Override
        public void actionPerformed(ActionEvent e) {
            // simply loops through a colors array, changing background color
            if (colorsIndex < COLORS.length) {
                setBackground(COLORS[colorsIndex]);
                colorsIndex++;
            } else {
                // when all colors shown -- stop the timer
                ((Timer) e.getSource()).stop();

                // and call the done method -- ******* here's the key!
                done();  // called when Timer is done!
            }
        }
    }

    private static void createAndShowGui() {
        WhenTimerDone mainPanel = new WhenTimerDone();

        JFrame frame = new JFrame("WhenTimerDone");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
0

The Keywords here are notify/wait Your timer thread should notify the other thread which should be waiting like this:

import javax.swing.Timer;

public class doesntMatter
{
Timer timer;
ActionListener timerTask;

public doesntMatter
{
     timerTask = new ActionListener()
     {
          @Override
          public void actionPerformed(ActionEvent e)
          {
              synchronized(timer){
                  //taskSomethingIdk
                  //you would have to rig something so we can access a common object as the monitor/lock object
                  timer.notify()
              }
          }
     }
}

private void whatever
{
    timer = new Timer(1000, timerTask);
    timer.setInitialDelay(0);
    timer.start();
    //Need to obtain a lock on the "monitor" object
    //Lock will be released while it is waiting
    synchronized(timer){
        timer.wait()
        //do whatever
    }
}

}

This will make the "main" thread wait until the timer thread calls the notify method which will then wake up one of the waiting threads.

Also i don't think that "ActionListener" extends the "TimerTask". So the code example probably does not compile due to you giving an ActionListener to the Timer, which expects a TimerTask as the input. Or maybe i somehow do not understand what your code is supposed to do anyway.

See How to use wait and notify in Java? for more information.

Timmeey
  • 363
  • 3
  • 9
  • Have you tested this code? It looks like it will cause the Swing event dispatch thread to *wait*, meaning that the entire GUI should freeze. I'm not sure that this is the behavior that the OP is desiring. – Hovercraft Full Of Eels Jan 15 '17 at 02:02
  • No i didn't test it.. But only the thread that called the "public void whatever()" method will wait until the actionPerformed method is called from a different thread. If the swing dispatcher calls the "whatever" method, yes. then the dispatcher thread will hang. But the thread that calls actionPerformed() will only hang to wait to obtain the lock on the "timer" object. – Timmeey Jan 15 '17 at 02:06
  • uhm.. thank you both: I tried it and this guy is right.. it does freeze.. i want a label to do a countdown – user7419985 Jan 15 '17 at 02:11
  • @Timmeey: the thread that calls actionPerformed **is** the EDT, the event dispatch thread, but I assume that you already know this. And putting it into wait state will completely freeze and render useless the GUI. – Hovercraft Full Of Eels Jan 15 '17 at 02:13
  • @user7419985: of course it freezes the GUI. It blocks the EDT. You could use a background thread, but then you're over-complicating things when this is not needed. Instead just wire your timer to notify the class when it itself is done. – Hovercraft Full Of Eels Jan 15 '17 at 02:14
  • @HovercraftFullOfEels But the code inside the actionPerformed() does not even contain a wait? It just contains the notify(), but no waiting, besides obtaining the lock in the synchronized(timer) statement. So yeah, the EDT calls actionPerformed() which then notifies the other thread but i don't see how it will wait for longer than is needed to obtain a lock on the lock-object but yeah, this seems overly complicated – Timmeey Jan 15 '17 at 02:17
  • Timmeey -- avoid all confusion -- create your own [mcve] and post it here. But please do make sure to start your Swing GUI on the EDT as I do in my MCVE below, by using `SwingUtilities.invokeLater(() -> /* start gui here * / );` – Hovercraft Full Of Eels Jan 15 '17 at 02:20
  • 1
    If you're call wait in the EDT, this will not work, just saying ;) – MadProgrammer Jan 15 '17 at 02:29