The Danilo Pizza Application

The Danillo Pizza Application

Introduction

In this exercise, we are going to simulate the order processing of a pizza shop. If you have never written a (mini) application before, you will see that a great deal of your time is spent on the interface design, especially if you don't want your users to look at a boring display all day long.

Prerequisites:

The application we are going to write simulates many of the scenarios you would encounter in a typical (database) assignment. Although there can be different sizes of pizza, for our application, we will use only three. The clerk will select one pizza size using one of three radio buttons. There will be only one pizza per order. Here is the reason I decided to do it like that. Imagine you allow the clerk to specify the number of pizzas per order. This can easily be done by adding an edit box next to each radio button so that the clerk can click the desired size and type the number of pizzas required. If we want the clerk to accept more than one kind of pizza, we can change the radio buttons to check boxes. Suppose a customer comes to the store and places an order of One Small Pizza with Cheese and Extra Onion + One Medium pizza with 1/2 having Pepperoni and the other half having Olives + One Medium Pizza With Onion and Extra Cheese + One Large Pizza With Pepperoni, Onion and Extra Cheese + 2 Buffalo Wings + 2 Pepsi + 4 Root Beer + 1 Sprite... I know you are saying that this is still not such a big deal, and I agree. But to make our application less confusing, we will process one pizza per order.

