| A parallel process capability allows for timers, which provide 
              for periodic updates and scheduling of tasks. For example, a timer 
              can  
              Signal the redrawing of frames for an animation.Prompt for the status of a task and post a message about it. 
              Issue a daily/weekly reminders.Trigger a single task at a particular time in the future. With the Thread 
              class you could create your own timer class using the Thread.sleep(T) 
              method to delay action for some time T (see, for example, Chapter 
              8: Java : Demo 1). This approach, however, has some drawbacks. 
              For periodic events, if the processing times in between the sleep 
              periods vary significantly, then the overall timing will vary as 
              well and soon get out of synch with the "wall clock". 
              Also, if you need many timer events, the program will require many 
              threads and use up system resources.  For many applications you can instead use the timer classes that 
              come with the Java 2 SE:  
              javax.swing.Timer 
                provides timers to use with the Swing GUI such as prompting the 
                update of a component like a progress bar.
 
The java.util 
                package (as of version 1.3) includes Timer 
                and TimerTask, 
                which work together to provide general purpose timers. These timers can provide multiple timed events from a single thread 
              and thus conserve resources. They also have various useful methods 
              such as scheduleAtFixedRate(TimerTask 
              task, long delay, long period) in java.util.Timer. 
              This method will set events to occur periodically at a fixed rate 
              and tied to the system clock. This is obviously useful for many 
              applications such as a countdown timer and alarm clocks where you 
              don't want the timing to drift relative to absolute time. 
             The resources listed below include a number 
              of tutorials and example programs dealing with timers. Here we will 
              give a couple of simple examples of the two types of Java timers 
              to illustrate how they work. Note: these timers are not intended 
              for real-time applications where the timing of actions must 
              be predictable and guaranteed. TimerTask 
              and Timer 
             The Timer 
              and TimerTask 
              combo in java.util 
              offers the most general timing capabilities with a number of options. 
              A Timer 
              object holds a single thread and can control many TimerTask 
              objects. The TimerTask 
              abstract class implements the Runnable 
              interface but it does not provide a concrete run() 
              method. Instead you create a TimerTask 
              subclass to provide the concrete run() 
              method with the code to carry out the task of interest. In the example below we fill a simulate the filling of a histogram 
              during an experiment. The data comes in at random times and we want 
              to show the histogram during the "data taking". The MakeData 
              object runs in a thread and the run() 
              method generates values from a Gaussian and uniform random number 
              generators to simulate "signal" and background noise, 
              resp. MakeData 
              uses the methods from the Updateable 
              interface to call back to the owner to tell it that new data has 
              been added and when the histogram filling is finished. We use a timer to set a flag to signal that the histogram display 
              should be repainted. A subclass of TimerTask 
              called PaintHistTask 
              sets the flag. Since its task is so simple we made it an inner class 
              for convenience and clarity. A Timer 
              object is created and scheduled to run PaintHistTask 
              every 250 milliseconds and to begin after a 100 millisecond delay 
              to give time for the histogram to receive some data.  
              
                 
                 
                  |  
                      TimerHistFillApplet.java 
                        - similar 
                        to UIDrawHistApplet 
                        in Chapter 7: 
                        Tech except that here a timer (java.util.Timer and 
                        its helper java.util.TimerTask) is used to allow for display 
                        of the histogram during its filling. A separate thread 
                        object, MakeData, creates the data. The class implements 
                        the Updateable interface to provide for callbacks. 
                        
 + New classes:
 MakeData.java 
                        - an instance of this Runnable class fills the histogram 
                        with a combination of a Gaussian and flat background to 
                        simulate data taking. It calls back to the Updateable 
                        owner object via the update() and done() methods
 
 Updateable.java 
                        - interface for callbacks to inform the calling object 
                        of an addition to the histogram and when the data filling 
                        has finished.
 
 + Previous classes:
 Chapter 
                        6:Tech: Histogram.java, 
                        HistPanel.java
 Chapter 
                        6:Tech: PlotPanel.java, 
                        PlotFormat.java
 
 |   
                  | import 
                    javax.swing.*; import java.awt.*;
 import java.awt.event.*;
 
 /**
 * Demonstrate the java.util.Timer by filling a 
                    histogram with
 * radomly generated data and periodically updating 
                    the histogram
 * display.
 *
 * This program will run as an applet inside an 
                    application frame.
 *
 * The applet uses the HistPanel to display contents 
                    of
 * an instance of Histogram. HistFormat used by 
                    HistPanel to
 * format the scale values.
 *
 * The java.util.Timer and java.util.TimerTask 
                    are used
 * to update the display of the histogram during 
                    the filling
 * of the histogram.
 *
 * Includes "Go" button to initiate the filling 
                    of the histogram.
 * To simulate data taking, a combination of a 
                    Gaussian and random
 * background values are generated.
 *
 * The number of values taken from
 * entry in a JTextField. "Clear"  button 
                    clears the histogram.
 * In standalone mode, the Exit button closes the 
                    program.
 **/
 public class TimerHistFillApplet extends JApplet
 implements ActionListener, Updateable
 {
 // Use the HistPanel JPanel subclass here
 HistPanel fOutputPanel = null;
 
 Histogram fHistogram = null;
 int fNumDataPoints = 100;
 
 boolean fMakingHist = false;
 boolean fUpdateDisplay = false;
 MakeData fMakeData;
 
 // Use the java.util Timer and TimerTask combo
 // for timing events.
 java.util.Timer fTimer;
 
 // A text field for input strings
 JTextField fTextField = null;
 
 // Flag for whether the applet is in a browser
 // or running via the main () below.
 boolean fInBrowser=true;
 
 //Buttons
 JButton fGoButton;
 JButton fClearButton;
 JButton fExitButton;
 
 /**
 * Create a User Interface with a histogram 
                    and a Go button
 * to initiate processing and a Clear 
                    button to clear the .
 * histogram. In application mode, 
                    the Exit button stops the
 * program.
 **/
 public void init () {
 Container content_pane = getContentPane 
                    ();
 
 JPanel panel = new JPanel (new BorderLayout 
                    ());
 
 // Use a textfield for an input parameter.
 fTextField =
 new JTextField (Integer.toString 
                    (fNumDataPoints), 10);
 
 // If return hit after entering text, 
                    the
 // actionPerformed will be invoked.
 fTextField.addActionListener (this);
 
 fGoButton = new JButton ("Go");
 fGoButton.addActionListener (this);
 
 fClearButton = new JButton ("Clear");
 fClearButton.addActionListener (this);
 
 fExitButton = new JButton ("Exit");
 fExitButton.addActionListener (this);
 
 JPanel control_panel = new JPanel 
                    ();
 
 control_panel.add (fTextField);
 control_panel.add (fGoButton);
 control_panel.add (fClearButton);
 control_panel.add (fExitButton);
 
 // Create a histogram and start filling 
                    it.
 makeHist ();
 fGoButton.setText ("Stop");
 fClearButton.setEnabled (false);
 if (fInBrowser) fExitButton.setEnabled 
                    (false);
 
 // JPanel subclass here.
 fOutputPanel = new HistPanel (fHistogram);
 
 panel.add (fOutputPanel,"Center");
 panel.add (control_panel,"South");
 
 // Add text area with scrolling to 
                    the contentPane.
 content_pane.add (panel);
 
 } // init
 
 /** Stop the filling if the browser page unloaded. 
                    **/
 public void stop () {
 fGoButton.setText ("Go");
 fClearButton.setEnabled (true);
 fMakingHist = false;
 }
 
 public void actionPerformed (ActionEvent e) {
 Object source = e.getSource ();
 if (source == fGoButton || source 
                    == fTextField) {
 String 
                    strNumDataPoints = fTextField.getText ();
 try
 {
 fNumDataPoints 
                    = Integer.parseInt (strNumDataPoints);
 }
 catch (NumberFormatException 
                    ex)
 {   // Could 
                    open an error dialog here but just
 // 
                    display a message on the browser status line.
 showStatus 
                    ("Bad input value");
 return;
 }
 if (!fMakingHist) {
 makeHist 
                    ();
 fGoButton.setText 
                    ("Stop");
 fClearButton.setEnabled 
                    (false);
 }  else {
 // 
                    Stop button has been pushed
 fGoButton.setText 
                    ("Go");
 fClearButton.setEnabled 
                    (true);
 fMakingHist 
                    = false;
 }
 
 } else if (source == fClearButton) 
                    {
 fHistogram.clear 
                    ();
 repaint ();
 } else if (!fInBrowser)
 System.exit 
                    (0);
 } // actionPerformed
 
 
 void makeHist () {
 if (fMakingHist) return; // only fill 
                    one hist at a time.
 fMakingHist = true;
 
 // Create an instance of the histogram 
                    class.
 // Make it wide enough enough to include 
                    the data.
 if (fHistogram == null)
 fHistogram 
                    = new Histogram ("Gaussian + Random Background",
 "Data",
 20,-10.0,10.0);
 
 // Create the runnable object to fill 
                    the histogram
 // Center signal at 3.0 and create 
                    background between
 // -10 and 10. The fraction of the 
                    data due to the
 // Gaussian will be 0.60. The maximum 
                    delay between
 // data poins will be 500msecs.
 fMakeData =
 new MakeData (this, fHistogram, 
                    fNumDataPoints,
 3.0, 0.60, -10.0, 10.0, 500);
 Thread data_thread = new Thread (fMakeData);
 
 
 // Before starting the filling, create 
                    the timer task
 // that will cause the histogram display 
                    to update
 // during the filling.
 // Create a timer. TimerTask created 
                    in MakeHist ()
 fTimer = new java.util.Timer ();
 
 // Start the timer after 100ms and 
                    then repeat calls
 // to run in PaintHistTask object 
                    every 250ms.
 fTimer.schedule (new PaintHistTask 
                    (), 100, 250);
 
 // Now start the data filling.
 data_thread.start ();
 
 } // makeHist
 
 /**
 * Use the inner class technique to 
                    define the
 * TimerTask subclass for signalling 
                    that the display
 * should be updated.
 **/
 class PaintHistTask extends java.util.TimerTask
 {
 public void run () {
 fUpdateDisplay = true;
 }
 } // class PaintHistTask
 
 /**
 *  Repaint the histogram 
                    display and turn off the
 *  update display flag. 
                    Return the fMakingHist flag
 *  to indicate if updating 
                    should continue.
 **/
 public boolean update (Object obj) {
 // Don't update the display until 
                    the timer
 // turns on the fUpdateDisplay flag.
 if (fUpdateDisplay) {
 // Possible this method 
                    called before fOutputPanel
 // created in the init 
                    (). So check if it exists
 // before attempting to 
                    repaint.
 if (fOutputPanel != null) 
                    fOutputPanel.repaint ();
 fUpdateDisplay = false;
 }
 return fMakingHist;
 } // update
 
 /** Called when the histogram filling is finished. 
                    **/
 public void done () {
 fMakingHist = false;
 
 // Stop the histogram display updates.
 fTimer.cancel ();
 
 // Update one last time
 fOutputPanel.repaint ();
 
 // Reset the buttons.
 fGoButton.setText ("Go");
 fClearButton.setEnabled (true);
 } .. done
 
 public static void main (String[] args) {
 //
 int frame_Width=450;
 int frame_Height=300;
 
 //
 TimerHistFillApplet applet = new TimerHistFillApplet 
                    ();
 applet.fInBrowser = false;
 applet.init ();
 
 // Following anonymous class used 
                    to close window & exit program
 JFrame f = new JFrame ("Demo");
 f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
 
 // Add applet to the frame
 f.getContentPane ().add ( applet);
 f.setSize (new Dimension (frame_Width,frame_Height));
 f.setVisible (true);
 } //main
 } // class TimerHistFillApplet
 |   
                  | /** * This runnable class fills a histogram with Gaussian
 * distributed random data.
 **/
 public class MakeData implements Runnable
 {
 Histogram fHistogram;
 int fNumData;
 Updateable fOwner;
 
 // Gaussian center with default value
 double fSignalPoint;
 
 // Flat background range with defaults
 double fBgLow;
 double fBgRange;
 
 // Fraction of the data due to the Gaussian
 double fFractionSignal = 0.60;
 
 // Maximum delay between data points with default
 int fMaxDelay = 1000;
 
 // Create an instance of the Random class for
 // producing our random values.
 static java.util.Random fRan = new java.util.Random 
                    ();
 
 /**
 *  Constructor
 *  @param owner to call back with updates.
 *  @param histogram to add data to.
 *  @param numData Number of data points 
                    to add to histogram.
 *  @param signalPoint Position of center 
                    of Gaussian.
 *  @param fractionSignal Fraction of 
                    data due to Gaussian
 *  @param bgLow Low end of flat background 
                    range.
 *  @param bgHi High end of flat background 
                    range.
 *  @param maxDelay maximum delay in 
                    msecs between data events.
 **/
 public MakeData (Updateable owner,
 Histogram histogram, int numData,
 double fSignalPoint, double fractionSignal,
 double bgLow, double bgHi,
 int maxDelay) {
 
 fHistogram  = histogram;
 fNumData    = 
                    numData;
 fOwner = owner;
 
 // Background upper and lower range
 fBgLow   = bgLow;
 fBgRange = bgHi - fBgLow;
 
 // Position of center of Gaussian.
 fSignalPoint    = 
                    fSignalPoint;
 fFractionSignal = fractionSignal;
 
 // Maximum delay time between new 
                    data points
 fMaxDelay = maxDelay;
 } // ctor
 
 
 /**
 * Simulate data taking by generating 
                    both a Gaussian
 * and a flat background. Put in random 
                    delays between
 * the data points.
 **/
 public void run () {
 for (int i=0; i < fNumData; i++) {
 double val;
 
 // Signal 
                    events
 if (fRan.nextDouble 
                    () < fFractionSignal)
 val 
                    = fRan.nextGaussian () + fSignalPoint;
 else
 // Flat background
 val 
                    = fBgRange * fRan.nextFloat () + fBgLow;
 
 // Fill histogram
 fHistogram.add 
                    (val);
 
 // Update 
                    the owner. Stop updates if
 // false returned.
 if (!fOwner.update 
                    (this) ) break;
 
 // Pause for 
                    random periods between events
 try {
 Thread.sleep 
                    (fRan.nextInt (fMaxDelay));
 }
 catch  (InterruptedException 
                    e)
 {}
 }
 
 // Tell the Updateable owner that 
                    the fNumData is now filled.
 fOwner.done ();
 } // run
 
 } // class MakeData
 |   
                  | /*** This interface provides for callbacks to
 * update an object.
 **/
 interface Updateable
 {
 boolean update ();
 void done ();
 }// interface Updateable
 |   
                  | PlotPanel.java, PlotFormat.java are unchanged 
                      from Chapter 6: Tech 
                      : Plotting.  HistPanel.java, 
                      Histogram.java 
                      are unchanged from Chapter 
                      6: Tech : Histogram Plot  |    javax.swing.Timer The javax.swing.Timer 
              can also do the above task. Below we show the class SwingTimerHistFillApplet, 
              which is very similar to the above program except for the use of 
              a javax.swing.Timer 
              instance.  
              
                
                  | SwingTimerHistFill_JApplet11.java 
                    - same as TimerHistFill_JApplet11 
                    above except it uses a javax.swing.Timer instance for the 
                    histogram updating. |   
                  | import 
                      javax.swing.*;import java.awt.*;
 import java.awt.event.*;
 
 /**
 * This program will run as an applet inside
 * an application frame.
 *
 * The applet uses the HistPanel to display contents 
                      of
 * an instance of Histogram. HistFormat used 
                      by HistPanel to
 * format the scale values.
 *
 * The javax.swing is used to update the display 
                      of the histogram
 * during the filling of the histogram.
 *
 * Includes "Go" button to initiate the filling 
                      of the histogram.
 * To simulate data taking, a combination of 
                      a Gaussian and random
 *  background values are generated.
 *
 * The number of values taken from entry in a 
                      JTextField.
 * The "Clear"  button clears the histogram. 
                      In standalone mode,
 * the Exit button closes the program.
 *
 **/
 public class SwingTimerHistFillApplet extends JApplet
 implements ActionListener, Updateable
 {
 // Use the HistPanel JPanel subclass here
 HistPanel fOutputPanel;
 
 Histogram fHistogram;
 int fNumDataPoints = 100;
 
 boolean fMakingHist = false;
 boolean fUpdateDisplay = false;
 MakeData fMakeData;
 
 // Use the Swing timer
 javax.swing.Timer fTimer;
 
 // A text field for input strings
 JTextField fTextField;
 
 // Flag for whether the applet is in a browser
 // or running via the main () below.
 boolean fInBrowser = true;
 
 //Buttons
 JButton fGoButton;
 JButton fClearButton;
 JButton fExitButton;
 
 /**
 * Create a User Interface with a 
                      histogram and a Go button
 * to initiate processing and a Clear 
                      button to clear the .
 * histogram. In application mode, 
                      the Exit button stops the
 * program.
 **/
 public void init () {
 Container content_pane = getContentPane 
                      ();
 
 JPanel panel = new JPanel (new BorderLayout 
                      ());
 
 // Use a textfield for an input 
                      parameter.
 fTextField =
 new JTextField (Integer.toString 
                      (fNumDataPoints), 10);
 
 // If return hit after entering 
                      text, the
 // actionPerformed will be invoked.
 fTextField.addActionListener (this);
 
 fGoButton = new JButton ("Go");
 fGoButton.addActionListener (this);
 
 fClearButton = new JButton ("Clear");
 fClearButton.addActionListener (this);
 
 fExitButton = new JButton ("Exit");
 fExitButton.addActionListener (this);
 
 JPanel control_panel = new JPanel 
                      ();
 
 control_panel.add (fTextField);
 control_panel.add (fGoButton);
 control_panel.add (fClearButton);
 control_panel.add (fExitButton);
 
 // Create a histogram and start 
                      filling it.
 makeHist ();
 fGoButton.setText ("Stop");
 fClearButton.setEnabled (false);
 if (fInBrowser) fExitButton.setEnabled 
                      (false);
 
 // JPanel subclass here.
 fOutputPanel = new HistPanel (fHistogram);
 
 panel.add (fOutputPanel,"Center");
 panel.add (control_panel,"South");
 
 // Add text area with scrolling 
                      to the contentPane.
 content_pane.add (panel);
 
 } // init
 
 public void actionPerformed (ActionEvent e) 
                      {
 Object source = e.getSource ();
 if (source == fGoButton || source 
                      == fTextField) {
 String strNumDataPoints 
                      = fTextField.getText ();
 try {
 fNumDataPoints 
                      = Integer.parseInt (strNumDataPoints);
 }
 catch (NumberFormatException 
                      ex) {
 // 
                      Could open an error dialog here but just
 // 
                      display a message on the browser status line.
 showStatus 
                      ("Bad input value");
 return;
 }
 if (!fMakingHist) 
                      {
 makeHist 
                      ();
 fGoButton.setText 
                      ("Stop");
 fClearButton.setEnabled 
                      (false);
 } else {
 // 
                      Stop button has been pushed
 fGoButton.setText 
                      ("Go");
 fClearButton.setEnabled 
                      (true);
 fMakingHist 
                      = false;
 }
 
 } else if (source == fTimer) {
 fUpdateDisplay 
                      = true;
 } else if (source == fClearButton) 
                      {
 fHistogram.clear 
                      ();
 repaint 
                      ();
 } else if (!fInBrowser)
 System.exit 
                      (0);
 } // actionPerformed
 
 /**
 * Create an instance of Histogram 
                      and pass it to the
 * an instance of MakeData. Also, 
                      create an instance of
 * javax.swing.Timer, which will 
                      invoke actionPerformed ()
 * method above and set the fUpdateDisplay 
                      flag every 250ms.
 **/
 void makeHist () {
 if (fMakingHist) return; // only 
                      fill one hist at a time.
 fMakingHist = true;
 
 // Create an instance of the histogram 
                      class.
 // Make it wide enough enough to 
                      include the data.
 if (fHistogram == null)
 fHistogram 
                      = new Histogram ("Gaussian + Random Background",
 "Data",
 20,-10.0,10.0);
 
 // Create the runnable object to 
                      fill the histogram
 // Center signal at 3.0 and create 
                      background between
 // -10 and 10. The fraction of the 
                      data due to the
 // Gaussian will be 0.60. The maximum 
                      delay between
 // data poins will be 500msecs.
 fMakeData =
 new MakeData (this, 
                      fHistogram, fNumDataPoints,
 3.0, 
                      0.60, -10.0, 10.0, 500);
 Thread data_thread = new Thread 
                      (fMakeData);
 
 // Before starting the filling, 
                      create the timer
 // that will cause the histogram 
                      display to update
 // during the filling.
 
 // Send events very 250ms.
 fTimer = new javax.swing.Timer (250,this);
 // Start after 100ms
 fTimer.setDelay (100);
 
 // First start the data filling.
 data_thread.start ();
 
 // Then the timer.
 fTimer.start ();
 
 } // makeHist
 
 /**
 *  Repaint the histogram 
                      display and turn off the
 *  update display flag. 
                      Return the fMakingHist flag
 *  to indicate if updating 
                      should continue.
 **/
 public boolean update (Object obj) {
 // Don't update the display until 
                      the timer
 // turns on the fUpdateDisplay flag.
 if (fUpdateDisplay) {
 // Possible this method 
                      called before fOutputPanel
 // created in the init 
                      (). So check if it exists
 // before attempting 
                      to repaint.
 if (fOutputPanel != 
                      null) fOutputPanel.repaint ();
 fUpdateDisplay = false;
 }
 return fMakingHist;
 } //update
 
 
 /**  Called when the histogram filling 
                      is finished. **/
 public void done () {
 fMakingHist = false;
 
 // Stop the histogram display updates.
 fTimer.stop ();
 
 // Update one last time
 fOutputPanel.repaint ();
 
 // Reset the buttons.
 fGoButton.setText ("Go");
 fClearButton.setEnabled (true);
 
 } // done
 
 public static void main (String[] args) {
 //
 int frame_width=450;
 int frame_height=300;
 
 //
 SwingTimerHistFillApplet applet 
                      = new SwingTimerHistFillApplet ();
 applet.fInBrowser = false;
 applet.init ();
 
 // Following anonymous class used 
                      to close window & exit program
 JFrame f = new JFrame ("Demo");
 f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
 
 // Add applet to the frame
 f.getContentPane ().add ( applet);
 f.setSize (new Dimension (frame_width,frame_height));
 f.setVisible (true);
 } // main
 
 } // class SwingTimerHistFillApplet
 |    Note that since the two timer classes have the same name, so you 
              will need to specify the correct package for the one you choose. 
             See the following references for more about these timer classes 
              and the options they provide.  References 
              & Web Resources Latest update: Nov. 8, 2004 |