22.1.7 创建事件处理程序(1)
使用Form Design功能以图形方式构建GUI的过程,已经自动为添加的控件生成了代码。现在,每个添加到窗体的控件都对应着Form1类的一个成员,而且初始化这些控件的代码也已经全部添加到InitializeComponent()函数中。如果查看该函数,将看到其中有大量设置控件属性以及把控件放入各自的容器中的代码。以图形方式创建GUI是一件轻而易举的事情,我们需要多动动脑筋才能使该应用程序继续前进。
为了使该程序以我们需要的方式工作,必须为需要该应用程序识别并处理的事件创建事件处理程序函数,并实现这些函数,使用户与GUI的交互作用做我们想做的事情。虽然处理事件的代码不能自动生成,但IDE仍然可以帮助我们生成骨架事件处理程序函数,并使用事件委托注册这些函数。
可以在某个控件的Properties窗口中单击Events按钮,查看该控件的事件。这将显示出该控件上所有可能的事件,可以在某个事件名称右边的单元格中设定处理该事件的函数的名称。当然,只需要为那些希望识别的事件确定处理程序函数,而且多数情况下它们只是全部控件事件中非常小的一部分。需要为所有菜单项和选项卡上的每一个按钮创建Click事件的处理程序函数。在CLR Sketcher中通过Properties窗口执行该操作,但是为控件创建响应Click事件的处理程序函数还可以使用快捷方式;只需在Editor窗口中双击相应的控件,系统就会创建并显示函数代码,并把该函数注册为该事件对象的处理程序。这种方法创建的是控件独有的事件处理程序,但有时候我们希望使一个函数为多个控件处理特定类型的事件。在这种情况下,需要使用Properties窗口进行设置。
1. 菜单项的事件处理程序
可以首先为Play菜单项创建事件处理程序函数。双击该菜单项,创建下面的处理程序函数代码:
- private: System::Void playMenuItem_Click(System::Object^ sender,
- System::EventArgs^ e)
- {
- }
该函数是函数体中不包含任何代码的骨架处理程序。下面回顾一下在CLR Sketcher中学到的内容,第一个参数是引用产生该事件的控件的句柄,第二个参数提供与该事件有关的信息。当调用某个事件处理程序时,第一个实参的类型对应于产生该事件的控件的类型。在本例中,该类型是ToolStripMenuItem^,因为这个处理程序函数是Play菜单项被单击时调用的;该菜单项句柄存储在Form1类的playMenuItem成员中,我们可以在类定义中查看该成员的类型。同样,Click事件处理程序的第二个实参的实际类型也取决于控件的类型。
默认生成的处理程序函数名是playMenuItem_Click。我们不能在代码中修改这个函数名。事实上,建议不要在代码中修改任何自动生成的名称,而应该总是通过Properties窗口进行修改。如果不喜欢已经为事件处理程序函数创建的名称,可以在相应控件的Properties窗口中通过Click事件的属性值进行修改。
在InitializeComponent()函数中,上述处理程序函数的名称已经由下面这条语句注册到事件对象上:
- this->playMenuItem->Click +=
- gcnew System::EventHandler(this, &Form1::playMenuItem_Click);
该语句给playMenuItem对象(是Form1类的成员)中的Click委托添加上述函数名。我们在第9章学过委托以及注册事件处理程序函数的方法。
2. 给Form1类添加成员
在实现菜单项的处理程序之前,还需要几个字段来存储与彩票号码的约束条件有关的数据。我们知道如何给Form1类添加新字段,那是我们已经大量使用的给类添加成员的方法。切换到Class View,右击Form1类,并从上下文菜单中选择Add | Add Variable。另外,也可以手动添加代码,但务必不要闯入为Form Design操作保留的类定义区域。下面这些变量需要作为私有成员添加到类中:
- private:
- int lottoValuesCount; // Number of values in Lotto entry
- int euroValuesCount; // Number of values in Euromillions entry
- int euroStarsCount; // Number of stars in Euromillions entry
- int lottoLowerLimit; // Minimum value allowed in Lotto
- int lottoUpperLimit; // Maximum value allowed in Lotto
- int lottoUserMinimum; // Lower lotto range limit from user
- int lottoUserMaximum; // Upper lotto range limit from user
-
- int euroLowerLimit; // Minimum value allowed in Euromillions
- int euroUpperLimit; // Maximum value allowed in Euromillions
- int euroStarsLowerLimit; // Minimum stars value
allowed in Euromillions - int euroStarsUpperLimit; // Maximum stars value
allowed in Euromillions - int euroUserMinimum; // Lower euro range limit from user
- int euroUserMaximum; // Upper euro range limit from user
- int euroStarsUserMinimum;// Lower euro stars range limit from user
- int euroStarsUserMaximum;// Upper euro stars range limit from user
我们还需要给Form1类添加一个Random类型的私有字段:
- Random^ random; // Generates pseudo-random numbers
Random类型的对象可以生成各种类型的伪随机数。我们将使用该对象来生成彩票号码的值。
所有这些字段都必须在类的构造函数中初始化。确保Form1类的构造函数定义与下面相似:
- public ref class Form1 : public System::Windows::Forms::Form
- {
- public:
- Form1(void)
- : lottoValuesCount(6),
- euroValuesCount(5), euroStarsCount(2),
- lottoLowerLimit(1),lottoUpperLimit(49),
- lottoUserMinimum(lottoLowerLimit),lottoUserMaximum(lottoUpperLimit),
- euroLowerLimit(1), euroUpperLimit(50),
- euroStarsLowerLimit(1),euroStarsUpperLimit(9),
- euroUserMinimum(euroLowerLimit),euroUserMaximum(euroUpperLimit),
- euroStarsUserMinimum(euroStarsLowerLimit),euroStarsUserMaximum
- (euroStarsUpperLimit)
- {
- InitializeComponent();
- //
- random = gcnew Random;
- //
- }
这是目前我们需要的所有新的类数据成员,因此返回到事件处理上。