在此系列教程中,你将生成一个数学测验。 测验包含四个随机数学问题,测验者尝试在指定时间内回答。
测验使用计时器控件。 此控件背后的代码跟踪经过的时间,并检查测验参与者的答案。
在本第三个教程中,你将了解如何:
- 添加计时器控件。
- 为计时器添加事件处理程序。
- 编写代码以检查用户的答案、显示消息并填写正确的答案。
先决条件
本教程基于前面的教程,从 创建数学测验 WinForms 应用开始。 如果尚未完成这些教程,请先完成这些教程。
添加倒计时计时器
若要跟踪测验期间的时间,请使用计时器组件。 还需要一个变量来存储剩余的时间量。
添加一个名为 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;
在 Windows 窗体设计器中,将 Timer 控件从 工具箱 的 组件 类别移动到窗体中。 该控件显示在设计窗口底部的灰色区域中。
在表单上,选择刚添加的 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()
来检查测验者答案。 它还检查测验已消耗的时间。
在窗体中,双击“计时器”控件,或将其选中,然后选择 Enter。 这些操作添加 Tick 事件处理程序。 代码编辑器将出现并显示 Tick 处理程序的方法。
对于 C#,它会在连接事件处理程序的 Form1.Designer.cs 代码文件中添加一行代码:
timer1.Tick += new EventHandler(timer1_Tick);
(对于 Visual Basic,不需要该行,但事件处理程序包含执行相同操作的
handles Timer1.Tick
。将以下语句添加到新的事件处理程序方法。
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() 方法启动倒计时。
运行应用
保存程序并运行它。
选择 开始测验。 计时器开始倒计时。 当时间用完时,测验结束,答案会显示。
启动另一个测验,并为数学问题提供正确的答案。 在时间限制内正确回答时,将打开一个消息框,启动按钮将变为可用,计时器将停止。
后续步骤
转到下一教程,了解如何自定义数学测验。