22.1.7 创建事件处理程序(2)
3. 处理Play菜单的事件
playMenuItem_Click()处理程序应该在当前可见的选项卡的按钮上创建一组新号码。记得在本章前面已经把TabControl控件中两个选项卡的(Name)属性值设置为lottoTab和euroTab。如果查看现在大规模Form1类的Class View窗口的下方窗格,将发现两个名称相同的TabPage^类型的变量。TabPage^类型的对象具有bool类型的Visible属性,如果选项卡页可见,该属性为true,否则为false。这就是需要实现Play菜单项的处理程序的原因。
该处理程序的轮廓逻辑可以像下面这样使用选项卡页的Visible属性值:
- private: System::Void playMenuItem_Click(System::Object^ sender,
- System::EventArgs^ e)
- {
- if(lottoTab->Visible)
- {
- // Generate and set values for Lotto entry
- }
- else if(euroTab->Visible)
- {
- // Generate and set values for Euromillions entry
- }
- }
如果lottoTab页的Visible属性为true,就创建新的Lotto彩票记录;而如果euroTab页的Visible属性为true,则创建Euromillions彩票记录。虽然这两个选项卡不可能同时可见,但还是要显式测试两个选项卡页,因为用户可能在Web Page选项卡可见的时候单击Play菜单项。
为两支彩票生成一组号码的过程有一些共同的地方。对Lotto彩票来说,必须生成给定范围内的6个不同的随机整数。而对Euromillions彩票来说,我们必须生成给定范围内的5个不同的整数,然后再生成另一个范围内的两个不同的整数。生成给定范围内任意数量整数的辅助函数对我们来说是有用的。可以将函数定义成下面的样子:
- void GetValues(array<int>^ values, int min, int max)
- {
- // Fill the array with different random integers from min to max...
- }
Values数组的Length属性告诉我们要生成多少个数值。调用函数只需要创建一个适当大小的数组,并将其作为第一个实参传递给GetValues()函数即可。第二个和第三个实参指定要生成的数值的范围。
将GetValues()函数作为私有成员添加到Form1类中,然后像下面这样完成其定义:
- void GetValues(array<int>^ values, int min, int max)
- {
- values[0] = random->Next(min, max+1); // Generate first random value
-
- // Generate remaining random values
- for(int i = 1 ; i<values->Length ; i++)
- {
- for(;;) // Loop until a valid value is found
- {
- // Generate random integer from min to max
- values[i] = random->Next(min, max+1);
-
- // Check that its different from previous values
- if(IsValid(values[i], values, i))
- // Check against previous values...
- break; // ...it is different so end loop
- }
- }
- }
任何在允许范围内的数值都可以作为第一个元素。以后的数值必须与先前生成的数值进行核对,而IsValid()函数用于执行该操作。下面是该函数的实现:
- // Check whether number is different from values array elements
- // at index positions less than indexLimit
- bool IsValid(int number, array<int>^ values, int indexLimit)
- {
- for(int i = 0 ; i< indexLimit ; i++)
- {
- if(number == values[i])
- return false;
- }
- return true;
- }
将IsValid()函数作为私有成员添加到Form1类中。该函数的操作非常简单:将第一个实参与第二个实参指定的数组中索引值小于第三个实参的元素进行核对,如果第一个实参等于任何一个数组元素,则返回false,否则返回true,表明第一个实参有效。
GetValues()函数中的无穷for循环将持续执行并生成新的随机数,直到IsValid()函数返回true为止,此后内部循环结束,外部for循环的下一次迭代开始执行,以找出下一个特定的数值。
现在可以在Play菜单Click事件处理程序的实现中使用GetValues()函数:
- private: System::Void playMenuItem_Click(System::Object^ sender,
- System::EventArgs^ e)
- {
- array<int>^ values; // Variable to store
a handle to array of integers - if(lottoTab->Visible)
- {
-
- // Generate and set values for Lotto entry
- values = gcnew array<int>(lottoValuesCount); // Create the array
- GetValues(values, lottoUserMinimum, lottoUserMaximum);
-
// Generate values - SetValues(values, lottoValues);
- }
- else if(euroTab->Visible)
- {
- // Generate and set values for Euromillions entry
- values = gcnew array<int>(euroValuesCount);
- GetValues(values, euroUserMinimum, euroUserMaximum);
- SetValues(values, euroValues);
- values = gcnew array<int>(euroStarsCount);
- GetValues(values, euroStarsUserMinimum, euroStarsUserMaximum);
- SetValues(values, euroStars);
- }
- }