2

I used the setText method for the change but it doesn't work. When I debugged my program, I have noticed that the setText() didn't work well as it just shows the last thing while its loop is going to 60 seconds.

For example, I want to see all the numbers from 1 to 60 but It just shows 59.

From what I saw the result of clicking the JButton, I think there don't seem to have problem with the Actionlistener. That's why I changed the logic several times but always happened to the same.

public class Game extends JFrame implements ActionListener {

    JLabel jTimer = new JLabel();//Showing time
    JLabel jScore = new JLabel("");//Showing  score

    Game() {
        JFrame Gframe = new JFrame("Game play");
        Gframe.setBounds(400, 400, 800, 800);
        Gframe.setLayout(null);
        JPanel pScore = new JPanel();

        EtchedBorder border = new EtchedBorder();
        JLabel score = new JLabel(" Score ");
        Font font1 = new Font("굴림", Font.PLAIN, 20);


        jScore.setPreferredSize(new Dimension(5, 5));
        score.setFont(font1);
        score.setBounds(330, 30, 100, 100);
        score.setBorder(border);


        Font font2 = new Font("고딕체", Font.PLAIN, 20);
        JLabel ttime = new JLabel(" Time ");

        JButton start = new JButton("START");
        start.setFont(font2);
        start.setBounds(150, 40, 100, 100);
        start.setBorder(border);
        start.addActionListener(this);

        jTimer.setLayout(null);
        jTimer.setBounds(330, 30, 300, 300);


        ttime.setFont(font2);
        ttime.setBounds(200, 15, 100, 100);
        ttime.setBorder(border);


        pScore.setLayout(new GridLayout(2, 2));
        pScore.setBounds(330, 30, 200, 100);
        pScore.add(score);
        pScore.add(ttime);
        pScore.add(jScore);
        pScore.add(jTimer);
        add(start);
        Gframe.add(pScore);//Including Score&Time
        Gframe.add(start);//Adding Start Butto

        Gframe.setVisible(true);
    }


    public void setTimer() {
        int i = 0;
        while (true) {
            try {
                System.out.println(i);
                jTimer.setText(i + "Sec");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            i++;
            if (i == 60) {
                break;
            }
        }
    }

    // When this method is performed,
    // The result indicates that The println(i) shows correctly as a timer 
    // but jTimer.setText() don't show at all.
    // What's more During the playing time, Jbutton(Start) is clicked until it's finished completely.
    public void actionPerformed(ActionEvent e) {
        String str = e.getActionCommand();
        if (str.equals("START")) {
            System.out.println("Counting");
            setTimer();
        }
    }
}

I expect JLabel(jTimer) shows all the numbers but the actual output is just a previous number.

Madplay
  • 1,027
  • 1
  • 13
  • 25
Akses
  • 21
  • 2
  • 1
    Possible duplicate of [this](https://stackoverflow.com/q/5911204/261156) or [this](https://stackoverflow.com/q/8079782/261156). – Catalina Island Apr 29 '19 at 10:25
  • 2
    *Why does it still show the last number?.* - because code from the ActionListener runs on the `Event Dispatch Thread (EDT)` which is the Thread responsible for responding to events and for repainting the GUI. The Thread.sleep() prevents the GUI from repainting itself until the looping code has finished executing and at that time the value of the text field is the last value that was set. So the solution is to use a [Swing Timer](https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) (not a loop) so you don't prevent the EDT from repainting itself. – camickr Apr 29 '19 at 14:30

2 Answers2

1

Because of the single-threaded nature of Swing, you can not use the loop or Thread.sleep methods.

Therefore, the UI is blocked and it is not updated until the loop completes. Because these updates are executed within the context of the EDT(Event Dispatching Thread), it can be safely used when updating the UI Components.

public class Game extends JFrame implements ActionListener {
    private int count = 0; 
    // ...

    public void setTimer() {
        count = 0; // initialize variable for timer.
        Timer timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                jTimer.setText(count + " Sec");
                count++;
                if(count == 60) {
                    ((Timer)e.getSource()).stop();
                }
            }
        });
        timer.setInitialDelay(0);
        timer.start();

        // When the timer is over
        System.out.println("done!");
    }
}
Madplay
  • 1,027
  • 1
  • 13
  • 25
0

The Problem is in in your setTimer-Method. Your jumping out the loop before you write the time to the label. My suggestion for your Method:

public void setTimer()
{
    int i=0;
    while(i <= 60)
    {              
        try {
            System.out.println(i);       
            jTimer.setText(i+"Sec");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        i++;     
    }
}    

I replaced the loop-condition, so the loop breaks after the time has been updated.

mchl_bld
  • 86
  • 5
  • I tried to that already but it works the same. The things I want to fix now is that when I clicked the button, it has not to be pushed and show the numbers in the setText() in the frame.Why does it still show the last number?. – Akses Apr 29 '19 at 09:25