1. Trang chủ
  2. » Công Nghệ Thông Tin

Ivor Horton’s BeginningVisual C++ 2008 phần 10 ppsx

142 193 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 142
Dung lượng 2,23 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

In the same way you can change the Nameproperty for the Reset menu item to resetMenuItem, set theShortCutKeysproperty value to Ctrl+Alt+R, and make the tooltip text “Reset limits to orig

Trang 1

More on Windows For ms Applications

You already know quite a lot about the process of creating Windows Forms applications fromCLR Sketcher In this chapter, you will explore some more controls that you can use in the GUI for a Windows Forms application You’ll do this by assembling a single application incrementallythroughout the chapter, so by the end of the chapter you’ll have another Windows Forms program

of a reasonable size

In this chapter, you’ll learn:

❑ How to use a wider variety of controls to build an application GUI

❑ How to display a Web page in an application

❑ How to work with control containers

❑ How to create and display message boxes

Creating the Application GUI

Create a new CLR project using the Windows Forms Applicationtemplate and assign thename Ex22_01to the project You are going to develop Ex22_01into a program to generate lot-tery entries The program won’t be an ideal design because it includes controls that duplicatesome functions perhaps unnecessarily, but the benefit is that you get to try out various possibili-ties in a working application I have chosen two lotteries with which I am familiar and for whichthe program generates entries; if these don’t match the lottery that you favor, you should be able

to adjust the example quite easily

Trang 2

Let me make one point against entering a lottery — you would probably not choose the numbers 1 to 6 as your entry because it is extremely unlikely that such an entry would win Of course, the truth is that it’s just as likely as any other more random-looking set of numbers you might choose, but the numbers 1 to 6 have never come up as the winning entry in any lottery anywhere So you can conclude that whatever

you choose — you lose.

First, display the Properties window for the form and change the value of its Text property to A WinningApplication To display the controls that are available for use with the form, press Ctrl+Alt+X, or select theView > Toolboxmenu item Add a menu strip control to the top of the form by dragging a MenuStripfrom the Toolbox window to the form Add three menu items to the menu strip with the text &Play,

&Limits, and &Help The &precedes the character that is the accelerator character for the menu item, soAlt+Pis the accelerator for the Play menu The Editor window containing the form with the menu stripshould now look as shown in Figure 22-1

The Play menu won’t have a submenu but will cause a Clickevent to fire when it is clicked Becauseyou’ll be handling the event, it is convenient to give the menu item a name that is shorter than the default.You can access the properties by right-clicking the control in the form and selecting Properties from thecontext menu, but this time try clicking menuStrip1below the form and select Edit Items from the con-text menu It displays the Items Collection Editor dialog box shown in Figure 22-2

If you select the name in the left pane in the dialog box corresponding to the Play menu, the properties for

it are displayed in the right pane You can then edit the (Name)property value to make it playMenuItem.Figure 22-2 shows the dialog box after the change has been made The advantage of using this dialog box

is that you can work through all the items on the menu strip adjusting the properties as necessary You canalso add new items to the menu strip or rearrange the menu sequence by moving items up or down usingthe buttons to the right of the left pane

Figure 22-1

Trang 3

Figure 22-2

Adding Submenus

Add three menu items, Upper, Lower, and Reset, to the Limits menu and add an About menu item to theHelp menu You can add new menu items to a drop-down menu using the Items Collection Editor, too Youaccess this by right-clicking the top level menu item such as Limits and selecting EditDropDownItems from the pop-up You just select the item you want to add from the drop-down list at the top, and click theAdd button Alternatively you can work through the Editor pane and interact directly with the menu strip

as you did with the CLR Sketcher application The properties for the new menu items need to be modified,

so display the properties for the Upper menu first of all by right-clicking it and selecting Properties from thepop-up You will be handling events for this menu item so you can change the default name property tosomething shorter, such as upperMenuItem You can also add a shortcut key for the item by clicking thedown arrow in the value column for the ShortcutKeysproperty to display the list shown in Figure 22-3

Trang 4

Select the modifier or modifiers by clicking one or more of the checkboxes and select the key from thedrop-down list I chose Ctrl+Alt+Uas the shortcut for this menu item, as you can see Figure 22-3 alsoshows that I have set the value for the ToolTipTextproperty as “Set upper limit for values” Asyou know, hovering the mouse cursor over a menu item results in the tooltip being displayed after a briefdelay Setting the AutoToolTipproperty that is toward the beginning of the list to Truemakes the tooltipthe same as the text on the menu item Leaving the property value as Falsecauses the ToolTipTextproperty value to be chosen for the tooltip text You can also control whether or not the shortcut key com-bination is displayed alongside the menu item text by setting the ShowShortcutKeysproperty value.Clicking the Lower menu item causes its properties to be displayed in the Propertieswindow You can then change the (Name)property value to lowerMenuItem, the ShortcutKeysproperty value toCtrl+Alt+L, and the ToolTipTextproperty values to “Set lower limit for values” In the same way you can change the (Name)property for the Reset menu item to resetMenuItem, set theShortCutKeysproperty value to Ctrl+Alt+R, and make the tooltip text “Reset limits to originalvalues” You can also change the (Name)property value for the About menu item to aboutMenuItemand add tooltip text for that, too; an About menu item doesn’t usually have a shortcut key combinationdefined The Play menu item creates a complete new set of values for a lottery entry, so you could addtooltip text to indicate that, if you want.

Adding a Tab Control

A TabControlcontrol provides multiple tabs that can each contain their own set of controls You can use atab control to provide for entries to more than one lottery in the application window client area Displaythe Toolbox window (Ctrl+Alt+X)and select TabControlfrom the list — it’s in the Containersgroup.Click in the client area of the form to add the tab control and then display its properties All the controlslisted under the Containersheading can contain other controls so they all provide a means of collectingtogether a set of controls into a group Obviously with the tab control each tab can contain its own set ofcontrols, and you can have as many tabs in the control as you want

You want the tab control to always fill the client area of the window, and this is determined by the value

of the Dockproperty that is in the Layoutgroup of properties for the TabControlcontrol Figure 22-4shows the Propertieswindow for the tab control with the value cell for the Dockproperty expanded.Clicking in the central area where the cursor currently appears in Figure 22-4 changes the Dockpropertyvalue to Fill, which is what you want here You can also dock the control to any of the four sides of theclient area by clicking in one of the four areas around the edge of the pop-up or have it undocked byclicking in the area labelled None The form in the Editorpane should now look like Figure 22-5.The tab control has two tabs, but you can add another by clicking the arrow on the top edge of the con-trol toward the right Just click Add Tab from the pop-up You’ll need to change the text on each of thetabs to something more meaningful and change the (Name)property values too Go to the Propertieswindow for the TabControlcontrol — right-clicking the control and selecting Properties from the pop-

up displays the window if it is not already visible — then select the value field for the TabPageserty and click the ellipsis that appears The Tab Page Collection Editor dialog box shown in Figure 22-6displays

Trang 5

prop-Figure 22-4

Figure 22-5

