【问题标题】:How to make Timer countdown along with progress bar?如何使计时器倒计时和进度条一起?
【发布时间】:2011-05-09 02:32:24
【问题描述】:

如何让进度条随着时间限制慢慢下降?

class GamePanel extends JPanel implements MouseListener, ActionListener
{
    private JButton quit;
    private JButton q;
    private Font loadFont;

    public GamePanel()
    {
        setBackground(Color.blue); // sets background color
        this.setLayout(null);
        quit = new JButton("Quit");
        quit.addActionListener(this);
        quit.setBounds(550, 700, 100, 30);
        this.add(quit);

        q = new JButton("Questions");
        q.addActionListener(this);
        q.setBounds(100, 100, 120, 30);
        this.add(q);

        loadFont = new Font("Serif", Font.PLAIN, 30);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.black);
        g.fillRect(80, 100, 610, 560);
        g.setColor(Color.white);
        g.fillRect(90, 110, 110, 100);// 1st column
        g.fillRect(90, 220, 110, 100);//
        g.fillRect(90, 330, 110, 100);//
        g.fillRect(90, 440, 110, 100);//
        g.fillRect(90, 550, 110, 100);//
        g.fillRect(210, 110, 110, 100);// 2nd column
        g.fillRect(210, 220, 110, 100);//
        g.fillRect(210, 330, 110, 100);//
        g.fillRect(210, 440, 110, 100);//
        g.fillRect(210, 550, 110, 100);//
        g.fillRect(330, 110, 110, 100);// 3rd column
        g.fillRect(330, 220, 110, 100);//
        g.fillRect(330, 330, 110, 100);//
        g.fillRect(330, 440, 110, 100);//
        g.fillRect(330, 550, 110, 100);//
        g.fillRect(450, 110, 110, 100);// 4th column
        g.fillRect(450, 220, 110, 100);//
        g.fillRect(450, 330, 110, 100);//
        g.fillRect(450, 440, 110, 100);//
        g.fillRect(450, 550, 110, 100);//
        g.fillRect(570, 110, 110, 100);// 5th column
        g.fillRect(570, 220, 110, 100);//
        g.fillRect(570, 330, 110, 100);//
        g.fillRect(570, 440, 110, 100);//
        g.fillRect(570, 550, 110, 100);//
        g.setColor(Color.green);
        g.setFont(loadFont);
        g.drawString(input + ":", 100, 710);
    }

    public void actionPerformed(ActionEvent e)
    {
        String order = e.getActionCommand();
        if(order.equals("Quit"))
            cards.show(c, "Introduction");
        if(order.equals("Questions"))
            cards.show(c, "Questions");
    }

    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
}

class QuestionPanel extends JPanel implements ActionListener
{
    private long startTime, elapsedTime;
    private Timer timer;
    private int countdown;
    private Font loadFont;

    public QuestionPanel()
    {
        setBackground(Color.pink); // sets background color
        this.setLayout(null);  // moved into constructor from ActionPerformed: only change layout in constructor
        startTime = 0;
        elapsedTime = 0;
        countdown = 590;
        loadFont = new Font("Segoe Script", Font.BOLD, 20);
        if(timer == null)
        {// use the biggest value possible that provides your desired time keeping precision (usually no less than 15 on Windows)
            timer = new Timer(100, this);  
            startTime = System.currentTimeMillis();  // gets start time in milliseconds
            timer.start();
        }
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.fillRect(100, 100, 600, 25);
        g.setColor(Color.green);
        g.fillRect(105, 105, countdown, 15);
        g.setColor(Color.black);
        g.setFont(loadFont);
        g.drawString("" + ((System.currentTimeMillis() - startTime) / 1000.0), 100, 80);  // display remaining time
    }

    public void actionPerformed(ActionEvent e)
    {
        String command = e.getActionCommand();
        elapsedTime = System.currentTimeMillis() - startTime;
        if(elapsedTime < (5000))
        {
            countdown--;
            repaint();
        }
        else
        {
            timer.stop();
            if(timer == null)
            {
                timer = new Timer(500, this);
                timer.start();
            }
        }
        if(elapsedTime >= (5000))  // can't use == here because of limited precision of system clock
            cards.show(c, "Correct!");
    }
}

class AnswerPanel extends JPanel implements ActionListener
{
    private JButton revert;

    public AnswerPanel()
    {
        setBackground(Color.yellow); // sets background color
        this.setLayout(null);
        revert = new JButton("Back");
        revert.addActionListener(this);
        revert.setBounds(340, 700, 100, 30);
        this.add(revert);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
    }

    public void actionPerformed(ActionEvent e)
    {
        String directive = e.getActionCommand();
        if(directive.equals("Back"))
            cards.show(c, "Start");
    }
}

class FailPanel extends JPanel implements ActionListener
{
    private JButton turnaround;

    public FailPanel()
    {
        setBackground(Color.green); // sets background color
        this.setLayout(null);
        turnaround = new JButton("Back");
        turnaround.addActionListener(this);
        turnaround.setBounds(340, 700, 100, 30);
        this.add(turnaround);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
    }

    public void actionPerformed(ActionEvent e)
    {
        String bidding = e.getActionCommand();
        if(bidding.equals("Back"))
            cards.show(c, "Start");
    }
}
}// end of the entire program

【问题讨论】:

  • 我希望人们看看 QuestionPanel。我正在尝试让计时器倒计时,而进度条也在下降。当计时器达到 0 时(从 5 开始后),应该会显示另一个面板。另一个问题是计时器在我到达那个面板之前就开始了。我希望能够控制计时器何时开始。
  • 文字的圣墙,蝙蝠侠!我会尝试将问题压缩为尽可能小的示例。
  • 我强烈支持 TFRM 的建议。这只是太多的代码。你将不得不付出一些努力来使它变得更小和易于理解,但它的努力是值得的。否则很多人会在周日晚上做一些比阅读 3 卷代码书更好的事情。
  • @thynoob:我有 5 封信给你SSCCE。准备一份 SSCCE,问题(以及解决方案)很可能会在您这样做时变得清晰。如果这没有发生,至少你会有一小段代码,其他人可能会更仔细地查看。实际上,您要求我们搜索近 450 行代码以查找错误。您的请求很可能会被忽略。 @HFOE 感谢您格式化代码。
  • 您的程序也会因您这样做而受益,因为它可以帮助您实现将程序逻辑与 GUI 代码分离的目标。此外,您将希望摆脱所有绝对定位和大小调整,转而使用布局管理器,特别是如果您希望具有不同大小的显示器和屏幕分辨率的人能够看到您的 gui。例如,我无法完全看到它。

标签: java swing timer long-integer jprogressbar


【解决方案1】:

抱歉,我仍然找不到真正阅读您的代码的动机,只是根据问题将这个示例放在一起。看看它是否能给你一些想法。

请注意,它是一个 SSCCE,总共只使用了 40 行代码。

import java.awt.event.*;
import javax.swing.*;

class CountDownProgressBar {

    Timer timer;
    JProgressBar progressBar;

    CountDownProgressBar() {
        progressBar = new JProgressBar(JProgressBar.VERTICAL, 0, 10);
        progressBar.setValue(10);
        ActionListener listener = new ActionListener() {
            int counter = 10;
            public void actionPerformed(ActionEvent ae) {
                counter--;
                progressBar.setValue(counter);
                if (counter<1) {
                    JOptionPane.showMessageDialog(null, "Kaboom!");
                    timer.stop();
                } 
            }
        };
        timer = new Timer(1000, listener);
        timer.start();
        JOptionPane.showMessageDialog(null, progressBar);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                CountDownProgressBar cdpb = new CountDownProgressBar();
            }
        });
    }
}

【讨论】:

  • @thynoob:Andrews 代码不仅仅是简短的,它还是可编译、可运行和可测试的。由于它很简短,我们可以很快理解它。由于它可以编译并运行,我们都可以在不修改的情况下运行此代码,对其进行修改、改进并在短时间内修复其中的任何错误。
【解决方案2】:

从外观上看,所有这些代码都在一个大 Java 文件中?这是个坏主意。

您应该有充分的理由将一个类定义为内部类,并且从外观上看,您没有为 QuestionPanel 和其他类定义的。

至于问题,每次更新计数器时都会调用您的 paintComponent 方法,现在大约每 0.1 秒一次,但每次更新时您只滴答 1 个像素,所以到 5 秒结束,您已经剪掉了 10*5 像素 (50)。您应该做的是通过不同的机制更新进度条,例如计算当前处理的时间:

long processed = System.currentTimeMillis() - startTime;
double percent = Math.max(0, 1 - processed / 5000.0);
int width = (int)(590 * percent);

【讨论】:

  • 为什么不简单地使用 JProgressBar?
  • 我想这是为了分配任务,否则我同意你的看法。
  • 我很欣赏你的输入 pickypg 但有没有办法让显示的剩余时间从 5 秒开始?
  • 是的,更改绘制时间左字符串的最后一行。 double remaining = 5 * percent; g.drawString(String.format("%.2f", remaining), 100, 80);
  • 所以我将你刚刚给的最后一行代码替换为你首先给我的代码的最后一行?然后我使用我的变量将它放入我的代码中,一切都应该没问题吗? o__o
【解决方案3】:

这绝对是太多的信息,而且是一个非常广泛的问题。我会说你最多只需要包含计时器所在类的代码,以及绘制进度条的类。

通过浏览代码,我猜您正在使用矩形来绘制进度条。基于此,您可以采取的一种方法是使用变量来存储条的宽度,并且每次计时器滴答时,将条的宽度减小一定量。然后只需将绘制的矩形的宽度设置为存储在变量中的值即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多