Review

We started this chapter with our work cut out for us; the program was performing as intended, so we just had to go over exactly how it worked. We started with the new main function, which consists of two consecutive “endless” loops (loops that execute until a particular criterion is met, rather than for a predetermined number of times). The first loop keeps executing as long as the user is still entering, modifying, or examining the data in the inventory. When the user is finished with these operations, the only remaining question is whether he or she wants to save the changes to the inventory, so the code in the second loop is designed to find the answer to that question and either save or discard the changes as desired.

The main work of the program is done inside the first loop, which consists of a call to the GetMenuChoice function to find out which operation the user wants to perform, followed by a call to the ExecuteMenuChoice function to execute that operation. When the user selects the “exit” operation, this loop terminates and allows the second loop to start execution.

The GetMenuChoice function is fairly simple, but it uses some functions we hadn't seen previously, including the (non-standard) clrscr function, which clears the screen, the GetCount function, which returns the number of items in the inventory, and the HandleError function from the HomeUtility namespace.

Once the GetMenuChoice function has determined which operation the user wants to perform, the ExecuteMenuChoice function takes over to execute it. It does this with a switch statement that contains one case for each possible operation. All of these cases are fairly similar. The main task of each of them is to request any information that might be required from the user, to display a heading telling the user what operation is in progress, and then to call a function in the Inventory class to do the actual work. If the operation results in a change to the database, the resulting inventory is saved in a backup file so that it can be recovered in the event of a power failure or other crash. Because of the similarity of the code in each of these cases, we won't review them further.

Instead, we will proceed to the functions of the HomeUtility namespace, starting with a set of functions that read numeric input either from the keyboard or a file. The first of these functions is called ReadDoubleFromLine, and as its name suggests, it reads a numeric value from a line of data into a double variable that is a reference argument. Then it calls CheckNumericInput to make sure that there are no garbage characters left in the line after reading the numerical value.

The next function in the HomeUtility namespace, ReadLongFromLine, is almost identical to ReadDoubleFromLine, with the obvious exception of the type of variable it fills in. So I won't bother discussing it further.

The next function, ReadDateFromLine, however, is a little bit more complicated, as it attempts to do a little bit of validation on the data it is reading in from the user or file, and displays an error message if it doesn't like the data being entered.

Next, we have a particularly simple function, IgnoreTillCR. This function ignores characters from an input stream until it gets to a “carriage return”[16], which is generated when the ENTER key is struck. The next function is HandleError, which is used to display an error message and wait for the user to hit ENTER.

[16] This is another name for the character known as “newline”.

Now we get to GetNumberOrEnter, which is considerably more complicated than the other functions in the HomeUtility namespace, as it has the more complex task of taking input from the user one keystroke at a time. This function actually has two “modes” of operation. In the first mode, it accepts only digits, ENTER, and the backspace key, which is used for correcting errors; in the second mode, it also accepts the up and down arrow keys — this mode is used when the user wants to select an item from a list via the SelectItem function. While going through this function, we ran into several new constructs, the most significant being the (non-standard) windos::getkey function that allows us to read one key from the keyboard without having to wait for the user to hit the ENTER key, as is necessary when we use the standard C++ stream input functions. In addition to getkey, we also discussed a set of special keys, such as backspace and newline, which have to be handled differently from the “normal” digit keys in this function. We also saw that it is necessary to copy the key value from an int to a char variable before displaying it on the screen if we want it to come out in the proper format. Sending an int to cout via operator << will display the numeric value of the int, which in this case would not be informative to the user who is expecting to see the key he or she just pressed!

After we covered the details of this GetNumberOrEnter function, including the way in which it handles the backspace key so that the user can back up and change the value of the number, we moved on to the relatively simple HomeUtility::ClearRestOfScreen function, which is used by SelectItem to erase the part of the screen it uses to display its list of items. Even though this ClearRestOfScreen function isn't very complicated, it deserved some discussion because it was the first one where we used a couple of the screen-handling functions from the (non-standard) conio (console I/O) library: gotoxy and clreol, along with another non-standard function called windos::ScreenRows. The gotoxy function, as its name suggests, allows us to position the “cursor” (the place where the next character will be written on the screen) to a particular X and Y coordinate: X is the column number and Y is the row number. Unusually for C or C++, this function starts counting at 1; that is, the first row and first column are numbered 1 rather than 0. The clreol function erases some or all of the characters on the line where the cursor is currently located, from the cursor's position rightward to the end of the line. The windos::ScreenRows function tells us the number of lines on the screen that we can use, which we need so we will know where to stop clearing lines.

HomeUtility::SelectItem, the next function we discussed, is responsible for allowing the user to select from a list of items. It has two arguments: Number, a Vec of indexes into the inventory list of the items to be displayed, and Name, a Vec of textual information about each of those items. It uses these arguments to display a formatted list of items, handling a large number of items by scrolling a portion of the list onto the screen at any one time. Once the user selects one of the items, it returns the information about which one was selected to the calling function.

The final function in this namespace is CheckNumericInput, which is called after every numeric input operation. It determines whether the previous input operation was successful by looking to see whether the next character waiting in the input stream is a newline. If so, all of the characters up to that point have been accepted by the input operator as part of a numeric value, which means that the user didn't type anything that shouldn't be in a number. In that case, the function returns the value true to its caller to indicate success. However, if the next character in the input stream isn't a newline, the user must have included some inappropriate character(s) in the input. In that case, this function displays the leftover characters and returns the value false to the calling function to inform it of the error.

After dealing with that final function in the HomeUtility namespace, we moved on to the changes in the HomeInventory class. These changes weren't too extensive, primarily consisting of better error checking and sorting of the inventory list by the name of the item. Other changes included the ability of the “locate” functions to return a Vec of item indexes rather than just one, the addition of functions to locate items by their category fields, and the ability to print items or item names. The most complicated function in this new version of the class, besides the sorting function, is SelectItemFromCategoryList, because it uses some fairly fancy formatting to get the category information to line up correctly. The main complexity is caused by the necessity to pad the item names to a consistent length so that the category information will start in the same column on the screen for each item no matter how long its name may be. After we have created and displayed the heading, we call the SelectItem function to allow the user to select one of the items.

The final function in the HomeInventory class that we discussed is DeleteItem, which deletes an item from the inventory list.

The changes to the HomeItem class were relatively small. We modified the implementation of operator >> to allow the user to hit ENTER to avoid entering an item, to allow the user to enter only the first letter of the type rather than having to type “Basic” or “Music”, and to improve error handling. The changes in the HomeItemBasic and HomeItemMusic classes consisted of simple improvements to error handling and flexibility in user input, so they didn't require any additional discussion.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset