22.1.14 响应上下文菜单(2)
当然,可以从对话框对象的属性中获得极限值,但这种方法要求我们总是要首先设置相应属性。通过使用极限值作为形参,就消除了这种依赖性。
可以在Form1类的构造函数中创建该对话框对象,但需要给Form1类添加一个私有成员来存储对话框的句柄:
- private: UserValueDialog^ userValueDialog;
还需要在Form1.h头文件中添加一条嵌入UserValueDialog.h的#include指令。
在Form1类的构造函数中添加下面这行创建对话框对象的代码:
- userValueDialog = gcnew UserValueDialog;
如果在UserValueDialog窗体中双击OK按钮,将创建该按钮的Click事件处理程序。该函数应当获取用户在TextBox控件中输入的值,并检查输入值是否在允许范围之内,是否与所有当前值都不同。如果输入值因某种原因无效,则该函数应当显示一个消息框。下面是该函数的实现:
- System::Void OK_Click(System::Object^ sender, System::EventArgs^ e)
- {
- ::DialogResult result; // Stores return value from Show()
- if(String::IsNullOrEmpty(textBox->Text))
- // Chheck for null or empty string
- {
- result = MessageBox::Show(this,
- L"No input - enter a value.",
- L"Input Error",
- MessageBoxButtons::RetryCancel,
- MessageBoxIcon::Error);
- if(result == ::DialogResult::Retry) // If Retry button clicked
- DialogResult = ::DialogResult::None;
- // ...prevent dialog from closing...
- else // ...otherwise...
- DialogResult = ::DialogResult::Cancel;// ...close the dialog.
- return;
- }
-
- int value = Int32::Parse(textBox->Text); // Get text box value
- bool valid = true; // Indicator for valid entry
-
- for each(int n in Values) // Check input against current values
- if(value == n) // If it's the same...
- {
- valid = false; // ...it is invalid.
- break; // Exit the loop
- }
-
- // Check limits and result of previous validity check
- if(!valid || value < LowerLimit || value > UpperLimit)
- {
- result = MessageBox::Show(this,
- L"Input not valid." +
- L"Value must be from " + LowerLimit +
- L" to " + UpperLimit +
- L"\nand must be different from existing
- values.",
- L"Input Error",
- MessageBoxButtons::RetryCancel,
- MessageBoxIcon::Error);
- if(result == ::DialogResult::Retry)
- DialogResult = ::DialogResult::None;
- else
- DialogResult = ::DialogResult::Cancel;
- }
- else
- Value = value; // Store the input in the property
- }
如果文本框的Text属性是空值或者是空字符串,则显示一个消息框。该消息框给出一条出错消息,并以Retry和Cancel按钮代替OK和Cancel。如果单击Retry,则表明用户希望再次输入,因此将对话框的DialogResult属性设置为::DialogResult::None,使其不能关闭。仅有的另一种可能性是用户单击消息框中的Cancel按钮,在这种情况下,将对话框的DialogResult属性设置为::DialogResult:: Cancel,这与单击对话框的Cancel按钮具有相同的效果。
TextBox控件的Text属性返回String^类型的句柄。通过将该句柄传递给Int32类中的静态Parse()函数,将其转换为整数。然后,将该整数与表示按钮上当前值集合的values数组中的元素进行比较。新值应该与所有其他值都不同,因此如果发现有一个当前值与新值相同,则将valid设置为false,并退出循环。
for each循环后面的if语句把几个条件OR在一起,检查valid的当前值以及新值是否超出了允许范围。如果3个表达式中的任何一个是false,整个条件就是false,于是显示一个消息框。该消息框与前一个消息框的工作方式相同,也是显示一条出错消息以及Retry和Cancel按钮。如果该数值确实是有效的,就将其存入对话框对象的Value属性中,准备供Form1对象中启动整个过程的事件处理程序检索。
4. 处理Choose菜单项的Click事件
现在,我们打算使用已经添加到UserValueDialog类的功能,完成chooseva lue_Click()处理程序函数的骨架。被右击按钮的句柄已经存储在contextButton成员中,因为首先执行的是前面添加的buttonContextMenu_Opening()处理程序。
- System::Void chooseva lue_Click(System::Object^ sender, System::EventArgs^ e)
- {
- array<int>^ values; // Array to store current button values
- array<Button^>^ theButtons; // Handle to aray of buttons
-
- // Check if the button is in the lottoValues group box
- if(lottoValues->Controls->Contains(contextButton))
- {
- // the button is from the lotto group...
- array<Button^>^ buttons = {lottoValue1, lottoValue2, lottoValue3,
- lottoValue4, lottoValue5, lottoValue6};
- theButtons = buttons; // Store array handle at outer scope
- values = GetButtonValues(buttons); // Get array of button values
-
- // Set up the dialog ready to be shown
- userValueDialog->Values = values = GetButtonValues(buttons);
- userValueDialog->LowerLimit = lottoUserMinimum;
- userValueDialog->UpperLimit = lottoUserMaximum;
- userValueDialog->SetLabelText(lottoUserMinimum,
- lottoUserMaximum);
- userValueDialog->ClearTextBox();
- }
- // Check if the button is in the euroValues group box
- else if(euroValues->Controls->Contains(contextButton))
- {
- // The button is in the Values group...
- array<Button^>^ buttons = {euroValue1, euroValue2, euroValue3,
- euroValue4, euroValue5};
- theButtons = buttons; // Store array handle at outer scope
- values = GetButtonValues(buttons); // Get array of button values
-
- // Set up the dialog ready to be shown
- userValueDialog->Values = values;
- userValueDialog->LowerLimit = euroUserMinimum;
- userValueDialog->UpperLimit = euroUserMaximum;
- userValueDialog->SetLabelText(euroUserMinimum, euroUserMaximum);
- userValueDialog->ClearTextBox();
- }
- // Check if the button is in the euroStars group box
- else if(euroStars->Controls->Contains(contextButton))
- {
- // The button is in the Stars group...
- array<Button^>^ buttons = { euroStar1, euroStar2 };
- theButtons = buttons; // Store array handle at outer scope
- values = GetButtonValues(buttons); // Get array of button values
-
- // Set up the dialog ready to be shown
- userValueDialog->Values = values;
- userValueDialog->LowerLimit = euroStarsUserMinimum;
- userValueDialog->UpperLimit = euroStarsUserMaximum;
- userValueDialog->SetLabelText(euroStarsUserMinimum,
- euroStarsUserMaximum);
- userValueDialog->ClearTextBox();
- }
-
- // Display the dialog
- if(userValueDialog->ShowDialog(this) == ::DialogResult::OK)
- {
- // Determine which button value should be replaced
- for(int i = 0 ; i<theButtons->Length ; i++)
- if(contextButton == theButtons[i])
- {
- values[i] = userValueDialog->Value;
- break;
- }
- Array::Sort(values); // Sort the values
-
- // Set all the button values
- for(int i = 0 ; i<theButtons->Length ; i++)
- theButtons[i]->Text = values[i].ToString();
- }
- }