0

I'm trying to display the current time in a JFrame. How can I refresh the text in the JLabel without opening a separate frame each time it has to update?

Here's all of my code so far...

Test

public class Test{

    static String timeDisplay = "";

    public static class time extends Thread{
        static int timeHours = 7;
        static int timeMins = 30;
        static int timeSecs = 0;
        @Override
        public void run(){

            while(true){
                try{

                    time.sleep(1000);
                    timeSecs++;

                    if(timeSecs == 60){
                        timeMins++;
                        timeSecs = 0;
                    }
                    if(timeMins == 60){
                        timeHours++;
                        timeMins = 0;
                    }

                    if(timeHours < 10){
                        if(timeMins < 10){
                            if(timeSecs < 10){
                                timeDisplay = "0" + timeHours + ":" + "0" + timeMins + ":" + "0" + timeSecs;
                            }
                            else{
                                timeDisplay = "0" + timeHours + ":" + "0" + timeMins + ":" + timeSecs;
                            }
                        }
                        else{
                            if(timeSecs < 10){
                                timeDisplay = "0" + timeHours + ":" + timeMins + ":" + "0" + timeSecs;
                            }
                            else{
                                timeDisplay = "0" + timeHours + ":" + timeMins + ":" + timeSecs;
                            }
                        }
                    }
                    else{
                        if(timeMins < 10){
                            if(timeSecs < 10){
                                timeDisplay = timeHours + ":" + "0" + timeMins + ":" + "0" + timeSecs;
                            }
                            else{
                                timeDisplay = timeHours + ":" + "0" + timeMins + ":" + timeSecs;
                            }
                        }
                        else{
                            if(timeSecs < 10){
                                timeDisplay = timeHours + ":" + timeMins + ":" + "0" + timeSecs;
                            }
                            else{
                                timeDisplay = timeHours + ":" + timeMins + ":" + timeSecs;
                            }
                        }
                    }

                    System.out.println(timeDisplay);
                    //CountDown time = new CountDown(timeDisplay);


                }
                catch(Exception e){
                    System.out.println("Something went wrong :(");
                }
            }

        }

    }

    public static void main(String[] args){

        time time = new time();
        time.start();
            try {
                TimeUnit.SECONDS.sleep(1);
                CountDown window = new CountDown(timeDisplay);
                window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                window.setSize(500, 500);
                window.setVisible(true);
            }
            catch (Exception e) {
                e.printStackTrace();
            }

    }

}

CountDown

public class CountDown extends JFrame{

    private static final long serialVersionUID = 1L;

    static JLabel label = new JLabel();

    public CountDown(String time){

        super("Title");
        setLayout(new FlowLayout());

        add(label);
        label.setText("Current Time: " + time);

        Handler eventHandler = new Handler();

    }

    private class Handler implements ActionListener{

        public void actionPerformed(ActionEvent event){

            String string = "";

            if(event.getSource()==""){
                string = String.format("label 1: %s", event.getActionCommand());
            }

        }

    }

}