The text on the tab should reflect the lottery name to which the controls on this tab relate, so I changedthe (Name)property value to lottoTaband the Textproperty value to Lotto, as shown in Figure 22-6.The (Name)property value is the name used in the Form1class for the variable that references this tab,and the Textproperty value is the text on the tab

Trang 6

Figure 22-6

The tab labelled tabPage2is for an entry to a second lottery, which in my case is called Euromillions.Again, you can choose whatever lottery you prefer Click tabPage2in the left pane to display the proper-ties for it in the right pane; after you select the new tab you should see that the name in the left pane fortabPage1has been altered to lottoTaband the text on the first tab in the form has been updated I setthe Textproperty value for tabPage2as Euromillionsand the (Name)property value as euroTab.You’ll use the third tab to display a Web page for entering a lottery so change the Textproperty value for tabPage3to Web Pageand the name property value to webTab When you have completed that, you can click the OK button to close the dialog box

Using GroupBox Controls

You can use a GroupBoxcontrol to collect other controls together in a group A GroupBoxcontrol alsodelineates the group with a line boundary and allows you to label the group if you want A Lotto lotteryentry consists of six different numbers that are from 1 to 49 so you’ll want to group together the controlsthat will display these numbers Add a GroupBoxcontrol to the Lottotab by clicking the control in theToolboxwindow and then clicking in the Lottotab You can then modify the Text, (Name), and Dockproperty values for the GroupBoxto the values shown in Figure 22-7

The Textproperty value indicates the range of possible values for the lottery entry that is displayed onthis tab The value for the Dockproperty makes the GroupBoxcontrol fill its container, which is the Lottotab on the Tabcontrol The (Name)property value determines the name of the variable in the Form1classthat identifies this control

The lottery entry on the Euromillions tab involves two groups of values, one group of five different valuesfrom 1 to 50 and a second group of two different “star” values each from 1 to 9 Numbers in the firstgroup can be the same as the two “star” values Use yet another container in the Euromillions tab, so click

on SplitContainerin the Containersgroup in the Toolboxwindow and click in the Euromillions tab

to place it there To select a tab, first click the tab label at the top of the tab control — this selects the tabcontrol with the tab label you highlighted; you then click within the display area of the tab to select thehighlighted tab within the control The Dockproperty value for the SplitContainercontrol is Fillbydefault so the control should fill the tab The control has two panes that can each contain further controls.You can drag the divider between the panes to adjust the relative sizes of the panes

Trang 7

Figure 22-8

Trang 8

You can group the contents of each pane in the SplitContainercontrol using a GroupBoxcontrol, soadd a GroupBoxcontrol to each of the panes Set the Text, (Name), and Dockproperties for the GroupBoxcontrol in the upper pane to have the values “Values 1 to 50”, euroValues, and Fill, respectively,and set the Text, (Name), and Dockproperties for the GroupBoxcontrol in the lower pane to have thevalues “Values 1 to 9,” euroStars, and Fill, respectively The Editor window should look likeFigure 22-9.

Figure 22-9

You have quite a hierarchy of controls now The client area of the form contains a tab control and theEuromillions tab on the tab control contains a SplitContainercontrol and each of the panes in theSplitContainercontrol contains a GroupBoxcontrol The next step is to add buttons to each of theGroupBoxcontrols in the panes

Using Button Controls

Buttoncontrols in the Common Controlsgroup are regular buttons that typically appear in a dialogwindow You’ll use a button control to house each value in a lottery entry For the Euromillions lotteryyou’ll need seven buttons, five in the group box in the top pane with values from 1 to 50 and two in thegroup box in the bottom pane with values from 1 to 9

Place five buttons in the group box in the upper pane on the Euromillions tab and add two more in thegroup box in the lower pane below to make an elegant arrangement You can reposition any of the but-tons by dragging it with the mouse whereupon you should see vertical and/or horizontal alignmentguides displayed to help you align the control to the others You can also use the Format > HorizontalSpacing > Make Equalmenu item to make the spacing in a horizontal sequence of controls uniform.The other menu items in the Format menu are worth exploring; they provide for setting the vertical spac-ing, for aligning controls, for centering a selected group of controls in a form, and for adjusting the heightand width of the controls You can select any number of controls by clicking them while holding the Ctrlkey down

Trang 9

Figure 22-10 shows my arrangement for the buttons on the Euromillionstab.

You’ll be generating values to display as the text on these buttons, so you need to change the propertiesfor each of them I suggest you make the values for the Textproperty on the upper five buttons the val-ues 1, 2, 3, 4, and 5, and the values for the Textproperty on the two buttons in the lower pane 1 and 2.You can change the (Name)property for each button too The buttons in the upper pane can have nameseuroValue1, euroValue2, through to euroValue5, and the two on the lower pane euroStar1andeuroStar1 While you’re at it, you might like to change the BackColorproperty for each button thatdetermines the background color I chose the color Silverfor the top five buttons and Goldfor the bot-tom two — where both colors are from the Webpalette When you have completed that, the applicationwindow with the Euromillionstab selected should look as shown in Figure 22-11

Now you can return to the Lottotab by clicking it in the Editor window You can then add buttons tothat The Lotto lottery is very simple: You just have to choose six different values from 1 to 49 for an entry.You therefore need to add six Buttoncontrols to the GroupBoxthat is already on the Lottotab After youhave arranged the buttons to your satisfaction, change the text on the buttons so they show the defaultvalues 1 to 6 and change the (Name)property for the buttons to lottoValue1, lottoValue2, through tolottoValue6 You can also set the BackColorproperty value for the buttons to a color of your choice —

I chose the SkyBluefrom the Webcolor palette If you compile and execute the application, it shouldlook as shown in Figure 22-12

Figure 22-10

Figure 22-11

Trang 10

Figure 22-12

You can add a control to the Web Pagetab next

Using the WebBrowser Control

Displaying a Web page in the application is going to be much easier than you might have imagined becausethe WebBrowsercontrol in the Common Controlsgroup does all of the work Click the Web Pagetab

in the form the Editor window; then click on WebBrowserin the Toolboxwindow, and click in the tab toplace it there You can display its properties by right-clicking it and selecting Properties from the pop-up.The Properties window for the control is shown in Figure 22-13

Figure 22-13

Figure 22-13 shows the properties after I have amended the (Name)property value to webBrowser, andset a value for the Urlproperty as the URL for the Web page that the control should display; you canenter the URL for your local lottery organization here If you verify that the Dockproperty value is Fill,

Trang 11

that’s all that’s required to get the Web page displayed on the tab Of course, the page displays only if yourcomputer has an active Internet connection when you execute the program and the security settings foryour browser do not prevent it from being displayed If you recompile the program an execute it oncemore, the Web Page tab should look more or less like Figure 22-14.

Figure 22-14

If the Web page doesn’t appear, it may be that your Internet connection is not active Note how you getscrollbars by default in the WebBrowsercontrol when they are necessary You can also navigate by selectingactive links in the Web page If the Web page looks scrambled, it may be because you have strict Internet set-tings, in which case adding the Web site to your Trusted Sites zone may fix the problem

You have almost — but not quite — finished the GUI for the application It’s time to review how theapplication is going to work in detail

Operation of the Winning Application

Clicking the Playmenu item displays a complete entry on the tab that is currently visible in the tion window; thus you can apply the Playitem to the Lottotab or the Euromillionstab The valuesfor a lottery entry are displayed in ascending sequence Switching to the Web Page tab displays the Webpage where you can enter a lottery

applica-After an entry has been created, you might want to be able to change a particular value — because youhave an irrational aversion to particular numbers, for instance, or because you don’t believe numbersover 30 are for you Clicking a button could cause a new number to be generated to replace the number

on the button you clicked Of course, the new number would have to be different from all the numbers

in the current entry

Trang 12

Another possibility is that you might want to choose a specific number that you regard to be lucky — abirthday or a birth month, for example, or the number of peas you left on your plate at lunch today Youcould arrange for this possibility by adding a context menu that displays when you right-click on a par-ticular button A Choosemenu item on the context menu could accommodate this Dealing with theevent arising from clicking the context menu item needs a little work because you’ll have to providefor the entry of the data The number that is entered also needs to be validated; the value must be withinthe permitted range, and it must not duplicate an existing value in the current group of buttons.

The Limits > Upperand Limits > Lowermenu items allow a more constrained range of values to beused for generating an entry There need to be checks here, too; the range must be inside the range that ispermitted for a given lottery, and the range must be wide enough to allow the required number of differ-ent values to be generated

Finally the Help > Aboutmenu item should display a message box displaying information about theapplication

The first step in implementing the application so that it operates as described previously is to add a contextmenu for the buttons that display lottery entry values That’s surprisingly easy

Adding a Context Menu

As you saw when developing CLR Sketcher, a context menu in a CLR Forms application is just anothercontrol It’s the ContextMenuStripcontrol that is in the Menus & Toolbarsgroup of controls in theToolboxwindow Click the ContextMenuStripcontrol and then click in the grey area at the bottom of theEditorwindow to add the control to the application The context menu displays in the form below theexisting menu If you click in the first menu, you can insert the item name You can enter &Choosefor thetext for menu item, which makes Alt+Cthe accelerator for the item It would be better to have a moremeaningful name for the context menu, so open the Propertieswindow for the ContextMenuStripcontrol and change its (Name)property value to buttonContextMenu You could also change the valuefor the (Name)property for the Choosemenu item to chooseValue

You can now enable the buttonContextMenucontrol as the context menu for each of the buttons on thetwo lottery entry tabs To do this, set the value of the ContextMenuStripproperty for each button to thename of the ContextMenuStripcontrol, buttonContextMenu The name appears in the drop-down list

in the value cell for the property so you just click it to set the value You can do this for all the buttons on atab at once: Place the mouse cursor above and to the left of the group of buttons and drag the cursor so it’sbelow and to the right of the buttons before releasing it This selects all the buttons and you change theContextMenuStripproperty value in the Properties window for all the selected buttons

Creating Event Handlers

The process of building the GUI graphically using the Form Designcapability has automatically ated code for the controls you have added There is now a member of the Form1class for every controlyou have added to the form, and code to initialize these has been added to the InitializeComponent()function If you look at the function, you’ll see that it now contains a vast amount of code that sets proper-ties for individual controls and assembles controls into their containers Creating the GUI graphically is abreeze — you’ll need a few more brain cells ticking over to move the application on from there

Trang 13

gener-To make the program work the way that you want, you must create event handler functions for the eventsyou want the application to recognize and process, and implement these functions to make user interac-tions with the GUI do what you want Although the code to handle the events cannot be generated auto-matically, the IDE can still help by generating the skeleton event handler functions and registering themwith the event delegates.

You can view the events for a control by clicking the events button in the Propertieswindow for the control This displays all the possible events for the control and you set the name of the function that is tohandle a particular event in the cell to the right of the event name Of course, you identify handler func-tions only for the events you want to recognize and in most instances this is a very small proportion of the possible events for a control You’ll want to create handler functions for the Clickevent for the menuitems for all the menu items and each of the buttons on the tabs You did this in CLR Sketcher through the Properties window but there’s also a shortcut for creating a handler function for a control to respond

to a Clickevent; you just double-click the control in the Editorwindow and the code is created and played, and the function is registered as a handler for the event object This creates a unique event handlerfor the control, but sometimes you’ll want to make a single function handle events of a given type for morethan one control In this case, the Propertieswindow route is the way to do it

dis-Event Handlers for Menu Items

You can start by creating an event handler function for the Playmenu item Double-clicking the menuitem creates the following handler function code:

private: System::Void playMenuItem_Click(System::Object^ sender,

System::EventArgs^ e) {

}This is a skeleton handler containing no code in the body of the function Just to remind you of what youlearned with CLR Sketcher, the first parameter is a handle referencing the control from which the eventoriginated, and the second parameter provides information related to the event The type of the first argu-ment when a handler is called corresponds to the type of the control that originated the event, and this isToolStripMenuItem^in this case because the handler function is called when the Playmenu item isclicked; the menu item handle is stored in the playMenuItemmember of the Form1class and you cancheck out its type in the class definition Similarly, the actual type of the second argument to a Clickevent handler depends on the type of the control

The handler function name that is generated by default is playMenuItem_Click You must not change

the function name in the code In fact, I recommend you do not change any names in the code that is

auto-matically generated; always do it through the Propertieswindow If you don’t like the name that hasbeen created for the event handler function, you can change it through the Clickevent property value inthe Propertieswindow for the control

The name of the handler function has been registered with the event object by the following statement inthe InitializeComponent()function:

this->playMenuItem->Click +=

gcnew System::EventHandler(this, &Form1::playMenuItem_Click);

Trang 14

This statement adds the function name to the Clickdelegate in the playMenuItemobject that is a ber of the Form1class You learned about delegates and how event handler functions are registered inChapter 9.

mem-Adding Members to the Form1 Class

Before you start implementing the handlers for the menu items, there are some additional fields thatyou’ll need to store data relating to the constraints on the values for the lottery entries You know how toadd a new field to the Form1class; it’s the way you have already used extensively to add members to aclass Switch to Class View, right-click the Form1class, and select Add > Add Variablefrom the con-text menu Alternatively, you can just add the code manually, but be sure you don’t intrude on the region

of the class definition that is reserved for use by the Form Design operations You’ll need to add the lowing variables as private members:

fol-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

You also need to add a private field of type Randomto the Form1class:

Random^ random; // Generates pseudo-random numbers

An object of type Randomcan generate pseudo-random values of various types You’ll use this to generatethe values for a lottery entry

All of these fields must be initialized in the class constructor Make sure the Form1constructor definitionlooks similar to this:

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void): lottoValuesCount(6),

Trang 15

Handling the Play Menu Event

The playMenuItem_Click()handler should create a new set of values on the buttons for the tab that iscurrently visible Recall earlier in this chapter that you set the (Name)property values for the tabs in theTabControlcontrol as lottoTaband euroTab If you look in the lower pane of the Class View windowfor the now extensive Form1class, you’ll find two variables of type TabPage^with these names Objects

of type TabPagehave a Visibleproperty of type boolthat has the value trueif the page is visible andfalseif it is not This is just what you need to implement the handler for the Playmenu item

The outline logic for the handler can use the values of the Visibleproperty for the tab pages like this: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}

}

If the Visibleproperty for the lottoTabpage is true, you create a new Lottolottery entry, and if theVisibleproperty for the euroTabpage is true, you create a Euromillions lottery entry Although bothtabs cannot be visible at the same time, it’s as well to test positively for both tab pages because a usermight click the Playmenu item when the Web Page tab is visible

The process for generating a set of values for the two lotteries have some things in common For lotto youmust generate six different random integers in a given range For Euromillions you must generate five dif-ferent integers within a given range and then generate two different integers within another range Ahelper function to generate an arbitrary number of integers within a given range would be useful Youcould define such a function something like this:

void GetValues(array<int>^ values, int min, int max){

// Fill the array with different random integers from min to max

}

Trang 16

The Lengthproperty for the values array tells you how many values are to be generated The callingfunction just needs to create an array of the appropriate size and pass it as the first argument to theGetValues()function The second and third arguments specify the limits for the values to be generated.Add the GetValues()function as a private member of the Form1class and complete the definition like this: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++)

}

}

Any value within the range is fine for the first element Subsequent values must be checked against thepreceding values that have been generated, and the IsValid()function does this Here’s how you canimplement this function:

// 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;

}

Add this function as a privatemember of the Form1class It’s operation is simple: it checks the firstargument against the elements in the array specified by the second argument that have index values lessthan the third argument and returns falseif the first argument is equal to any of the array elements; other-wise, it returns trueto indicate the first argument is valid

The indefinite forloop in the GetValues()function continues to execute and generate new random ues until the IsValid()function returns true, whereupon the inner loop ends and the next iteration ofthe outer forloop executes to find the next unique value

val-You can now use the GetValues()function in the implementation of the Playmenu Clickevent handler:private: System::Void playMenuItem_Click(System::Object^ sender,

Trang 17

{array<int>^ values; // Variable to store a handle to array of integersif(lottoTab->Visible)

{// Generate and set values for Lotto entryvalues = gcnew array<int>(lottoValuesCount); // Create the arrayGetValues(values, lottoUserMinimum, lottoUserMaximum); // Generate valuesSetValues(values, lottoValues);

}else if(euroTab->Visible){

// Generate and set values for Euromillions entryvalues = gcnew array<int>(euroValuesCount);

GetValues(values, euroUserMinimum, euroUserMaximum);

SetValues(values, euroValues);

values = gcnew array<int>(euroStarsCount);

GetValues(values, euroStarsUserMinimum, euroStarsUserMaximum);

SetValues(values, euroStars);

}}The Lotto entry is created in three steps:

1. Create the array to hold the values.

2. Generate the values by calling the GetValues()function

3. Set the values as text on the buttons by calling the SetValues()function

The sequence of steps is repeated twice for the Euromillions lottery entry: once for the set of five valuesand again for the set of two stars

You can make use of the fact that the buttons are contained within a GroupBoxcontrol when menting the SetValues()function The Controlsproperty for a GroupBoxobject returns a collection

imple-on all the cimple-ontrols that have been added to the object The collectiimple-on that is returned by the Controlsproperty for a GroupBoxitself has a default indexed property that accesses the controls in the collec-tion The collection is first-in last-out like a stack, so index values for the property accesses the controls

in the reverse sequence from the sequence in which you added them to the group box You can ment the SetValues()function as a private member of the Form1class like this:

imple-// Set values as text on buttons in a GroupBox controlvoid SetValues(array<int>^ values, GroupBox^ groupBox){

Array::Sort(values); // Sort values in ascending sequenceint count = values->Length - 1;

for(int i = 0 ; i<groupBox->Controls->Count ; i++)safe_cast<Button^>(groupBox->Controls[i])->Text = values[count-i].ToString();}

After sorting the array of values, you set the countvariable as the index value for the last element in thearray The loop then stores the string representation of the values in the Textproperty for each Buttoncon-trol in reverse sequence The expression groupBox->Controls[i]results in a handle of type Control^that references the control corresponding to index iin the collection, and you cast this to type Button^

Trang 18

which you added buttons to the group box determines the sequence of buttons in the Controls collection.

If this does not match the visible sequence of the buttons, the resulting button values will not appear inascending sequence

You don’t have to implement the capability that the SetValues()function provides using the GroupBoxobject All the buttons are explicit members of the Form1class, so you could take the pedestrian approachand access each of them directly to set the value for the Textproperty This will guarantee the buttonsequence is correct if you named them in sequence You need at least two separate functions — one for theLotto entry and one for the Euromillions entry, although the latter might more conveniently be split intotwo functions making three in all Here’s how the function to set values for the Lotto entry might look:void SetNewValues(array<int>^ values)

You can now recompile Ex22_01to see if it all works If you managed to enter all the code without typos,you should be able to generate a Lotto entry like the one shown in Figure 22-15

Figure 22-15

The numbers on the buttons appear in ascending sequence so they look neat and tidy If they do not appear

in sequence, it may be because you did not add the buttons to the GroupBoxcontrol in an orderly manner.The program also produces an entry for the Euromillions lottery as in Figure 22-16

Trang 19

Figure 22-16

Now that the basic functionality is there, it’s time to develop the application further

Handling Events for the Limits Menu

There are three menu items on the Limitsmenu, and you’ll need a handler for the Clickevent for each.Double-click each of the menu items in turn to generate the handler functions; this will also register each

of them to handle the Clickevent

The Clickevent handler for the Resetmenu item is going to be the easiest to implement because all ithas to do is set the user limits back to be the same as the limits imposed by the lottery that’s currentlyvisible The Clickevent handlers for the other two menu items are going to involve rather more work.You will have to make provision for the limit values to be entered somehow, and the obvious way to dothis is to display a dialog box when the menu item is clicked Clearly, the next step in developing theapplication is to create a dialog box

Creating a Dialog Box

The Toolboxwindow provides several standard dialog boxes; all of them are quite fancy but none ofthem are suitable in this instance Because you need something very specific in this program, you mustcreate the dialog box yourself A dialog box is just a form with its FormBorderStyleproperty value set

to FixedDialog, so you’ll get a lot of help from the Form Designer in creating the dialog box

Select Project > Add New Itemon the main menu, or press Ctrl+Shift+Ato display the Add NewItem dialog Select the UIfrom the Categories:list in the right pane and the template in the rightpane as Windows Formand enter the name as LottoLimitsDialog This is the dialog window you’lldisplay when setting the upper or lower limits for the Lotto entry You’ll create another dialog form forthe Euromillions lottery entry later on When you click the Addbutton, a new form is added to the proj-ect and is displayed in the Editor window The class type for the new dialog box is the name you sup-plied, LottoLimitsDialog

Press F4to display the Propertieswindow for the new form You can change the Textproperty value

to “Set Limits for Lotto Values”, and this text is displayed in the title bar of dialog window; you

Trang 20

can adjust the width of the window by dragging the right side until the title bar text is visible You canalso set the value for the StartPositionproperty in the Layoutgroup of properties to Center Parent

so the dialog window displays at the center of the parent form that displays it — this is the applicationwindow in the example Because this is going to be a dialog box and not an application window, set theFormBorderStyleproperty value to FixedDialog The dialog window should not be minimized ormaximized by the user when it is displayed, so set the MinimizeBoxand MaximizeBoxproperties in theWindow Stylegroup to Falseto remove the capability A dialog box should be closed through the but-tons that you’ll provide in the dialog window, so set the ControlBoxproperty value to Falseto removethe control and system boxes from the title bar

The next step is to add two buttons toward the bottom of the form; these are going to be the OKandCancelbuttons for the dialog box Set the Textproperty value for the button to the left to be “OK”andthe (Name)property to be lottoOK You can also set the value for the DialogResultproperty in theBehaviorgroup to OK The values for the same properties for the right button should be “Cancel”,lottoCancel, and Cancel, respectively The effect of setting the DialogResultproperty value for thebuttons is that the value of the DialogResultproperty for the dialog box is set to the value correspon-ding to the value for the DialogResultproperty for the button that was clicked to close the dialog box.This gives you the possibility of testing programmatically for which button was used to close the dialogand execute different code depending on whether it was the OKbutton or the Cancelbutton

Now that you have added the buttons to the dialog box, you can return to the dialog properties and setthe values for the AcceptButtonand CancelButtonproperties in the Miscproperty group to lottoOKand lottoCancel, respectively This has the effect that pressing the Enterkey while the dialog box isdisplayed clicked the OKbutton, and pressing the Esckey clicks the Cancelbutton

You have more than one control in the dialog box that you could use to permit a limit value to beentered You can use a ListBoxcontrol to enable the user to select from a list of possible values, so you can try that here You should add two Labelcontrols to the dialog box form with two ListBoxcontrols alongside, as shown in Figure 22-17

The GUI for the dialog box is complete, but to make it do what you want you are back in coding mode

Trang 21

Adding a List to a ListBox

The list that a ListBoxcontrols 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 listbox, 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 Int32whenever necessary The Itemsproperty for a ListBoxobject returns

a reference to a collection of the objects in the list box; this collection has an Add()method that adds anobject that you pass as the argument to the list A ListBoxobject has a large number of properties includ-ing the Enabledproperty that has the value truewhen the user can interact with the list box and thevalue falsewhen interaction is to be inhibited

The basic process for loading up the list for a list box is the same for both ListBoxcontrols, so you couldcode a private function member of the LottoLimitsDialogclass that is generalized to add a range ofintegers to a list box:

void SetList(ListBox^ listBox, int min, int max, int selected){

listBox->BeginUpdate(); // Suppress drawing the listboxfor(int n = min ; n <= max ; n++)

listBox->Items->Add(n);

listBox->EndUpdate(); // Resume drawing the list boxlistBox->SelectedItem = Int32(selected);

} The arguments to the SetList()function are the list box for which the list is to be added, the minimumand maximum integers in the range to be added, and the integer that is to be selected in the list box Thefunction adds integers from minto maxinclusive to the list box using the Add()function for the collec-tion object that is returned by the Itemsproperty for the ListBoxobject 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 forthe SelectedItemproperty 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 beaccessed from a function belonging to the Form1object; the event handler for the menu items have responsi-bility for retrieving the limit value and storing it in the Form1object One way to do this is to add a couple

of private members to the LottoLimitsDialogclass to store the upper and lower limit values and thenadd public properties to the class to make the values available externally Adding the following code to theLottoLimitsDialogclass definition does that:

private:

int lowerLimit; // Lower limit from controlint upperLimit; // upper limit from controlpublic:

property int LowerLimit // Property accessing lower limit{

int get(){ return lowerLimit; }void set(int limit)

{

Trang 22

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);

}}

You need to be able to update the properties because the Clickevent handler for the Limits > Resetmenu item changes the limits, and you want the ListBoxobjects to have whatever is the current upper orlower limit selected As well as storing the value in the class object, you also update the ListBoxobjects

to reflect the new limits

You can now create two public member functions in the LottoLimitsDialogclass that sets up the twoListBoxcontrols:

SetList(lottoUpperList, min, max, selected);

upperLimit = selected;

}Each function uses the SetList()function to set the range of values in the corresponding ListBoxobjectand then sets the selectedvalue in the member for storing the limit

Handling the Dialog Button Events

Add an event handler function for the Clickevent for the OK Buttonobject, so return to the Designtabfor the LottoLimitsDialogform and double-click the OK button to add the skeleton code

You don’t need to add a handler for the Clickevent for the Cancelbutton The effect of clicking thebutton is to close the dialog box and no further action is required

You can implement the handler for the Clickevent for the OKbutton like this:

System::Void lottoOK_Click(System::Object^ sender, System::EventArgs^ e)

{

// If there’s a currently selected upper limit item, save it

Trang 23

if(lottoUpperList->SelectedItem != nullptr)upperLimit = safe_cast<Int32>(lottoUpperList->SelectedItem);

// If there’s a currently selected lower limit item, save itif(lottoLowerList->SelectedItem != nullptr)

lowerLimit = safe_cast<Int32>(lottoLowerList->SelectedItem);

}The function first stores the upper limit value from the lottoUpperList ListBoxobject in the membervariable you added for that purpose The SelectedItemproperty for a ListBoxobject makes the cur-rently selected item available as a handle of type Object^and as a precaution the code verifies that thehandle returned is not null Before storing the selected item you must cast it to its actual type — typeInt32 Auto-unboxing then takes care of converting the object to an integer The handler next stores thelower limit value from the other ListBoxobject in the same way When the handler finishes executing,the dialog box is closed automatically

Controlling the State of the ListBox Objects

The same dialog object is used in the response to the Clickevents for both the Limits > UpperandLimits > Lowermenu items, but you don’t want to allow both list boxes to be changed in either case.For the Uppermenu item event you’ll want the selection of a lower limit to be inhibited, and for theLowermenu item you’ll want the list box for the upper limit to be inhibited You could add a couple ofpublic function members to the LottoLimitsDialogclass to make this possible Here’s the function toset the state of the ListBoxobjects for the Uppermenu item:

void SetUpperEnabled(){

lottoUpperList->Enabled = true; // Enable upper list boxlottoLowerList->Enabled = false; // Disable lower list box}

You set the Enabledproperty for the lottoUpperListobject to trueto allow the user to interact with

it Setting the Enabledproperty for lottoLowerListto falsemakes it read-only

For the Lowermenu item you do the reverse:

void SetLowerEnabled(){

lottoUpperList->Enabled = false; // Disable upper list boxlottoLowerList->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’tyet have a dialog object The application window object takes care of that

Creating the Dialog Object

The Form1class constructor can create the dialog object It can also initialize the ListBoxobjects in thedialog Add a private member to the Form1 class that stores the handle to the dialog box:

private: LottoLimitsDialog^ lottoLimitsDialog;

Trang 24

Add the following lines of code to the body of the Form1constructor:

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 statementscall the functions that initialize the lists in the ListBoxobjects The maximum value in the ListBoxobject 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 mum for the lower limit must be 44 — if it was any higher you could not create six different values Thesame reasoning 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 lottoUserMinimumand lottoUserMaximumvalues

maxi-Because you refer to the LottoLimitsDialogclass name in the Form1class constructor, you’ll need toadd an #includedirective 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 Clickevent handlers for the Upperand Lowermenu items in the Limitsmenu 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 theShowDialog()function You can implement the Clickevent handler functions like this:

System::Void lowerMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {

// Update user limits from dialog propertieslottoUserMaximum = lottoLimitsDialog->UpperLimit;

lottoUserMinimum = lottoLimitsDialog->LowerLimit;

}}

Trang 25

if(result == ::DialogResult::OK){

// Update user limits from dialog propertieslottoUserMaximum = 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 thendisplay 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 thedialog object instead

When you call the ShowDialog()function, it does not return until the dialog box closes This meansthat the code to update the limits is not executed until the new limits have been recorded in the dialogobject by the Clickevent handler for the lottoOKbutton 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 accessdata that might have been changed in the dialog box, you need another way to do it Adding a handlerfunction for the Closingevent for the dialog form is one possibility; another would be to deal withtransferring the data in the handler for the button that closes the dialog box

The ShowDialog()function returns a value of the enumeration type DialogResultand you store this inthe local variable, result The return value from the ShowDialog()function indicates which button in thedialog was clicked, and if the value is the enumeration constant ::DialogResult::OK, it indicates that the

OKbutton was clicked Thus the code in each handler function updates only the lottoUserMaximumandLottoUserMinimumfields when the OKbutton was used to close the dialog

Note the use of the ::operator in the type specification ::DialogResultand in the expression::DialogResult::OK The scope resolution operator is necessary preceding the DialogResultname

to distinguish the name of the enumeration at global scope from the property with the same name that

is a member of the Form1class

Of course, you could access the DialogResultproperty for the lottoLimitsDialogobject directly, soyou could write the ifstatement as:

if(lottoLimitsDialog->DialogResult == ::DialogResult::OK){

// Update user limits from dialog propertieslottoUserMaximum = lottoLimitsDialog->UpperLimit;

lottoUserMinimum = lottoLimitsDialog->LowerLimit;

}The former version is better because it is obvious that you are checking the value returned by theShowDialog()function

At the moment, the Clickevent handler for the OKbutton does not validate the input values It is rently quite possible to set the lower and upper limits to values that make it impossible to assign sixunique values for the lottery entry You can use the DialogResultproperty for the form to deal withthe problem

Trang 26

cur-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 Clickevent handler for the OKbutton in the dialog class to check for this:

System::Void lottoOK_Click(System::Object^ sender, System::EventArgs^ e)

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);

Now the function saves the values selected in the ListBoxobjects in the local variables lowerand upper

If the values differ by less than 5, a message box is displayed and closing of the dialog box is inhibited bysetting the value of the DialogResultproperty to None The static Show()function in the MessageBoxclass displays a message box that is customized by the arguments to the function This version of theShow()function used here accepts four arguments as shown in the following table

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

mes-sage box The MessageBoxButtonsenumeration defines the followingvalues:

OK, OKCancel, YesNo, YesNoCancel, RetryCancel,AbortRetryIgnore

Trang 27

There are a significant number of overloaded versions of the static Show()function that range from the verysimple 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 tothat shown in Figure 22-18

Figure 22-18

As you see, you automatically get a scrollbar for scrolling through the list of items in a list box Note thatscrolling to a given item does not select it You must click on the item to select it before clicking the OKbutton The circular red icon with the white cross was specified by the fourth argument to the Show()function, and the single OKbutton is the result of the third argument

The Show()function that you call to display a message box returns a value of type DialogResultthatindicates 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 OKbutton in the limits log box, you could decide whether or not to close the limits dialog box using the value returned by theShow()function for the message box:

dia-System::Void lottoOK_Click(System::Object^ sender, System::EventArgs^ e) {

Parameter Type Description

MessageBoxIcon An enumeration constant specifying the icon to appear in the message

box The MessageBoxIconenumeration defines the following values:

Asterisk, Exclamation, Error, Hand, Information, None,Question, Stop, Warning

Trang 28

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;

elseDialogResult = ::DialogResult::Cancel;

Trang 29

Handling the Reset Menu Item Event

You can implement the event handler for the Resetmenu item like this:

System::Void resetMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {

if(lottoTab->Visible){

// Reset user limits for LottolottoUserMaximum = lottoUpperLimit;

lottoUserMinimum = lottoLowerLimit;

lottoLimitsDialog->UpperLimit = lottoUpperLimit;

lottoLimitsDialog->LowerLimit = lottoLowerLimit;

}else if(euroTab->Visible){

// Reset user limits for EuromillionseuroUserMaximum = euroUpperLimit;

Adding the Second Dialog

The second dialog box for setting limits for the Euromillions lottery is going to be easy; it’s the sameprocess as for the first dialog box Create a new form in the project by pressing Ctrl+Shift+Ato dis-play the Add New Itemdialog box and select the UIcategory and the Windows Formtemplate; thename should be EuroLimitsDialog You can set property values for this dialog box in much the sameway as for the previous dialog

Trang 30

You can add OKand Cancel buttons to the dialog form next Set the Textproperty values for the buttons

to “OK”and “Cancel”and the (Name)property values to euroOKand euroCancel, respectively Youshould also set the DialogResultproperty values to OKand Cancel With the buttons defined, you canreturn to the properties for the dialog form and set the AcceptButtonand CancelButtonproperty val-ues to euroOKand euroCancel, respectively Set the value of the AcceptButtonproperty for the form

to be euroOK

In the interests of getting experience of a wider range of controls, you’ll forego consistency in the cation, and you won’t use ListBoxcontrols to handle the input as you did in the first dialog box In thisdialog box you need to provide for the entry of upper and lower limits for the set of five values as well

appli-as the set of two stars It won’t make for a very elegant implementation, but to maximize the variety ofcontrols you work with you’ll use NumericUpDowncontrols for the former and ComboBoxcontrols forthe latter You can add these controls together with associated Labelcontrols to the dialog form witheach group of controls placed within a GroupBoxcontrol, as illustrated in Figure 22-20 Obviously you’llneed to add the GroupBoxcontrols first and then place the other controls within them

Figure 22-20

You can set the value of the Textproperty for each Labelcontrol as shown in Figure 22-20 The font sizefor the labels has been changed to 9 point To identify the function of the controls within each group box,the value for the Textproperty for the upper group box has been set to “Set Values Limits”and that

of the lower group box “Set Stars Limits.”You won’t be accessing the GroupBoxobjects in the code,

so the (Name)property values for these are of no importance

The values for the (Name)properties for the NumericUpDowncontrols in the upper group box should beset to lowerValuesLimitsand upperValuesLimits You can set the values that these controls display

by setting values for the Maximumand Minimumproperties These values for the lowerValuesLimitscontrol on the left should be 45 and 1 respectively, and the values for the Maximumand Minimumproper-ties for the control to the right should be 49 and 5 respectively You can set the value of the Valueprop-erty for the upperValuesLimitcontrol to 49; this is the value displayed initially in the control If youalso set the ReadOnlyproperty value for each of the NumericUpDowncontrols to True, this prevents theentry of a value from the keyboard You are using the NumericUpDowncontrol very simply here You can

Trang 31

change the up down increment by setting the Incrementproperty value The Incrementproperty is oftype Decimalso you can set this to non-integral values, too.

You can set the values of the (Name)property for the ComboBoxcontrols in the lower group box tolowerStarsLimitsand upperStarsLimits You can enter values to be displayed in a ComboBoxquiteeasily Click the small arrow at the top right of the leftmost ComboBoxcontrol to display the menu shown

Trang 32

Getting the Data from the Dialog Controls

You’ll get the limit values back from the controls in essentially the same way as you did for the dialogbox for Lotto limits You can add some new data members to the EuroLimitsDialogclass to hold theuser limit values first:

lowerValuesLimits->Value = limit; // Set as selected in NumericUpDown }

upperValuesLimits->Value = limit; // Set as selected in NumericUpDown }

}

property int LowerStarsLimit

{

Trang 33

int get() { return lowerStarsLimit; }void set(int limit)

{lowerStarsLimit = limit;

lowerStarsLimits->SelectedItem = limit; // Set as selected in ComboBox lowerStarsLimits->SelectedIndex = // Set index for selected item

lowerStarsLimits->FindString(limit.ToString());}

}property int UpperStarsLimit{

int get() { return upperStarsLimit; }void set(int limit)

{upperStarsLimit = limit;

upperStarsLimits->SelectedItem = limit; // Set as selected in ComboBox upperStarsLimits->SelectedIndex = // Set index for selected item

upperStarsLimits->FindString(limit.ToString());}

}The get()function for each property returns the value of the corresponding private member of the dia-log class The set()function sets the value of the data member and also updates the control in the dialogbox so that the value set becomes the selected value The SelectedIndexproperty value is the index tothe selected item You set this using the FindString()function for the ComboBoxcontrol that returns theindex value for the first occurrence of the argument in the control’s collection of items The value at thisposition is displayed initially in the control

Add a Clickevent handler for the OKbutton in the EuroLimitsDialogclass by double-clicking thebutton in the Design window You won’t need to implement a handler for the Cancelbutton You canimplement the OKbutton handler like this:

System::Void euroOK_Click(System::Object^ sender, System::EventArgs^ e) {

::DialogResult result;

// get the limits for values int valuesLower = Decimal::ToInt32(lowerValuesLimits->Value);

int valuesUpper = Decimal::ToInt32(upperValuesLimits->Value);

if(valuesUpper - valuesLower < 4) // Check for an adequate range{

result = MessageBox::Show(this, // Range insufficient so

“Upper values limit: “+valuesUpper + // display message box

“ Lower values limit: “+ valuesLower+

“\nUpper values limit must be at least 4 greater that the lower limit.”+

“\nTry Again.”,

“Limits Invalid”,MessageBoxButtons::OKCancel,MessageBoxIcon::Error);

Trang 34

if(result == ::DialogResult::OK) // If message box OK clickedDialogResult = ::DialogResult::None; // prevent dialog from closingelse // Messag box Cancel clickedDialogResult = ::DialogResult::Cancel; // so close the dialogreturn;

}

// Get stars limits

int starsLower = lowerStarsLimits->SelectedItem == nullptr ?

lowerStarsLimit :Int32::Parse(lowerStarsLimits->SelectedItem->ToString());

int starsUpper = upperStarsLimits->SelectedItem == nullptr ?

upperStarsLimit :Int32::Parse(upperStarsLimits->SelectedItem->ToString());

if(starsUpper - starsLower < 1) // Check for an adequate range{

result = MessageBox::Show(this, // Range insufficient so

“Upper stars limit: “+starsUpper + // so display message box

“ Lower stars limit: “+ starsLower+

“\nUpper stars limit must be at least 1 greater that the lower limit.”+

“\nTry Again.”,

“Limits Invalid”,MessageBoxButtons::OKCancel,MessageBoxIcon::Error);

if(result == ::DialogResult::OK) // If message box OK clickedDialogResult = ::DialogResult::None; // prevent dialog from closingelse // Message box Cancel clickedDialogResult = ::DialogResult::Cancel; // so close the dialog}

// Store the new limits

on the safe side you check whether it is null If it is null, you set the local variable to the current valuerecorded in the dialog object; if it isn’t null, you store the value represented by the SelectedItemprop-erty You can’t store the value directly, but calling the ToString()function for the object produces astring representation of the object that you are then able to convert to type intusing the static Parse()function in the Int32class

Trang 35

You will need a private member of the Form1class that stores a handle to the new dialog box:

private:

EuroLimitsDialog^ euroLimitsDialog; // Dialog to set Euromillions limitsYou can add the following statements to the end of the code in the Form1class constructor to create thedialog object and update the properties for the stars limit values:

euroLimitsDialog = gcnew EuroLimitsDialog;

euroLimitsDialog->LowerStarsLimit = euroStarsLowerLimit;

euroLimitsDialog->UpperStarsLimit = euroStarsUpperLimit;

By setting the LowerStarsLimitand UpperStarsLimitproperties for the dialog object, you ensurethat the ComboBoxcontrols show these values when the dialog box is initially displayed If there is noselected item set for a ComboBoxcontrol, it displays nothing initially

Don’t forget to add the #includedirective for the EuroLimitsDialogclass definition to Form1.h:

#include “EuroLimitsDialog.h”

Disabling Input Controls

When the Limits > Uppermenu item is clicked, you want to prevent the input for a lower limit beingentered, and when the Limits > Lowermenu item is selected, you want to prevent input for an upperlimit value You can add a couple of member functions to the EuroLimitsDialogclass to make thispossible:

public:

// Disables controls for selecting upper limitsvoid SetLowerEnabled(void)

{upperValuesLimits->Enabled = false;

upperStarsLimits->Enabled = false;

lowerValuesLimits->Enabled = true;

lowerStarsLimits->Enabled = true;

}// Disables controls for selecting lower limitsvoid SetUpperEnabled(void)

{upperValuesLimits->Enabled = true;

upperStarsLimits->Enabled = true;

lowerValuesLimits->Enabled = false;

lowerStarsLimits->Enabled = false;

}The value of the Enabledproperty for a control determines whether it is enabled A truevalue enablesthe control, and a value of falsedisables it so the user cannot interact with it The SetLowerEnabled()function disables the controls used to enter upper limits and enables those for entry of lower limits TheSetUpperEnabled()function does the reverse

Trang 36

Updating the Limits Menu Item Handlers

The last step to complete the support for entering limits for the Euromillions lottery is to update theClickevent handlers in the Form1class for the items in the Limitsmenu The handler for the Uppermenu item should be modified as follows:

System::Void upperMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {

lottoUserMaximum = lottoLimitsDialog->UpperLimit;

lottoUserMinimum = lottoLimitsDialog->LowerLimit;

}}

}

The local variable resultis used in both ifstatements, so it is now declared at the beginning of thefunction After enabling the controls in the dialog box appropriately by calling the SetUpperEnabled()function for the dialog object, you display the dialog box as modal If the user closes the dialog box byclicking the OKbutton, you store the results available through the properties of the dialog object.The changes to the handler for the Clickevent for the Lowermenu item are very similar:

System::Void lowerMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {

lottoUserMaximum = lottoLimitsDialog->UpperLimit;

lottoUserMinimum = lottoLimitsDialog->LowerLimit;

}}

