views:

86

answers:

1

I am trying to write the simples GUI countdown. I found in Internet some code but it is already too fancy for me. I am trying to keep it as simple as possible. So, I just want to have a window saying "You have 10 second left". The number of second should decrease every second from 10 to 0. I wrote a code. And I think I am close to the working solution. But I still missing something. Could you pleas help me to find out what is wrong? Here is my code:

import javax.swing.*;

public class Countdown {

    static JLabel label;

    // Method which defines the appearance of the window.   
    private static void showGUI() {
        JFrame frame = new JFrame("Simple Countdown");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JLabel label = new JLabel("Some Text");
        frame.add(label);
        frame.pack();
        frame.setVisible(true);
    }

    // Define a new thread in which the countdown is counting down.
    static Thread counter = new Thread() {
        public void run() {
            for (int i=10; i>0; i=i-1) {
                updateGUI(i,label);
                try {Thread.sleep(1000);} catch(InterruptedException e) {};
            }
        }
    };

    // A method which updates GUI (sets a new value of JLabel).
    private static void updateGUI(final int i, final JLabel label) {
        SwingUtilities.invokeLater(new Runnable(i,label) {

            public Runnable(int i, JLabel label) {
                this.i = i;
                this.label = label;
            }

            public void run() {
                label.setText("You have " + i + " seconds.");
            }

        });
    }

    // The main method (entry point).
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                showGUI();
                //counter.start();
            }
        });
        //counter.start();
    }

}

And I have several concrete question about this code:

  1. Where should I place the counter.start();? (In my code I put it on 2 places. Which one is correct?)

  2. Why compiler complains about the constructor for Runnable? It says that I have an invalid method declaration and I need to specify the returned type.

ADDED: I made the suggested corrections. And then I execute the code and get:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Worker.run(Worker.java:12)

In the Worker.java in the line 12 I have: label.setText("You have " + i + " seconds.");.

+2  A: 

Call counter.start() inside the runnable:

// The main method (entry point).
public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            showGUI();
            counter.start();
        }
    });
}

You really want a specific order of invocation, if you place it outside the thread then the counter will start even before the GUI exists and it will fail on you.

For the second question:

// A method which updates GUI (sets a new value of JLabel).
private static void updateGUI(final int i, final JLabel label) {
    SwingUtilities.invokeLater(new Worker(i, label));
}

Here is the worker:

import javax.swing.JLabel;

public class Worker implements Runnable{
    private int i;
    private JLabel label;
    public Worker(int i, JLabel label) {
        this.i = i;
        this.label = label;
    }

    public void run() {
        label.setText("You have " + i + " seconds.");
    }
}

And your main now:

// The main method (entry point).
public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            Countdown.showGUI();
            counter.start();
        }
    });
}

UPDATE:
Or if you still want to use the anonymous pattern then:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Countdown {

    static JLabel label;

    // Method which defines the appearance of the window.   
    public static void showGUI() {
        JFrame frame = new JFrame("Simple Countdown");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        label = new JLabel("Some Text");
        frame.add(label);
        frame.pack();
        frame.setVisible(true);
    }

    // Define a new thread in which the countdown is counting down.
    public static Thread counter = new Thread() {
        public void run() {
            for (int i=10; i>0; i=i-1) {
                updateGUI(i,label);
                try {Thread.sleep(1000);} catch(InterruptedException e) {};
            }
        }
    };

    // A method which updates GUI (sets a new value of JLabel).
    private static void updateGUI(final int i, final JLabel label) {
        SwingUtilities.invokeLater( 
            new Runnable() {
                public void run() {
                    label.setText("You have " + i + " seconds.");
                }
            }
        );
    }
}
Lirik