My intentions for this program was to make a frame that displayed the current time. It's using local time from the program, not the actual time. Thanks in advance, and feel free to let me know if I should change anything in my code to make it better.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 2
    You're going to want to start by having a look at [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) and [How to use Swing Timers](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) for more details about a better solution, Swing is single threaded and you should never attempt to modify the UI from outside the content of the Event Dispatching Thread – MadProgrammer Feb 22 '17 at 02:42
  • 1
    You're also trying to compare the ActionEvent's source to the wrong type of object -- a String, and incorrectly -- using the `==` operator. – Hovercraft Full Of Eels Feb 22 '17 at 02:44
  • `if(event.getSource()==""){` is dangerous and confusing, `event.getSource()` returns an `Object`, it was a `String` then `==` is likely to fail as `String` comparison doesn't work this way – MadProgrammer Feb 22 '17 at 02:44
  • May be have a look at [this example](http://stackoverflow.com/questions/35714257/i-dont-know-how-to-display-timer-when-stopped/35714415#35714415) and [this example](http://stackoverflow.com/questions/35714257/i-dont-know-how-to-display-timer-when-stopped/35714415#35714415) for more ideas – MadProgrammer Feb 22 '17 at 02:46
  • 1) @MadProgrammer *"look at this example and this example"* Such a good example, you thought you'd link it twice? I guess it was a 'copy/pate typo. 2) OP. The basic problem seems to come down to scope. in that the `Test` class does not seem to have a reference to the label, or any object instance that provides methodology to update the label. Does the specification explicitly call for two classes? If not, see [`ClockFrame`](http://stackoverflow.com/a/42266840/418556). – Andrew Thompson Feb 22 '17 at 03:03
  • 1
    @AndrewThompson Ops, should be [this](http://stackoverflow.com/questions/35714257/i-dont-know-how-to-display-timer-when-stopped/35714415#35714415) and [that](http://stackoverflow.com/questions/14678750/java-label-timer-and-saving/14678873#14678873) :P – MadProgrammer Feb 22 '17 at 03:07
  • @MadProgrammer Ah ..crap. I'd already upvoted *that*. – Andrew Thompson Feb 22 '17 at 03:15

2 Answers2

0

The API Docs will be your friend. Take a look at the documentation for JLabel, particularly the method setText(). You can use this method again in your event handler to change the text of your label.

But another problem you have is that you are neither firing nor registering for events, so that actionPerformed function you have written is never being called. If second-accuracy is good enough, you could simplify your code greatly, using javax.swing.Timer. Without changing your code where unnecessary, this should get you on the right path:

public class CountDown extends JFrame{

    private static final long serialVersionUID = 1L;

    private JLabel label = new JLabel(); // note: understand static keyword before using it.

    private long startTime = System.currentTimeMillis(); // gets the current time in milliseconds, when your class is initialized.

    public CountDown(String time){

        super("Title");
        setLayout(new FlowLayout());

        add(label);
        // label.setText("Current Time: " + time); "time" was never in scope here.

        Handler eventHandler = new Handler();
        new Timer(1000, eventHandler).start(); // will execute ~1/sec
    }

    private class Handler implements ActionListener{

        public void actionPerformed(ActionEvent event){

              // NOTE: here, you could put all of your logic that was previously
              // in your Thread to determine the time, then use the result
              // with label.setText();
              long currentTime = System.currentTimeMillis();

              long upTime = currentTime - startTime; // this is how many milliseconds your JFrame has been up and running.

              // TODO: formate upTime however you desire.

              label.setText( <whatever_you_calculate_directly_above> );
            }

        }

    }

}

You will also need to rewrite your main method to initialized your Frame. That should do it.

public static void main( String[] args){
  JFrame frame = new CountDown(); 
  frame.setVisible(true);
}

If your main method is in a separate file, you will need to import CountDown near the beginning of that file.

sethro
  • 2,127
  • 1
  • 14
  • 30
0

You should first create an instance of CountDown and then call one of its method setting the text of the label.

In CountDown you have to call the JLabel.setText. method to set the label's text:

public void displayTime(String time){
   label.setText("Current Time: " + time);
}

...and instead of System.out.println(time) call

time.displayTime(timeDisplay);

Instead of using a simple thread , you'd better use a java.util.Timer or even better a javax.swing.Timer that is better suited for gui objects.

Another remark: class names begin by an upper case letter while methods or variables begin by a lower case method.

Finally what has your handler to do here. You don't register it and it seems useless.

C.Champagne
  • 5,381
  • 2
  • 23
  • 35
  • Creating a method `displayTime` and then calling it from a `Thread` is not good practice in a Swing application. You want your UI updates to occur in the Event Dispatch Thread. Your other suggestion, to use javax.swing.Timer seems much better for this scenario. – sethro Feb 22 '17 at 03:20
  • @sethro I agree. In fact I first considered directly talking about javax.swing.timer but I then thought it could be clearer to proceed step by step. I don't know if I did well though. – C.Champagne Feb 22 '17 at 03:31