Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 127 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
127
Dung lượng
2,6 MB
Nội dung
You have more than one control in the dialog box that you could use to permit a limit value to be entered. You can use a ListBox control to enable the user to select from a list of possible values, so you can try that here. You should add two Label controls to the dialog box form with two ListBox controls alongside, as shown in Figure 21-21. Figure 21-21 The (Name) property for the list boxes should be lottoLowerList and lottoUpperList for the top and bottom. As you see, I resized the ListBox controls to be the same height as the Label controls and a width sufficient to display a single limit value. I also changed the font Size property to 10 and the ScrollAlwaysVisible property to True. Make sure the SelectionMode property value is One for both list boxes, as you want to allow only one item to be selected from a list box at one time. The GUI for the dialog box is complete, but to make it do what you want you are back in coding mode again. You can start with the code that populates the ListBox controls with limit values. Adding a List to a ListBox The list that a ListBox controls is a set of objects that are stored as handles of type Object^, so any kind of object can be stored in the list. In the example you want to store a set of integer limit values in each list box, and for the most part you are able to rely on autoboxing and unboxing to convert values of type int to and from objects of type Int32 whenever necessary. The Items property for a ListBox object returns a reference to a collection of the objects in the list box; this collection has an Add() method that adds an object that you pass as the argument to the list. A ListBox object has a large number of properties including the Enabled property that has the value true when the user can interact with the list box and the value false when interaction is to be inhibited. The basic process for loading up the list for a list box is the same for both ListBox controls, so you could code a private function member of the LottoLimitsDialog class that is generalized to add a range of integers to a list box: 1058 Chapter 21 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1058 void SetList(ListBox^ listBox, int min, int max, int selected) { listBox->BeginUpdate(); // Suppress drawing the listbox for(int n = min ; n <= max ; n++) listBox->Items->Add(n); listBox->EndUpdate(); // Resume drawing the list box listBox->SelectedItem = Int32(selected); } The arguments to the SetList() function are the list box for which the list is to be added, the minimum and maximum integers in the range to be added, and the integer that is to be selected in the list box. The function adds integers from min to max inclusive to the list box using the Add() function for the collec- tion object that is returned by the Items property for the ListBox object. It also sets the selected value as the item that is initially selected in the list when the list box is displayed by setting it as the value for the SelectedItem property for the list box. When the user selects a limit in the dialog box, you’ll need somewhere to put the value so that it can be accessed from a function belonging to the Form1 object; the event handler for the menu items have responsibility for retrieving the limit value and storing it in the Form1 object. One way to do this is to add a couple of private members to the LottoLimitsDialog class to store the upper and lower limit values and then add public properties to the class to make the values available externally. Adding the following code to the LottoLimitsDialog class definition does that: private: int lowerLimit; // Lower limit from control int upperLimit; // upper limit from control public: property int LowerLimit // Property accessing lower limit { int get(){ return lowerLimit; } void set(int limit) { lowerLimit = limit; lottoLowerList->SelectedItem = Int32(limit); } } property int UpperLimit // Property accessing upper limit { int get(){ return upperLimit; } void set(int limit) { upperLimit = limit; lottoUpperList->SelectedItem = Int32(limit); } } 1059 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1059 You need to be able to update the properties because the Click event handler for the Limits > Reset menu item changes the limits, and you want the ListBox objects to have whatever is the current upper or lower limit selected. As well as storing the value in the class object, you also update the ListBox objects to reflect the new limits. You can now create two public member functions in the LottoLimitsDialog class that sets up the two ListBox controls: public: void SetLowerLimitsList(int min, int max, int selected) { SetList(lottoLowerList, min, max, selected); lowerLimit = selected; } void SetUpperLimitsList(int min, int max, int selected) { SetList(lottoUpperList, min, max, selected); upperLimit = selected; } Each function uses the SetList() function to set the range of values in the corresponding ListBox object and then sets the selected value in the member for storing the limit. Handling the Dialog Button Events Add an event handler function for the Click event for the OK Button object, so return to the Design tab for the LottoLimitsDialog form and double-click the OK button to add the skeleton code. You don’t need to add a handler for the Click event for the Cancel button. The effect of clicking the button is to close the dialog box and no further action is required. You can implement the handler for the Click event for the OK button like this: System::Void lottoOK_Click(System::Object^ sender, System::EventArgs^ e) { // If there’s a currently selected upper limit item, save it if(lottoUpperList->SelectedItem != nullptr) upperLimit = safe_cast<Int32>(lottoUpperList->SelectedItem); // If there’s a currently selected lower limit item, save it if(lottoLowerList->SelectedItem != nullptr) lowerLimit = safe_cast<Int32>(lottoLowerList->SelectedItem); } The function first stores the upper limit value from the lottoUpperList ListBox object in the member variable you added for that purpose. The SelectedItem property for a ListBox object makes the cur- rently selected item available as a handle of type Object^ and as a precaution the code verifies that the handle returned is not null. Before storing the selected item you must cast it to its actual type—type Int32. Auto-unboxing then takes care of converting the object to an integer. The handler next stores the lower limit value from the other ListBox object in the same way. When the handler finishes executing, the dialog box is closed automatically. 1060 Chapter 21 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1060 Controlling the State of the ListBox Objects The same dialog object is used in the response to the Click events for both the Limits > Upper and Limits > Lower menu items, but you don’t want to allow both list boxes to be changed in either case. For the Upper menu item event you’ll want the selection of a lower limit to be inhibited, and for the Lower menu item you’ll want the list box for the upper limit to be inhibited. You could add a couple of public function members to the LottoLimitsDialog class to make this possible. Here’s the function to set the state of the ListBox objects for the Upper menu item: void SetUpperEnabled() { lottoUpperList->Enabled = true; // Enable upper list box lottoLowerList->Enabled = false; // Disable lower list box } You set the Enabled property for the lottoUpperList object to true to allow the user to interact with it. Setting the Enabled property for lottoLowerList to false makes it read-only. For the Lower menu item you do the reverse: void SetLowerEnabled() { lottoUpperList->Enabled = false; // Disable upper list box lottoLowerList->Enabled = true; // Enable lower list box } You have done a lot of work to get the dialog object to behave as you want in the application, but you don’t yet have a dialog object. The application window object takes care of that. Creating the Dialog Object The Form1 class constructor can create the dialog object. It can also initialize the ListBox objects in the dialog. Add a private member to the Form1 class that stores the handle to the dialog box: private: LottoLimitsDialog^ lottoLimitsDialog; Add the following lines of code to the body of the Form1 constructor: lottoLimitsDialog = gcnew LottoLimitsDialog; lottoLimitsDialog->SetLowerLimitsList(1, lottoUpperLimit-lottoValuesCount+1, lottoUserMinimum); lottoLimitsDialog->SetUpperLimitsList(lottoValuesCount, lottoUpperLimit, lottoUserMaximum); This code is very straightforward. The first statement creates the dialog object. The next two statements call the functions that initialize the lists in the ListBox objects. The maximum value in the ListBox object that sets the lower limit is calculated so that it permits the required number of values for an entry to be created. If the maximum value for a value is 49 and the number of values in an entry is 6, the maxi- mum for the lower limit must be 44 — if it was any higher you could not create six different values. The same reason applies to the minimum value for the upper limit; it cannot be less than the number of val- ues in an entry. The selected item for the list boxes are the lottoUserMinimum and lottoUserMaximum values. 1061 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1061 Because you refer to the LottoLimitsDialog class name in the Form1 class constructor, you’ll need to add an #include directive for the class definition to Form1.h: #include “LottoLimitsDialog.h” Using the Dialog Box You’ll put the dialog box into operation in the code for the Click event handlers for the Upper and Lower menu items in the Limits menu. To display a dialog box as a modal dialog box, you call the ShowDialog() function for the dialog object. Optionally you can pass the handle to the parent form as the argument to the ShowDialog() function. You can implement the Click event handler functions like this: System::Void lowerMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { if(lottoTab->Visible) { lottoLimitsDialog->SetLowerEnabled(); ::DialogResult result = lottoLimitsDialog->ShowDialog(this); if(result == ::DialogResult::OK) { // Update user limits from dialog properties lottoUserMaximum = lottoLimitsDialog->UpperLimit; lottoUserMinimum = lottoLimitsDialog->LowerLimit; } } } System::Void upperMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { if(lottoTab->Visible) { lottoLimitsDialog->SetUpperEnabled(); ::DialogResult result = lottoLimitsDialog->ShowDialog(this); if(result == ::DialogResult::OK) { // Update user limits from dialog properties lottoUserMaximum = lottoLimitsDialog->UpperLimit; lottoUserMinimum = lottoLimitsDialog->LowerLimit; } } } These two functions both work in the same way; they call the function to set the list box states and then display the dialog box as a modal dialog box by calling the ShowDialog() function for the dialog object. If you wanted to display the dialog box as a modeless dialog box, you call the Show() function for the dialog object instead. When you call the ShowDialog() function, it does not return until the dialog box closes. This means that the code to update the limits is not executed until the new limits have been recorded in the dialog 1062 Chapter 21 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1062 object by the Click event handler for the lottoOK button. When you display a dialog box as modeless by calling the Show() function, the function returns immediately. Thus if you need to be able to access data that might have been changed in the dialog box, you need another way to do it. Adding a handler function for the Closing event for the dialog form is one possibility; another would be to deal with transferring the data in the handler for the button that closes the dialog box. The ShowDialog() function returns a value of the enumeration type DialogResult and you store this in the local variable, result. The return value from the ShowDialog() function indicates which button in the dialog was clicked, and if the value is the enumeration constant ::DialogResult::OK, it indicates that the OK button was clicked. Thus the code in each handler function updates only the lottoUserMaximum and LottoUserMinimum fields when the OK button was used to close the dialog. Note the use of the :: operator in the type specification ::DialogReult and in the expression ::DialogResult::OK. The scope resolution operator is necessary preceding the DialogResult name to distinguish the name of the enumeration at global scope from the property with the same name that is a member of the Form1 class. Of course, you could access the DialogResult property for the lottoLimitsDialog object directly, so you could write the if statement as: if(lottoLimitsDialog->DialogResult == ::DialogResult::OK) { // Update user limits from dialog properties lottoUserMaximum = lottoLimitsDialog->UpperLimit; lottoUserMinimum = lottoLimitsDialog->LowerLimit; } The former version is better because it is obvious that you are checking the value returned by the ShowDialog() function. The complete set of constants that the DialogResult enumeration defines is as follows: Yes No OK Cancel Retry Ignore None The DialogResult property value that is set for a dialog box determines whether or not the dialog box closes. If the value is set to None, the dialog box does not close. You can set the property to this value when you want to prevent the dialog box from closing for some reason—if the input is not valid, for instance. At the moment, the Click event handler for the OK button does not validate the input values. It is cur- rently quite possible to set the lower and upper limits to values that make it impossible to assign six unique values for the lottery entry. You can use the DialogResult property for the form to deal with the problem. Validating the Input The difference between the upper and lower limits that the user chooses must be greater than or equal to 5 if there are to be 6 unique values in a Lotto entry. You could modify the Click event handler for the OK button in the dialog class to check for this: 1063 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1063 System::Void lottoOK_Click(System::Object^ sender, System::EventArgs^ e) { int upper = 0; int lower = 0; // If there’s a currently selected upper limit item, save it if(lottoUpperList->SelectedItem != nullptr) upper = safe_cast<Int32>(lottoUpperList->SelectedItem); // If there’s a currently selected lower limit item, save it if(lottoLowerList->SelectedItem != nullptr) lower = safe_cast<Int32>(lottoLowerList->SelectedItem); if(upper - lower < 5) { MessageBox::Show(L”Upper limit: “ + upper + L” Lower limit: “ + lower + L”\nUpper limit must be at least 5 greater that the lower limit.” + L”\nTry Again.”, L”Limits Invalid”, MessageBoxButtons::OK, MessageBoxIcon::Error); DialogResult = ::DialogResult::None; } else { upperLimit = upper; lowerLimit = lower; } } Now the function saves the values selected in the ListBox objects in the local variables lower and upper. If the values differ by less than 5, a message box is displayed and closing of the dialog box is inhibited by setting the value of the DialogResult property to None. The static Show() function in the MessageBox class displays a message box that is customized by the arguments to the function. This ver- sion of the Show() function used here accepts four arguments as follows: Parameter Type Description String^ The text to be displayed in the message box. String^ The text to appear in the title bar of the message box. MessageBoxButtons An enumeration constant specifying the buttons to appear in the message box. The MessageBoxButtons enumeration defines the following values: OK, OKCancel, YesNo, YesNoCancel, RetryCancel, AbortRetryIgnore MessageBoxIcon An enumeration constant specifying the icon to appear in the message box. The MessageBoxIcon enumeration defines the following values: Asterisk, Exclamation, Error, Hand, Information, None, Question, Stop, Warning 1064 Chapter 21 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1064 There are a significant number of overloaded versions of the static Show() function that range from the very simple with a single parameter of type String^ to the rather more complicated with up to 10 parameters. If you compile and execute the example and set the limits inappropriately, you’ll see a window similar to that shown in Figure 21-22. Figure 21-22 The circular red icon with the white cross was specified by the fourth argument to the Show() function, and the single OK button is the result of the third argument. The Show() function that you call to display a message box returns a value of type DialogResult that indicates which button was used to close the message box. You can use this return value to decide what to do after the message box closes. In the lottoOK_Click() handler for the OK button in the limits dia- log box, you could decide whether or not to close the limits dialog box using the value returned by the Show() function for the message box: System::Void lottoOK_Click(System::Object^ sender, System::EventArgs^ e) { int upper = 0; int lower = 0; // If there’s a currently selected upper limit item, save it if(lottoUpperList->SelectedItem != nullptr) upper = safe_cast<Int32>(lottoUpperList->SelectedItem); // If there’s a currently selected lower limit item, save it if(lottoLowerList->SelectedItem != nullptr) lower = safe_cast<Int32>(lottoLowerList->SelectedItem); if(upper - lower < 5) { 1065 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1065 ::DialogResult result = MessageBox::Show(L”Upper limit: “ + upper + L” Lower limit: “ + lower + L”\nUpper limit must be at least 5 greater that the lower limit.” + L”\nTry Again.”, L”Limits Invalid”, MessageBoxButtons::OKCancel, MessageBoxIcon::Error); if(result == ::DialogResult::OK) DialogResult = ::DialogResult::None; else DialogResult = ::DialogResult::Cancel; } else { upperLimit = upper; lowerLimit = lower; } } Because the third argument to the Show() function is MessageBoxButtons::OKCancel, the message box now has two buttons as shown in Figure 21-23. Figure 21-23 In the Click event handler for the OK button in the limits dialog box you store the return value from the Show() function in result. The type for result has to be specified using the scope resolution operator. Otherwise, it is interpreted by the compiler as the DialogResult property for the lottoLimitsDialog object, and the code does not compile. If result contains the value ::DialogResult::OK, you set the DialogResult property for the lottoLimitsDialog object to ::DialogResult::None, which prevents the dialog box from closing and allows the limit to be changed. Otherwise you set the DialogResult property for the dialog to ::Dialog::Cancel, which has the same effect as clicking the Cancel button for the dialog box so it closes. 1066 Chapter 21 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1066 Handler the Reset Menu Item Event You can implement the event handler for the Reset menu item like this: System::Void resetMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { if(lottoTab->Visible) { // Reset user limits for Lotto lottoUserMaximum = lottoUpperLimit; lottoUserMinimum = lottoLowerLimit; lottoLimitsDialog->UpperLimit = lottoUpperLimit; lottoLimitsDialog->LowerLimit = lottoLowerLimit; } else if(euroTab->Visible) { // Reset user limits for Euromillions euroUserMaximum = euroUpperLimit; euroUserMinimum = euroLowerLimit; euroStarsUserMaximum = euroStarsUpperLimit; euroStarsUserMinimum = euroStarsLowerLimit; // Code to update Euromillions limits dialog } } This just resets the limits in the fields in the Form1 object and then updates the properties in the dialog object accordingly. You still have to add code to this function to deal with resetting the dialog box to which you have yet added the application that will handle the input for the Euromillions lottery limits. You can now recompile the program and try changing the limits for the Lotto entry. A typical application window is shown in Figure 21-24. Figure 21-24 1067 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 1067 [...]... a BindingNavigator control to navigate data from a source managed by a BindingSource control How you expedite updating of a database using a BindingNavigator control and a BindingSource component Visual C++ 2005 provides a high degree of automation for creating Forms-based applications that access data sources but you will start by ignoring the automation and get a feel for how you can work with components... About menu item is clicked: System::Void aboutToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { MessageBox::Show(L”(c) Copyright Ivor Horton”, L”About A Winning Application”, MessageBoxButtons::OK, MessageBoxIcon::Exclamation); } 107 5 Chapter 21 When the the menu item is clicked, the handler function displays the message box shown in Figure 21-28 Figure 21-28 Handling a Button... euroUserMinimum = euroLimitsDialog->LowerValuesLimit; euroStarsUserMaximum = euroLimitsDialog->UpperStarsLimit; 107 4 e) Applications Using Windows Forms euroStarsUserMinimum = euroLimitsDialog->LowerStarsLimit; } } } The local variable result is used in both if statements, so it is now declared at the beginning of the function After enabling the controls in the dialog box appropriately by calling the SetUpperEnabled()... properties for components used in the project 109 1 Chapter 22 The data in a DataGridView control is displayed in a rectangular array of cells that you can envisage as a collection of rows or as a collection of columns Each column of cells has a header cell at the top that typically contains text that identifies it, and each row has a row header cell at the beginning, as shown in Figure 22-1 DataGridView^... if(starsUpper - starsLower < 1) { result = MessageBox::Show(this, “Upper stars limit: “+starsUpper + “ Lower stars limit: “+ starsLower+ “\nUpper stars limit must be at least “\nTry Again.”, “Limits Invalid”, 107 2 // Check for an adequate range // Range insufficient so // so display message box 1 greater that the lower limit.”+ Applications Using Windows Forms MessageBoxButtons::OKCancel, MessageBoxIcon::Error);... entered, and when the Limits > Lower menu item is selected, you want to prevent input for an upper limit value You can add a couple of member functions to the EuroLimitsDialog class to make this possible: 107 3 Chapter 21 public: // Disables controls for selecting upper limits void SetLowerEnabled(void) { upperValuesLimits->Enabled = false; upperStarsLimits->Enabled = false; lowerValuesLimits->Enabled =... control on the left should be 44 and 1 respectively, and the values for the Maximum and Minimum properties for the control to the right should be 49 and 6 respectively You can set the value of the Value 106 8 Applications Using Windows Forms property for the upperValuesLimit control to 49; this is the value displayed initially in the control If you also set the ReadOnly property value for each of the NumericUpDown... upperStarsLimits You can enter values to be displayed in a ComboBox quite easily Click the small arrow at the top right of the leftmost ComboBox control to display the menu shown in Figure 21-26 Figure 21-26 106 9 Chapter 21 Select the Edit Items menu item at the bottom of the menu to display the dialog window for the String Collection Editor shown in Figure 21-27 Figure 21-27 Figure 21-27 shows the values... and find index for button for(int i = 0 ; i < values->Length ; i++) { values[i] = Int32::Parse(buttons[i]->Text); // Get current button value // If current handle is same as button, save the index value 107 6 Applications Using Windows Forms if(button == buttons[i]) index = i; } int newValue = 0; // Store the new button value // Check if it is different from the other button values for(;;) // Loop until... array^ buttons = {lottoValue1, lottoValue2, lottoValue3, lottoValue4, lottoValue5, lottoValue6}; // Replace the value on button SetNewValue(button, buttons, lottoUserMinimum, lottoUserMaximum); } 107 7 Chapter 21 The availability of the SetNewValue() function makes this handler function very simple The first statement stores the handle to the button that was clicked The first parameter to the event . Copyright Ivor Horton”, L”About A Winning Application”, MessageBoxButtons::OK, MessageBoxIcon::Exclamation); } 107 5 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 107 5 When. limit; lottoUpperList->SelectedItem = Int32(limit); } } 105 9 Applications Using Windows Forms 24_571974 ch21.qxp 1/20/06 11:47 PM Page 105 9 You need to be able to update the properties because. handler finishes executing, the dialog box is closed automatically. 106 0 Chapter 21 24_571974 ch21.qxp 1/20/06 11:47 PM Page 106 0 Controlling the State of the ListBox Objects The same dialog object