簡體   English   中英

如何在按下同一個按鈕時重置倒數計時器

[英]How to reset a countdown timer when the same button is pressed

所以我正在制作這款游戲,讓玩家有 30 秒的時間來選擇答案。 如果他們選擇一個選項,計時器將重置為 30 秒。

@Override
public void actionPerformed(ActionEvent e) {

    //the idea is that when this button is clicked, the timer starts.
    if(e.getSource() == button) {

        //random gui stuff which i won't include



        //calls the method for timer
        runner(); 

        

        }

這是我的 runner() 方法:

public void runner() {

    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    final Runnable runnable = new Runnable() {
        
        int countdownStarter = 30;

        public void run() {

            

            //this is my JLabel that prints out the timer
            label.setText("" + countdownStarter);
            
            countdownStarter--;

            if (countdownStarter < 0) {


                label.setText("");

                /*Random GUI stuff here I won't show*/ 

                scheduler.shutdown();
            }
        }

我的問題是,當單擊按鈕時計時器確實運行但是它創建了一個新的“計時器”所以在我的 GUI 上它只是在兩個不同的時間之間閃爍。 例如,如果已經存在的計時器為 5 秒(左)並且我單擊按鈕,則 JLabel 文本在 5/30、4/29、3/28、2/27 之間閃爍,但實際上我只是想要它停止現有的計時器。

不確定我能做什么,我真的很感激任何幫助,因為我對 swing 和 gui 東西還很陌生。

謝謝!

從分離您的關注點開始。

您有一種機制需要跟蹤按鈕何時被觸發以及它應該倒計時的時間量,並且您有一些更新 UI 的機制。

第一部分非常簡單,您可以簡單地利用java.time API,例如...

public class CountdownTimer {
    private Instant startedAt;
    private Duration duration;

    public CountdownTimer(Duration duration) {
        this.duration = duration.plusSeconds(1);
    }

    public boolean isRunning() {
        return startedAt != null;
    }

    public void start() {
        if (startedAt != null) {
            return;
        }
        startedAt = Instant.now();
    }

    public void stop() {
        startedAt = null;
    }
    
    public Duration getTimeRemaining() {
        return duration.minus(getRunTime());
    }

    public Duration getRunTime() {
        if (startedAt == null) {
            return null;
        }
        return Duration.between(startedAt, Instant.now());
    }
}

因此,基於“錨定”時間,您可以計算“運行時間”,然后從中計算“剩余時間”,很簡單。 現在,要重置它,您只需調用stopstart

接下來,我們需要一些方法來更新 UI。 Swing 是單線程的並且不是線程安全的,這意味着您不能在事件調度線程的上下文中運行長時間運行或阻塞操作,並且您不應該更新 UI 或 UI 所依賴的任何 state事件調度線程的一側。

最好的選擇是使用Swing Timer ,例如......

public class CountdownPane extends JPanel {

    private CountdownTimer countdownTimer;
    private Timer timer;

    public CountdownPane() {
        countdownTimer = new CountdownTimer(Duration.ofSeconds(5));
        JButton btn = new JButton("Destory the world");
        timer = new Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Duration duration = countdownTimer.getTimeRemaining();
                long seconds = duration.toSecondsPart();
                if (seconds <= 0) {
                    countdownTimer.stop();
                    timer.stop();
                    btn.setText("Boom");
                } else {
                    btn.setText(format(duration));
                }
            }
        });
        timer.setInitialDelay(0);
        setLayout(new GridBagLayout());
        setBorder(new EmptyBorder(36, 36, 36, 36));
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (countdownTimer.isRunning()) {
                    countdownTimer.stop();
                    timer.stop();
                    btn.setText("Destory the world");
                } else {
                    countdownTimer.start();
                    timer.start();
                }
            }
        });
        add(btn);
    }

    protected String format(Duration duration) {
        long seconds = duration.toSecondsPart();
        return String.format("%02d seconds", seconds);
    }
}

可運行的例子...

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new CountdownPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class CountdownPane extends JPanel {

        private CountdownTimer countdownTimer;
        private Timer timer;

        public CountdownPane() {
            countdownTimer = new CountdownTimer(Duration.ofSeconds(5));
            JButton btn = new JButton("Destory the world");
            timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Duration duration = countdownTimer.getTimeRemaining();
                    long seconds = duration.toSecondsPart();
                    if (seconds <= 0) {
                        countdownTimer.stop();
                        timer.stop();
                        btn.setText("Boom");
                    } else {
                        btn.setText(format(duration));
                    }
                }
            });
            timer.setInitialDelay(0);
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(36, 36, 36, 36));
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (countdownTimer.isRunning()) {
                        countdownTimer.stop();
                        timer.stop();
                        btn.setText("Destory the world");
                    } else {
                        countdownTimer.start();
                        timer.start();
                    }
                }
            });
            add(btn);
        }

        protected String format(Duration duration) {
            long seconds = duration.toSecondsPart();
            return String.format("%02d seconds", seconds);
        }
    }

    public class CountdownTimer {
        private Instant startedAt;
        private Duration duration;

        public CountdownTimer(Duration duration) {
            this.duration = duration.plusSeconds(1);
        }

        public boolean isRunning() {
            return startedAt != null;
        }

        public void start() {
            if (startedAt != null) {
                return;
            }
            startedAt = Instant.now();
        }

        public void stop() {
            startedAt = null;
        }

        public Duration getTimeRemaining() {
            return duration.minus(getRunTime());
        }

        public Duration getRunTime() {
            if (startedAt == null) {
                return null;
            }
            return Duration.between(startedAt, Instant.now());
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM