教程:将计时器添加到数学测验 WinForms 应用

在此系列教程中,你将生成一个数学测验。 测验包含四个随机数学问题,测验者尝试在指定时间内回答。

测验使用计时器控件。 此控件背后的代码跟踪经过的时间,并检查测验参与者的答案。

在本第三个教程中,你将了解如何:

  • 添加计时器控件。
  • 为计时器添加事件处理程序。
  • 编写代码以检查用户的答案、显示消息并填写正确的答案。

先决条件

本教程基于前面的教程,从 创建数学测验 WinForms 应用开始。 如果尚未完成这些教程,请先完成这些教程。

添加倒计时计时器

若要跟踪测验期间的时间,请使用计时器组件。 还需要一个变量来存储剩余的时间量。

  1. 添加一个名为 timeLeft 的整数变量,其方式与在前面的教程中声明变量的方式相同。 将 timeLeft 声明放在其他声明之后。 代码应如以下示例所示。

    public partial class Form1 : Form
    {
        // Create a Random object called randomizer 
        // to generate random numbers.
        Random randomizer = new Random();
    
        // These integer variables store the numbers 
        // for the addition problem. 
        int addend1;
        int addend2;
    
        // These integer variables store the numbers 
        // for the subtraction problem. 
        int minuend;
        int subtrahend;
    
        // These integer variables store the numbers 
        // for the multiplication problem. 
        int multiplicand;
        int multiplier;
    
        // These integer variables store the numbers 
        // for the division problem. 
        int dividend;
        int divisor;
    
        // This integer variable keeps track of the 
        // remaining time.
        int timeLeft;
    

  1. Windows 窗体设计器中,将 Timer 控件从 工具箱组件 类别移动到窗体中。 该控件显示在设计窗口底部的灰色区域中。

  2. 在表单上,选择刚添加的 timer1 图标,并将它的 Interval 属性设置为 1000。 由于此间隔以毫秒为单位,因此值 1000 会导致计时器每秒引发 Tick 事件。

检查答案

由于计时器每秒会引发 Tick 事件,因此检查 Tick 事件处理程序中的已用时间是有意义的。 检查该事件处理程序中的答案也是可行的。 如果时间已用完,或者答案正确,测验应结束。

在编写该事件处理程序之前,请添加一个名为 CheckTheAnswer() 的方法,以确定数学问题的答案是否正确。 此方法应与其他方法一致,例如 StartTheQuiz()。 代码应如以下示例所示。

/// <summary>
/// Check the answers to see if the user got everything right.
/// </summary>
/// <returns>True if the answer's correct, false otherwise.</returns>
private bool CheckTheAnswer()
{
    if ((addend1 + addend2 == sum.Value)
        && (minuend - subtrahend == difference.Value)
        && (multiplicand * multiplier == product.Value)
        && (dividend / divisor == quotient.Value))
        return true;
    else
        return false;
}

此方法确定数学问题的答案,并将结果与 NumericUpDown 控件中的值进行比较。 在此代码中:

  • Visual Basic 版本使用 Function 关键字而不是通常的 Sub 关键字,因为此方法返回一个值。

  • 无法使用键盘轻松输入乘法符号(×)和除号(÷),因此 C# 和 Visual Basic 接受星号 (*) 进行乘法和斜杠标记 (/) 进行除法。

  • 在 C# 中,&&logical and 运算符。 在 Visual Basic 中,AndAlso是等效运算符。 使用 logical and 运算符检查多个条件是否为 true。 在这种情况下,如果值都正确,该方法将返回一个值 true。 否则,该方法返回 false值。

  • if 语句使用 NumericUpDown 控件的 Value 属性来访问控件的当前值。 在下一部分中,使用同一属性在每个控件中显示正确的答案。

将事件处理程序添加到计时器

有了检查答案的方法后,可以编写 Tick 事件处理程序的代码。 计时器引发 Tick 事件后,此代码每秒运行一次。 此事件处理程序通过调用 CheckTheAnswer()来检查测验者答案。 它还检查测验已消耗的时间。

  1. 在窗体中,双击“计时器”控件,或将其选中,然后选择 Enter。 这些操作添加 Tick 事件处理程序。 代码编辑器将出现并显示 Tick 处理程序的方法。

    对于 C#,它会在连接事件处理程序的 Form1.Designer.cs 代码文件中添加一行代码:

    timer1.Tick += new EventHandler(timer1_Tick);
    

    (对于 Visual Basic,不需要该行,但事件处理程序包含执行相同操作的 handles Timer1.Tick

  2. 将以下语句添加到新的事件处理程序方法。

    private void timer1_Tick(object sender, EventArgs e)
    {
        if (CheckTheAnswer())
        {
            // If CheckTheAnswer() returns true, then the user 
            // got the answer right. Stop the timer  
            // and show a MessageBox.
            timer1.Stop();
            MessageBox.Show("You got all the answers right!",
                            "Congratulations!");
            startButton.Enabled = true;
        }
        else if (timeLeft > 0)
        {
            // If CheckTheAnswer() returns false, keep counting
            // down. Decrease the time left by one second and 
            // display the new time left by updating the 
            // Time Left label.
            timeLeft = timeLeft - 1;
            timeLabel.Text = timeLeft + " seconds";
        }
        else
        {
            // If the user ran out of time, stop the timer, show
            // a MessageBox, and fill in the answers.
            timer1.Stop();
            timeLabel.Text = "Time's up!";
            MessageBox.Show("You didn't finish in time.", "Sorry!");
            sum.Value = addend1 + addend2;
            difference.Value = minuend - subtrahend;
            product.Value = multiplicand * multiplier;
            quotient.Value = dividend / divisor;
            startButton.Enabled = true;
        }
    }
    

此方法在测验期间每秒运行一次。 代码首先检查 CheckTheAnswer() 返回的值。

  • 如果所有答案正确,则该值为 true,测验结束。

    • 计时器停止。
    • 屏幕上会显示一条祝贺信息。
    • startButton 控件的“已启用”属性将设置为 true,以便测验者可以开始其他测试
  • 如果 CheckTheAnswer() 返回 false,代码将检查 的 timeLeft 值

    • 如果此变量大于 0,计时器将从 timeLeft中减去 1。 它还更新 timeLabel 控件的 Text 属性,以显示测验者剩余的秒数。
    • 如果没有剩余时间,计时器将停止并更改 timeLabel 控件的文本,使之显示“时间到!”一个消息框宣布测验结束,并显示答案。 “开始”按钮将再次可用。

启动计时器

若要在测验启动时启动计时器,请将三行添加到 StartTheQuiz() 方法的末尾,如以下示例所示。

/// <summary>
/// Start the quiz by filling in all of the problem 
/// values and starting the timer. 
/// </summary>
public void StartTheQuiz()
{
    // Fill in the addition problem.
    // Generate two random numbers to add.
    // Store the values in the variables 'addend1' and 'addend2'.
    addend1 = randomizer.Next(51);
    addend2 = randomizer.Next(51);

    // Convert the two randomly generated numbers
    // into strings so that they can be displayed
    // in the label controls.
    plusLeftLabel.Text = addend1.ToString();
    plusRightLabel.Text = addend2.ToString();

    // 'sum' is the name of the NumericUpDown control.
    // This step makes sure its value is zero before
    // adding any values to it.
    sum.Value = 0;

    // Fill in the subtraction problem.
    minuend = randomizer.Next(1, 101);
    subtrahend = randomizer.Next(1, minuend);
    minusLeftLabel.Text = minuend.ToString();
    minusRightLabel.Text = subtrahend.ToString();
    difference.Value = 0;

    // Fill in the multiplication problem.
    multiplicand = randomizer.Next(2, 11);
    multiplier = randomizer.Next(2, 11);
    timesLeftLabel.Text = multiplicand.ToString();
    timesRightLabel.Text = multiplier.ToString();
    product.Value = 0;

    // Fill in the division problem.
    divisor = randomizer.Next(2, 11);
    int temporaryQuotient = randomizer.Next(2, 11);
    dividend = divisor * temporaryQuotient;
    dividedLeftLabel.Text = dividend.ToString();
    dividedRightLabel.Text = divisor.ToString();
    quotient.Value = 0;

    // Start the timer.
    timeLeft = 30;
    timeLabel.Text = "30 seconds"; 
    timer1.Start();
}

测验开始时,此代码将 timeLeft 变量设置为 30,并将 timeLabel 控件的 Text 属性设置为 30 秒。 然后计时器控件的 Start() 方法启动倒计时。

运行应用

  1. 保存程序并运行它。

  2. 选择 开始测验。 计时器开始倒计时。 当时间用完时,测验结束,答案会显示。

  3. 启动另一个测验,并为数学问题提供正确的答案。 在时间限制内正确回答时,将打开一个消息框,启动按钮将变为可用,计时器将停止。

    显示剩余 19 秒的已完成测验的屏幕截图。“开始测验”按钮可用。

后续步骤

转到下一教程,了解如何自定义数学测验。