Hello guys,

Im tring to make a stopwatch display in JTextField but so far i'am unable too :-(.
The stopWatch itself is working perfectly but only in the system output window...

I want the time to be displayed in the textfield(or Label) which is within a JFrame.

I'll appreciate any help and suggestion :-)

Here is the code for the stopWatch.java

package watch;

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

import javax.swing.Timer;



public class Watch
{
      String time = "0";

      int hours = 0;
      int minutes = 0;
      int seconds = 0;
      boolean runTimer = true;

      public Watch()
      {
            Timer timer = new Timer(1000, new TimerListenerClass());
            timer.start();

            while (runTimer)
            {
                        time = hours + minutes + seconds + "";
                        System.out.printf("%2d : %2d : %2d%n", hours, minutes, seconds);
            }
      }

      class TimerListenerClass implements ActionListener
      {

            @Override
            public void actionPerformed(ActionEvent arg0)
            {
                  seconds += 1;

                  if (seconds > 59)
                  {
                        seconds = 0;
                        minutes += 1;
                  }

                  if (minutes > 59)
                  {
                        minutes = 0;
                        hours += 1;
                  }

            }

      }
      public static void main(String[]args)
      {
          new Watch();
      }
}

here is the code for the JFrame

package watch;

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;

/**
 *
 * @author Taimoor
 */
public class Frame extends JFrame
{
    Watch watch;
    JTextField tF;
    public Frame()
    {
        setTitle("text");
        setSize(600,400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        watch = new Watch();
        tF = new JTextField("...",5);
        tF.setText(watch.time);
        add(tF, BorderLayout.CENTER);
        setVisible(true);
    }

    public static void main(String[] args)
    {
        Frame frame = new Frame();
    }

}

You need a mechanism for the UI to get an updated time value. You could either poll the watch on an update timer in your frame (a "pull" model) or you could register your frame as a listener or "observer" in the Watch class (a "push" model) and let Watch notify the frame via a callback method like updateTime() on your frame.

ps: You may want to chose another name for your Frame class since there is already a Frame class in the java.awt package.

Edited 5 Years Ago by Ezzaral: n/a

Hey Ezzaral

I really dont know how to do either of them? is there a special name to this type of situation? so i can google it and learn it...

Well, the first would simply involve creating a getTime() method on your watch class and making a Swing Timer in your frame to call getTime() and update the text field (of course that is somewhat redundant with the watch to begin with eh? :) )

The second is a standard listener or observer pattern. Once you see it you'll recognize that Java uses it quite extensively for event notification (ie MouseListener, ActionListener, etc). Here are several simple examples.

Also,

When ever I run the Frame.java, the JFrame doesn't display. You can only see the timer running in the system output window.

Ezzaral, wouldn't the following adjustment to the Frame.java work? I'm tell the panel to revalidate every second...

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package watch;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

/**
 *
 * @author Taimoor
 */
public class Frame extends JFrame
{
    Watch watch;
    JTextField tF;
    JPanel panel;
    Timer timer;
    public Frame()
    {
        setTitle("text");
        setSize(600,400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        watch = new Watch();
        panel = new JPanel();
        timer = new Timer(1000,new Listener());

        panel.add(tF);
        tF = new JTextField("...",5);
        tF.setText(watch.time);
        add(tF, BorderLayout.CENTER);
        setVisible(true);
        timer.start();
    }

    class Listener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            panel.revalidate();
        }
    }

    public static void main(String[] args)
    {
        Frame frame = new Frame();
    }

}

No, revalidate() is for layout changes such as adding or removing components in a container. You are needing to setText() on your text field again with the updated time value.

pack that

tF.setText(watch.time);

into invokeLater,

repaint(); if JTextField flickering

Edited 5 Years Ago by mKorbel: n/a

He should be able to do that directly within her Timer because the Swing Timer executes on the event dispatch thread. I don't think the invokeLater will be needed.

Edited 5 Years Ago by Ezzaral: n/a

Shouldn't my TextField(tF) update since i'm using tF.setText() method??? You can see below where and how im using it(it is underlined).
Also like i mentioned before,the timer is actually running in the System output area and the textField does not appear.

I wanna thank you guys for your help.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package watch;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

/**
 *
 * @author Taimoor
 */
public class Frame extends JFrame
{
    Watch watch;
    JTextField tF;
    JPanel panel;
    Timer timer;

    public Frame()
    {
        setTitle("Test");
        setSize(600,400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        setVisible(true);

        watch = new Watch();
        panel = new JPanel();
       [U] [B]timer = new Timer(1000, new Listener());[/B][/U]
        tF = new JTextField("...");
        add(tF, BorderLayout.CENTER);
    }

[U][B]    class Listener implements ActionListener
    {

 
       public void actionPerformed(ActionEvent e)
        {
            tF.setText(watch.time);
        }

    }[/B][/U]
    public static void main(String[] args)
    {
        Frame frame = new Frame();
    }

}

here's the code for the stopWatch.

package watch;

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

import javax.swing.Timer;



public class Watch
{
      String time = "0";
      boolean runTimer = true;

      int hours = 0;
      int minutes = 0;
      int seconds = 0;



      public Watch()
      {
            Timer timer = new Timer(1000, new TimerListenerClass());
            timer.start();
            while (runTimer)
            {
                time = hours + minutes + seconds + "";
                System.out.printf("%2d : %2d : %2d%n", hours, minutes, seconds);
            }
    }

      class TimerListenerClass implements ActionListener
      {

            @Override
            public void actionPerformed(ActionEvent arg0)
            {
                  seconds += 1;

                  if (seconds > 59)
                  {
                        seconds = 0;
                        minutes += 1;
                  }

                  if (minutes > 59)
                  {
                        minutes = 0;
                        hours += 1;
                  }
            }

      }
}

Edited 5 Years Ago by Taimoor Rana: n/a

Several things:
As mKorbel mentioned above, you need to pack() your Frame after adding the components to it.
You never start the timer in Frame.
You have an infinite loop in the Watch constructor and the timer that is updating the time never actually changes the "time" string.

I'd say you have a bit more to work on there.

Ezzaral mentioned the infinite loop (why bother CHECKING for changes when you know EXACTLY WHEN things change (i.e. when the timer goes off. Display a printout or update the JTextField only when the time CHANGES). The constant checking and printing hogs a lot of resources. That may not have adverse effects, but it certainly can't help.

Second, I don't know much about how accurate javax.swing.Timer is, but I imagine it loses time. Why not use a Date object instead? You can still update everything when the Timer goes off, but the underlying elapsed time will be at least as accurate as the repeated javax.swing.Timer updates/firings and possibly better. Again, I don't know the underlying reliability of javax.swing.Timer, but I've never seen any app that kept accurate time rely on it. It might be interesting to time your app with a stopwatch and see how reliable the timing is.

But for sure get rid of that while loop. You already have a listener, so the while loop is redundant and wastes resources.

http://download.oracle.com/javase/6/docs/api/java/util/Date.html

Edited 5 Years Ago by VernonDozier: n/a

I Finally got it to WORK!!!!!!! by using debugging :-). Like you guys mentioned, there was an infinite loop. Which prevented the Frame from appearing. I've rearranged my code and got the timer to work in textfield.

Thank you everyone for suggestion and pointers <3

This question has already been answered. Start a new discussion instead.