Since a store should be able to change the prices of items regularly (for example some weeks the store has regular prices and sometimes the store wants to have a "Special), we will provide an edit box for each size so the clerk or management can change the prices of items. This option will also apply to all other items of the application. 

As opposed to pizza sizes where the clerk can select only one, we will let the user add as many toppings as a customer wants. The user will select or not select a toping by clicking its check box. When a particular topping is selected, it displays a check box. This time also, the clerk can change the price of a topping (I know that most stores apply the same price to all toppings but to make our application more entertaining, we will allow different prices for the toppings).

Each of the side items and drinks is represented by a quantity and the item's net price. The clerk validates an item by setting its quantity to a value greater than 0. The application itself calculates the price, as we will see later.
 

Starting the Application

  1. Start Microsoft Visual C++. On the main menu, click File -> new...
  2. From the New dialog box, click the Projects property sheet and click MFC AppWizard (exe).
  3. In the Project Name edit box, type DaniloPizza and press Enter
  4. In the MFC AppWizard - Step 1, click the Dialog Based radio button and press Enter
  5. In the Title edit box, type Danilo Pizza and press Enter.
  6. Click the No, Thank You radio button and press Enter
  7. Press Enter twice or click Finish and OK.
 
 

Designing the Application

  1. Design the application as follows:
     
    Danillo Pizza: Design

    Here is the list of controls. During design, use the Properties window to set the desired properties (although you can use any properties and names you want, my code will reflects the names on this table). Any property not specified should keep its default value (unless you know what you are doing if you decide to change it:
     

    Danillo Pizza: Application Controls 
      
      Control ID Caption Property
    1 Group Box IDC_STATIC Size  
    2 Radio Button IDC_RDO_SMALL &Small Group = TRUE
    3 Edit Box IDC_EDIT_SMALL    
    4 Radio Button IDC_RDO_MEDIUM &Medium Group = no check
    5 Edit Box IDC_EDIT_MEDIUM    
    6 Radio Button IDC_RDO_LARGE &Large Group = no check
    7 Edit Box IDC_EDIT_LARGE    
    8 Group Box IDC_STATIC Side Items  
    9 Static Text   Qty  
    10 Static Text   Price  
    11 Static Text   Total  
    12 Static Text   Buffalo &Wings  
    13 Edit Box IDC_QTY_BUFFWINGS   Number = checked
    14 Edit Box IDC_PRICE_BUFFWINGS    
    15 Edit Box IDC_TOTAL_BUFFWINGS    
    16 Static Text   Brea&d Sticks  
    17 Edit Box IDC_QTY_BREADS   Number = checked
    18 Edit Box IDC_PRICE_BREADS    
    19 Edit Box IDC_TOTAL_BREADS    
    20 Group Box IDC_STATIC Toppings  
    21 Check Box IDC_CHECK_PEPPERONI &Pepperoni  
    22 Edit Box IDC_EDIT_PEPPERONI    
    23 Check Box IDC_CHECK_SAUSAGE &Sausage  
    24 Edit Box IDC_EDIT_SAUSAGE    
    25 Check Box IDC_CHECK_XCHEESE &Extra Cheese  
    26 Edit Box IDC_EDIT_XCHEESE    
    27 Check Box IDC_CHECK_ONIONS &Onions  
    28 Edit Box IDC_EDIT_ONIONS    
    29 Check Box IDC_CHECK_OLIVES Oli&ves  
    30 Edit Box IDC_EDIT_OLIVES    
    31 Group Box IDC_STATIC Drinks  
    32 Static Text   Qty  
    33 Static Text   Price  
    34 Static Text   Total  
    35 Static Text   &Pepsi  
    36 Edit Box IDC_QTY_PEPSI    
    37 Edit Box IDC_PRICE_PEPSI    
    38 Edit Box IDC_TOTAL_PEPSI    
    39 Static Text   &Diet Pepsi  
    40 Edit Box IDC_QTY_DPEPSI    
    41 Edit Box IDC_PRICE_DPEPSI    
    42 Edit Box IDC_TOTAL_DPEPSI    
    43 Static Text   &Sprite  
    44 Edit Box IDC_QTY_SPRITE    
    45 Edit Box IDC_PRICE_SPRITE    
    46 Edit Box IDC_TOTAL_SPRITE    
    47 Static Text   O&range Juice  
    48 Edit Box IDC_QTY_OJ    
    49 Edit Box IDC_PRICE_OJ    
    50 Edit Box IDC_TOTAL_OJ    
    51 Static Text   Root &Beer  
    52 Edit Box IDC_QTY_RBEER    
    53 Edit Box IDC_PRICE_RBEER    
    54 Edit Box IDC_TOTAL_RBEER    
    55 Group Box      
    56 OK Button      
    57 Cancel Button      
    58 Static Text   Total Order  
    59 Edit Box IDC_TOTAL_ORDER    

      

  2. Save your application

Programming the Application

Another area that would take most of your time is surprisingly not the coding itself but the conception of its functionality. Before writing code, you should decide how you want the user to interact with your product, then you should decide how you want the application to react to the changes that occur. A classic way that programmers use to update a dialog box is by using a button. Modern and event programming allow us to process transactions as events occur on Windows controls; and our application is equipped with a few of them.

When the user makes any change to the application, we need to anticipate those changes and to take actions: this is the essence of event programming. Although Microsoft Visual C++ is not as equipped as its rapid application development (RAD) rivals are, we can cope with what we have. When the clerk clicks one of the radio buttons, we can retrieve the price of the pizza size and store it somewhere in anticipation of the total price. In the same way, we will get the price of a topping when the customer requests one.

When the user changes the quantity of an item (side items and drinks), we will first update the sub-total of that item by multiplying the quantity to the net price and we will display this sub-total appropriately.

Unless we want want to use a button that the clerk can click to get the total, we should find another way to display the total price of the order that is being processed. To do this, we could use a "fake" event; for example, we can use the Click event of the dialog box. To be more modern, we will write a function that acts as the central point of the application. Whenever there is a change in the application, we will call this function to update the total price and display it in the appropriate edit box.

To configure this functionality, at all times we will make sure we have and know the total price of each item. 

  1. Press Ctrl + W to access the ClassWizard. Click the Member Variables property sheet.
  2. Double-click each item in the Control IDs list and create the variables as follows:
     
    MFC Class Wizard: This graphic was created on Paint Shop Pro
  3. When you have finished, click OK.
  4. To display default values for some of the controls, in the Workspace, click the ClassView property sheet and expand the CDanilloPizzaDlg folder.
  5. Double-click the CDanilloPizzaDlg constructor to display its section in the DanilloPizzaDlg.cpp file.
  6. Set the default values of the controls as follows:
     
     CDaniloPizzaDlg::CDaniloPizzaDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CDaniloPizzaDlg::IDD, pParent)
    {
    	//{{AFX_DATA_INIT(CDaniloPizzaDlg)
    	m_CheckOlives = FALSE;
    	m_CheckOnions = FALSE;
    	m_CheckPepper = FALSE;
    	m_CheckSausage = FALSE;
    	m_CheckExtraCheese = FALSE;
    	m_PriceLarge = _T("14.55");
    	m_PriceMedium = _T("12.75");
    	m_PriceOlives = _T("0.55");
    	m_PriceOnions = _T("0.25");
    	m_PricePepperoni = _T("0.45");
    	m_PriceSausage = _T("0.35");
    	m_PriceSmall = _T("8.95");
    	m_PriceExtraCheese = _T("0.45");
    	m_PriceBreads = _T("2.15");
    	m_PriceBuffWings = _T("3.25");
    	m_PriceDPepsi = _T("1.45");
    	m_PriceOJ = _T("2.25");
    	m_PricePepsi = _T("1.45");
    	m_PriceRootBeer = _T("1.25");
    	m_PriceSprite = _T("1.45");
    	m_QtyBreads = _T("0");
    	m_QtyBuffWings = _T("0");
    	m_QtyDPepsi = _T("0");
    	m_QtyOJ = _T("0");
    	m_QtyPepsi = _T("0");
    	m_QtyRootBeer = _T("0");
    	m_QtySprite = _T("0");
    	m_TotalBreads = _T("0.00");
    	m_TotalBuffWings = _T("0.00");
    	m_TotalDPepsi = _T("0.00");
    	m_TotalOJ = _T("0.00");
    	m_TotalPepsi = _T("0.00");
    	m_TotalRootBeer = _T("0.00");
    	m_TotalSprite = _T("0.00");
    	m_PriceSize = 1; // This sets the default pizza size to Medium
    	m_TotalOrder = _T("12.75"); // This is the same price as the Medium
    	//}}AFX_DATA_INIT
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
  7. Now, we will need a function that can carry the calculations and let other controls call it when they need to update the total price after a change.
    In the Workspace, right-click the CDanilloPizzaDlg folder and click Add Member Function...
  8. Set the Function Type to void and the Function Name to Calculate
  9. Since this function doesn't need to be accessed outside of the class, we will make it private. Click the Private radio button and click OK.
  10. Implement the function as follows:
     
     void CDaniloPizzaDlg::Calculate()
    {
        double PriceSize, Pepperoni, Sausage,
            ExtraCheese, Onions, Olives, BWings, Bread,
            Pepsi, DietPepsi, Sprite, OJ, RootBeer, TotalOrder;
    
        UpdateData();
    
        // Get the price of pizza depending on the selected size
        if( m_PriceSize == 0 )
            PriceSize = atof(m_PriceSmall);
        else if(m_PriceSize == 1 )
            PriceSize = atof(m_PriceMedium);
        else
            PriceSize = atof(m_PriceLarge);
    
        // Get the price of a topping if it was selected
        if( m_CheckPepper == TRUE)
            Pepperoni = atof(m_PricePepperoni);
        else
            Pepperoni = 0;
    
        if(m_CheckSausage == TRUE)
            Sausage = atof(m_PriceSausage);
        else
            Sausage = 0;
    
        if(m_CheckExtraCheese == TRUE)
            ExtraCheese = atof(m_PriceExtraCheese);
        else
            ExtraCheese = 0;
    
        if(m_CheckOnions == TRUE)
            Onions = atof(m_PriceOnions);
        else
            Onions = 0;
    
        if(m_CheckOlives == TRUE)
            Olives = atof(m_PriceOlives);
        else
            Olives = 0;
    
        // Calculate the price of the side dishes
        // depending on the quantity entered
        BWings = atof(m_TotalBuffWings);
        Bread = atof(m_TotalBreads);
    
    	// Calculate the price of the drink(s)
        Pepsi = atof(m_TotalPepsi);
        DietPepsi = atof(m_TotalDPepsi);
        Sprite = atof(m_TotalSprite);
        OJ = atof(m_TotalOJ);
        RootBeer = atof(m_TotalRootBeer);
    
        TotalOrder = PriceSize
            + Pepperoni + Sausage + ExtraCheese + Onions + Olives
            + BWings + Bread
            + Pepsi + DietPepsi + Sprite + OJ + RootBeer;
        m_TotalOrder.Format("%.2f", TotalOrder);
    
        UpdateData(FALSE);
    }
  11. When a customer adds one of the side items or a drink to his or her order, the clerk types the new quantity. We need to retrieve that quantity, multiply it by the net price of the item and display the sub-total in the corresponding edit box. To change an item's quantity, the clerk clicks in the desired Qty edit box and types a number. After entering the desired value, the user presses Tab or click somewhere else. This means that the edit box loses focus. We will use this LostFocus event to find out if the quantity has changed and to act accordingly.
    Every time a (new) calculation has occured, we will need to call the Calculate() function to update the total price and display it. This makes sure that the clerk doesn't have to perform any calculcation.
    Press Ctrl + W to access the ClassWizard and click the Message Maps property sheet.
  12. In the Object IDs list, click the IDC_QTY_BREADS to select it.
  13. In the Messages list box, double-click EN_KILLFOCUS and change the name of the function to OnQtyBreadsLostFocus:
     
    Add Member Function
  14. Click OK.
  15. Repeat the last three steps to add the following functions:
     
    Object ID Message Function
    IDC_QTY_BUFFWINGS EN_KILLFOCUS OnQtyBuffWingsLostFocus
    IDC_QTY_DPEPSI EN_KILLFOCUS OnQtyDPepsiLostFocus
    IDC_QTY_OJ EN_KILLFOCUS OnQtyOJLostFocus
    IDC_QTY_PEPSI EN_KILLFOCUS OnQtyPepsiLostFocus
    IDC_QTY_RBEER EN_KILLFOCUS OnQtyRBeerLostFocus
    IDC_QTY_SPRITE EN_KILLFOCUS OnQtySpriteLostFocus
  16. Click Edit Code and implement the functions as follows:
     
    void CDaniloPizzaDlg::OnQtyBreadsLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtyBreads.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtyBreads);
    
        Price = atof(m_PriceBreads);
    
        Total = Qty * Price;
        m_TotalBreads.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();
    }
    
    
    void CDaniloPizzaDlg::OnQtyBuffWingsLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtyBuffWings.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtyBuffWings);
    
        Price = atof(m_PriceBuffWings);
    
        Total = Qty * Price;
        m_TotalBuffWings.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();
    }
    
    void CDaniloPizzaDlg::OnQtyDPepsiLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtyDPepsi.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtyDPepsi);
    
        Price = atof(m_PriceDPepsi);
    
        Total = Qty * Price;
        m_TotalDPepsi.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();	
    }
    
    void CDaniloPizzaDlg::OnQtyOJLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtyOJ.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtyOJ);
    
        Price = atof(m_PriceOJ);
    
        Total = Qty * Price;
        m_TotalOJ.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();		
    }
    
    void CDaniloPizzaDlg::OnQtyPepsiLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtyPepsi.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtyPepsi);
    
        Price = atof(m_PricePepsi);
    
        Total = Qty * Price;
        m_TotalPepsi.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();		
    }
    
    void CDaniloPizzaDlg::OnQtyRBeerLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtyRootBeer.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtyRootBeer);
    
        Price = atof(m_PriceRootBeer);
    
        Total = Qty * Price;
        m_TotalRootBeer.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();	
    }
    
    void CDaniloPizzaDlg::OnQtySpriteLostFocus() 
    {
        int Qty;
        double Price, Total;
    
        UpdateData();
        if(m_QtySprite.IsEmpty())
        {
            Qty = 0;
        }
        else
            Qty = atoi(m_QtySprite);
    
        Price = atof(m_PriceSprite);
    
        Total = Qty * Price;
        m_TotalSprite.Format("%.2f", Total);
    
        UpdateData(FALSE);
        Calculate();	
    }
  17. All we have to do now is to call the Calculate() function whenever the user clicks one of the radio buttons. You could also do this for each LostFocus event of a net price of a side item or drink.
    Press Ctrl + W to access the ClassWizard.
  18. In the Message Maps property sheet, click the ID of each radio button. Then, in the Messages list, double-click BN_CLICKED. Accept the suggested name for each function.
  19. In the same way, create a BN_CLICKED function for the ID of each check box and accept the suggested name.
  20. Click Edit Code and implement the functions as follows:
     
    void CDaniloPizzaDlg::OnRdoSmall() 
    {
    	Calculate();
    }
    
    void CDaniloPizzaDlg::OnRdoMedium() 
    {
    	Calculate();
    }
    
    void CDaniloPizzaDlg::OnRdoLarge() 
    {
    	Calculate();
    }
    
    void CDaniloPizzaDlg::OnCheckOlives() 
    {
    	Calculate();	
    }
    
    void CDaniloPizzaDlg::OnCheckOnions() 
    {
    	Calculate();
    }
    
    void CDaniloPizzaDlg::OnCheckPepperoni() 
    {
    	Calculate();
    }
    
    void CDaniloPizzaDlg::OnCheckSausage() 
    {
    	Calculate();
    }
    
    void CDaniloPizzaDlg::OnCheckXcheese() 
    {
    	Calculate();	
    }
  21. Test your program.
 

Home Copyright © 2003 FunctionX, Inc.