Trang 37

else if(euroTab->Visible){

euroLimitsDialog->SetLowerEnabled();

result = euroLimitsDialog->ShowDialog(this);

if(result == ::DialogResult::OK){

Implementing the Help > About Menu Item

This is easy now that you know about the MessageBoxclass You can just show a message box when theHelp > Aboutmenu item is clicked:

System::Void aboutToolStripMenuItem_Click(System::Object^ sender,

System::EventArgs^ e) {

MessageBox::Show(L”© Copyright Ivor Horton”, L”About A Winning Application”,

MessageBoxButtons::OK, MessageBoxIcon::Exclamation);

}When the the menu item is clicked, the handler function displays the message box shown in Figure 22-23

Figure 22-23

Handling a Button Click

Clicking a button should change the value on the button to a new random value Of course, the valuemust be different from values on the other buttons as well as being different from the value for the button

Trang 38

that was clicked It would be a good idea to present the whole set in sorted order; this may result in thenew value being on a different button, but that’s likely to be better that not having the values in sequence.The process for handling a button click is going to be the same for all the buttons, so you’ll be able toeconomize on code by creating a generalized function to do the work You can define a private functionmember of the Form1class that generates a new value for a given Buttonobject from an array of buttons:// Generates a new value for button different from current button values

void SetNewValue(Button^ button, array<Button^>^ buttons,

int lowerLimit, int upperLimit){

int index = 0; // Index of button in buttons

// Array to store button values

array<int>^ values = gcnew array<int>(buttons->Length);

// Get values from buttons 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

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 we get a good one

The first two function parameters are the button that is to have a new number and the array of buttons inthe group to which the first button belongs The next two parameters specify the lower and upper limitsfor the values The current values of the buttons in the array are stored in the values array in the first loop.This loop also finds the index value in the buttonsarray for the Button^handle that is the first argu-ment You need this so you know which element of the valuesarray is to be replaced by a new value.The new value is created in the indefinite forloop This is the same mechanism that you used to createthe values for the button in the first instance After you have a valid new value, you store it in the valuesarray You then sort the elements in the valuesarray before storing them as the values for the Textprop-erties for the buttons in the buttonsarray You’ll be able to use this function for dealing with the Clickevents for all of the buttons

Trang 39

If you have not already done so, double-click the first button on the Lotto tab to generate a Clickeventhandler function for it You can edit the name of the handler function by opening the Propertiestab for the button, selecting the Eventsbutton, and changing the value for the Clickevent When you pressEnter, the code is updated with the new name I changed the value to lottoValue_Click.

You can amend the Clickevent handler to call the SetNewValue()function you have just added to theForm1class:

System::Void lottoValue_Click(System::Object^ sender, System::EventArgs^ e) {

Button^ button = safe_cast<Button^>(sender);

// Create the array of button handlesarray<Button^>^ buttons = {lottoValue1, lottoValue2, lottoValue3,

lottoValue4, lottoValue5, lottoValue6};

// Replace the value on buttonSetNewValue(button, buttons, lottoUserMinimum, lottoUserMaximum);

}The availability of the SetNewValue()function makes this handler function very simple The first state-ment stores the handle to the button that was clicked The first parameter to the event handler is a handle

to the object that originated the event, so all that’s necessary is to cast it to the appropriate type You thenjust assemble the handles for the buttons in an array and call the new function — job done!

You still have to deal with the Clickevent for the other buttons on the Lotto tab, but this doesn’t require anymore code Open the Propertieswindow for the second button and then click the Eventsbutton If youclick the Clickevent value, you’ll see a list of the existing event handlers If you select lottoValue_Clickfrom the list, the event handler for the first button will be registered as the event handler for the second but-ton, too

You can repeat the process for the remaining four buttons on the Lotto tab so that the one event handler

is called in response to the Clickevent for any of the buttons on the Lotto tab

The Clickevent handlers for the buttons on the Euromillions tab are going to be very easy Double-clickthe first of the five buttons in the Valuesgroup to create the event handler Open the Properties windowfor the button and change the value for the Clickevent to euroValue_Click You can then modify thecode for the handler like this:

System::Void euroValue_Click(System::Object^ sender, System::EventArgs^ e) {

Button^ button = safe_cast<Button^>(sender);

array<Button^>^ buttons = {euroValue1, euroValue2, euroValue3,

euroValue4, euroValue5 };

SetNewValue(button, buttons, euroUserMinimum, euroUserMaximum);

}This works exactly the same as the handler for the Lotto buttons The array contains the handles to the fivebuttons in the values group, and the SetNewValue()function does the rest If you open the Propertieswindow for each of the remaining four buttons in the group, you can select this function to respond to theClickevent for each of them Be sure you select euroValue_Clickand not lottoValue_Click!

Trang 40

Follow the same procedure for the Stars buttons on the Euromillions tab You can implement the handler as:System::Void euroStar_Click(System::Object^ sender, System::EventArgs^ e)

{

Button^ button = safe_cast<Button^>(sender);

array<Button^>^ buttons = { euroStar1, euroStar2 };

SetNewValue(button, buttons, euroStarsUserMinimum, euroStarsUserMaximum);

}

Set the handler for the Clickevent for the second button to be euro_StarClickand you are done Ifyou recompile the example, you should be able to generate a new value for any button on either tab just

by clicking it The last piece to complete the example is to allow the user to enter a value for a button

Responding to the Context Menu

Right-clicking a button brings up a context menu with a single menu item, Choose When the user clicksthis item, the program should display a dialog box that allowed a suitable value to be entered Click thename of the context menu in the Design tab for Form1and then double-click the menu item to create theClickevent handler

The first problem is to determine which group of buttons was clicked to cause the event Each group onbuttons is in its own GroupBoxcontrol, and the GroupBoxclass has a Controlsproperty that returns areference to an object of type Control::ControlCollectionthat represents the collection of controls

in the group box The Control::ControlCollectionclass defines the Contains()function that returnstrueif the control that you pass as the argument is within the collection and falseotherwise Thus youhave a way to determine to which group of buttons the button causing the Clickevent belongs An outlineimplementation of the event handler looks like this:

System::Void chooseValue_Click(System::Object^ sender, System::EventArgs^ e) {

// Get the button that was clicked for the context menu, then

Ngày đăng: 12/08/2014, 19:20