Visual Basic - The Pizza Delivery Project

The pizza delivery project has often been the subject of student programming assignments because it offers opportunities to explore a diverse range of controls, use program loops, and even incorporate some database programming and print routines. And, although the application is not intended for commercial use, there is certainly scope for further development - I have seen similar applications offered on the Internet, perhaps written by former students!

  1. Using the Windows Forms App (.Net Framework) template as we did for the "AddressBook" and "AddressBook02" projects, open a new project called "PizzaDelivery". Save your project immediately to create the program folder.
  2. Download the file pizza_delivery.zip using the link below, unzip the file, and copy or save the contents into your project folder's /bin/Debug subdirectory.

pizza_delivery.zip.

  1. Create an interface like the one illustrated below. Note that you will also need two PrintDocument controls (see below for details). The zipped file pizza_delivery.zip contains the database and program icon for the application, which should now be in your project's \bin\Debug\ subfolder.

The PizzaDelivery program interface

The PizzaDelivery program interface


  1. Set the properties of the controls as shown in the table below (properties not shown should be left at their default values). Note: if a control appears within a panel, it should be created as a child of the panel control (make sure the panel is selected before creating each child control). The locations given for these controls are relative to the top left-hand corner of the panel control.

PizzaDelivery Form Controls
ControlNameAdditional Properties
FormfrmPizzaDeliveryBackColor: Dark Orange
Icon: pizza.ico
Size: 775, 600
Text: "Pete's Pizza Delivery"
LabellblHeaderFont: Arial Rounded MT Bold, 14pt
ForeColor: White
Location: 10, 10
Text: "Pete's Pizza Delivery - Order Form"
LabellblTelephoneAutosize: False
ForeColor: White
Location: 472, 13
Size: 66, 20
Text: "Telephone:"
TextAlign: MiddleRight
TextBoxtxtTelLocation: 544, 14
Size: 120, 20
ButtoncmdContinueLocation: 670, 12
Text: "Continue"
PanelpnlLeftBackColor: Yellow
BorderStyle: FixedSingle
Enabled: False
Location: 10, 50
Size: 325, 500
LabellblSurnameAutosize: False
Location: 10, 10
Size: 66, 20
Text: "Surname:"
TextAlign: MiddleRight
LabellblForenameAutosize: False
Location: 10, 35
Size: 66, 20
Text: "Forename:"
TextAlign: MiddleRight
LabellblAddressAutosize: False
Location: 10, 60
Size: 66, 20
Text: "Address:"
TextAlign: MiddleRight
LabellblTownAutosize: False
Location: 10, 110
Size: 66, 20
Text: "Town:"
TextAlign: MiddleRight
LabellblPostcodeAutosize: False
Location: 10, 135
Size: 66, 20
Text: "Postcode:"
TextAlign: MiddleRight
LabellblOrderDetailsAutosize: False
Location: 10, 175
Size: 100, 20
Text: "Order details:"
TextAlign: MiddleLeft
ButtoncmdSaveEnabled: False
Location: 216, 10
Size: 94, 23
Text: "Save Customer"
TextBoxtxtSurnameLocation: 80, 11
Size: 120, 20
TextBoxtxtForenameLocation: 80, 36
Size: 120, 20
TextBoxtxtAddress01Location: 80, 61
Size: 230, 20
TextBoxtxtAddress02Location: 80, 86
Size: 230, 20
TextBoxtxtTownLocation: 80, 111
Size: 120, 20
TextBoxtxtPostcodeLocation: 80, 136
Size: 60, 20
TextBoxtxtOrderLocation: 13, 200
Multiline: True
ScrollBars: Vertical
Size: 300, 280
PanelpnlRightBackColor: Yellow
BorderStyle: FixedSingle
Enabled: False
Location: 345, 50
Size: 400, 500
PanelpnlToppingBackColor: PapayaWhip
BorderStyle: FixedSingle
Location: 10, 10
Size: 120, 150
LabellblToppingFont: Microsoft Sans Serif, 10pt, style=Bold
Location: 26, 10
Text: "Topping"
RadioButtonradTop00Location: 15, 40
Text: "Margherita"
RadioButtonradTop01Location: 15, 60
Text: "Four Seasons"
RadioButtonradTop02Location: 15, 80
Text: "Meat Feast"
PanelpnlBaseBackColor: PapayaWhip
BorderStyle: FixedSingle
Location: 140, 10
Size: 120, 150
LabellblBaseFont: Microsoft Sans Serif, 10pt, style=Bold
Location: 37, 10
Text: "Base"
RadioButtonradBas00Location: 15, 40
Text: "25 cm/10 in."
RadioButtonradBas01Location: 15, 60
Text: "30 cm/12 in."
RadioButtonradBas02Location: 15, 80
Text: "35 cm/14 in."
PanelpnlExtrasBackColor: PapayaWhip
BorderStyle: FixedSingle
Location: 270, 10
Size: 120, 150
LabellblExtrasFont: Microsoft Sans Serif, 10pt, style=Bold
Location: 34, 10
Text: "Extras"
CheckBoxchkExt00Location: 15, 40
Text: "Mushrooms"
CheckBoxchkExt01Location: 15, 60
Text: "Green Peppers"
CheckBoxchkExt02Location: 15, 80
Text: "Anchovies"
CheckBoxchkExt03Location: 15, 100
Text: "Cheese"
ButtoncmdAddItemLocation: 140, 166
Size: 120, 23
Text: "Add Item"
PanelpnlDrinksBackColor: GreenYellow
BorderStyle: FixedSingle
Enabled: False
Location: 10, 200
Size: 250, 150
LabellblDrinksFont: Microsoft Sans Serif, 10pt, style=Bold
Location: 10, 10
Text: "Drinks"
LabellblQtyFont: Microsoft Sans Serif, 10pt, style=Bold
Location: 184, 10
Text: "Qty"
LabellblColaLocation: 12, 41
Text: "Cola"
LabellblLemonadeLocation: 12, 66
Text: "Lemonade"
LabellblOrangeLocation: 12, 91
Text: "Orange"
LabellblWaterLocation: 12, 116
Text: "Mineral Water"
NumericUpDownnudDrk00Autosize: False
Location: 187, 39
Size: 40, 20
NumericUpDownnudDrk01Autosize: False
Location: 187, 64
Size: 40, 20
NumericUpDownnudDrk02Autosize: False
Location: 187, 89
Size: 40, 20
NumericUpDownnudDrk03Autosize: False
Location: 187, 114
Size: 40, 20
ButtoncmdClearLocation: 10, 428
Size: 120, 23
Text: "Clear Order"
ButtoncmdPrintLocation: 10, 457
Size: 120, 23
Text: "Print Delivery Note"
LabellblOrdValAutosize: False
Location: 220, 404
Size; 100, 13
Text: "Order value:"
TextAlign: MiddleRight
LabellblDelChgAutosize: False
Location: 220, 429
Size; 100, 13
Text: "Delivery charge:"
TextAlign: MiddleRight
LabellblOrdTotAutosize: False
Location: 220, 454
Size; 100, 13
Text: "Order total:"
TextAlign: MiddleRight
LabellblOrderValueAutosize: False
BackColor: White
BorderStyle: Fixed3D
Location: 326,400
Size: 60, 20
Text: none
TextAlign: MiddleRight
LabellblDeliveryChargeAutosize: False
BackColor: White
BorderStyle: Fixed3D
Location: 326, 425
Size: 60, 20
Text: noneTextAlign: MiddleRight
LabellblOrderTotalAutosize: False
BackColor: White
BorderStyle: Fixed3D
Location: 326, 450
Size: 60, 20
Text: none
TextAlign: MiddleRight
PrintDocumentprtDeliveryNote-
PrintDocumentprtContinuation-

The commented program code is reproduced in its entirety below. Hopefully the comments, together with the explanatory notes that follow, will be sufficient to inform the reader how the code works. Most of the code is relatively straightforward, and the program essentially brings together various elements that have been the subject of other pages in this section.

The PizzaDelivery project code:

Public Class frmPizzaDelivery
  'Declare database object variables
  Dim con As New OleDb.OleDbConnection
  Dim ds As New DataSet
  Dim da As OleDb.OleDbDataAdapter
  Dim sql As String
  Dim cmd As OleDb.OleDbCommand

  'Declare control arrays
  Dim RadioArrayTopping(0 To 2) As RadioButton
  Dim RadioArrayBase(0 To 2) As RadioButton
  Dim CheckArrayExtras(0 To 3) As CheckBox

  'Declare module variables
  Dim Topping() As String = {"Margherita", "Four Seasons", "Meat Feast"}
  Dim Base() As String = {"9""", "12""", "14"""}
  Dim Extras() As String = {"Mushrooms", "Green Peppers", "Anchovies", "Cheese"}
  Dim Drinks() As String = {"Cola", "Lemonade", "Orange", "Mineral Water"}
  Dim PizzaPrice(,) As Single = {{3.0, 4.0, 5.5}, {3.5, 4.5, 6.0}, {4.0, 5.0, 6.5}}
  Dim ExtraPrice() As Single = {0.5, 0.4, 0.6, 0.5}
  Dim DrinkPrice() As Single = {1.0, 1.0, 1.0, 0.9}
  Dim itemNo As Integer = -1
  Dim strOrder01 As String = ""
  Dim strOrder02 As String = ""
  Dim strDrinks As String = ""
  Dim pizzaVal, drinkVal, orderVal, delivery, total As Single

  'Structure to hold options for each pizza ordered
  Structure pizzaStruct
    Dim Topp As Integer
    Dim Base As Integer
    Dim Ex00 As Boolean
    Dim Ex01 As Boolean
    Dim Ex02 As Boolean
    Dim Ex03 As Boolean
  End Structure

  'Structure to hold drink selection
  Structure drinkStruct
    Dim Drink00 As Integer
    Dim Drink01 As Integer
    Dim Drink02 As Integer
    Dim Drink03 As Integer
  End Structure

  'Declare module structure variables
  Dim pizzaArray(-1) As pizzaStruct
  Dim drinkSelection As drinkStruct


  Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    'Set up control arrays
    RadioArrayTopping(0) = radTop00
    RadioArrayTopping(1) = radTop01
    RadioArrayTopping(2) = radTop02
    RadioArrayBase(0) = radBas00
    RadioArrayBase(1) = radBas01
    RadioArrayBase(2) = radBas02
    CheckArrayExtras(0) = chkExt00
    CheckArrayExtras(1) = chkExt01
    CheckArrayExtras(2) = chkExt02
    CheckArrayExtras(3) = chkExt03
    'Initialise order
    clearOrder()
  End Sub

  Function checkTelNum() As Boolean
    'Make sure telephone number is valid
    Dim strAllowedChars As String = "0123456789() -+ "
    If Len(txtTel.Text) < 5 Then
      Return False
    Else
      For i = 0 To Len(txtTel.Text) - 1
        If InStr(1, strAllowedChars, txtTel.Text(i)) = 0 Then
          Return False
        End If
      Next
      Return True
    End If
  End Function

  Private Sub cmdContinue_Click(sender As Object, e As EventArgs) Handles cmdContinue.Click
    'Check for valid telephone number before proceeding
    If checkTelNum() = False Then
      MsgBox("You have not entered a valid telephone number.")
      txtTel.Focus()
      Exit Sub
    End If
    'If telephone number is valid, disable telephone number input
    'and enable main form functionality
    cmdContinue.Enabled = False
    txtTel.Enabled = False
    pnlLeft.Enabled = True
    pnlRight.Enabled = True
    enableCustomerInput()
    'Open database and check for existing customer using telephone number
    con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=PizzaDelivery.accdb;"
    con.ConnectionString &= " Persist Security Info=False;"
    con.Open()
    sql = "SELECT * FROM Customer WHERE TelephoneNo = '" & txtTel.Text & "'"
    da = New OleDb.OleDbDataAdapter (sql, con)
    da.Fill(ds, "CustInfo")
    con.Close()
    If ds.Tables("CustInfo").Rows.Count = 0 Then
      'If customer telephone number not found, inform user
      'and move focus to customer surname input box
      MsgBox("Number not found in database.")
      cmdSave.Enabled = True
      txtSurname.Focus()
      Exit Sub
    Else
      'Otherwise add customer details to form
      txtTel.Text = ds.Tables("CustInfo").Rows(0).Item(0)
      txtSurname.Text = ds.Tables("CustInfo").Rows(0).Item(1)
      txtForename.Text = ds.Tables("CustInfo").Rows(0).Item(2)
      txtAddress01.Text = ds.Tables("CustInfo").Rows(0).Item(3)
      txtAddress02.Text = ds.Tables("CustInfo").Rows(0).Item(4)
      txtTown.Text = ds.Tables("CustInfo").Rows(0).Item(5)
      txtPostcode.Text = ds.Tables("CustInfo").Rows(0).Item(6)
      'Protect customer details from changes
      disableCustomerInput()
    End If
  End Sub

  Function checkCustomer() As Boolean
    'Make sure customer details are complete
    If txtSurname.Text = "" Then
      MsgBox("Please enter the customer's surname.")
      Return False
    ElseIf txtAddress01.Text = "" Then
      MsgBox("Please enter the customer's address.")
      Return False
    ElseIf txtPostcode.Text = "" Then
      MsgBox("Please enter the customer's postcode.")
      Return False
    Else
      Return True
    End If
  End Function

  Function addItem() As Boolean
    'Declare local variables
    Dim toppingSelected As Boolean = False
    Dim baseSelected As Boolean = False
    Dim top, bas As Integer
    'Check that a base and a topping are selected and get choices
    For i = 0 To 2
      If RadioArrayTopping(i).Checked = True Then
        toppingSelected = True
        top = i
      End If
      If RadioArrayBase(i).Checked = True Then
        baseSelected = True
        bas = i
      End If
    Next
    'If either base or topping not selected, prompt user
    If toppingSelected = False Then
      MsgBox("You have not selected a topping.")
      Return False
    End If
    If baseSelected = False Then
      MsgBox("You have not selected a base.")
      Return False
    Else
      'Increment item number
      itemNo += 1
      'If this is first pizza item enable drinks panel
      If itemNo = 0 Then pnlDrinks.Enabled = True
      'Increase the size of the pizza item array dynamically
      ReDim Preserve pizzaArray(itemNo)
      'Save user choices
      pizzaArray(itemNo).Topp = top
      pizzaArray(itemNo).Base = bas
      pizzaArray(itemNo).Ex00 = CheckArrayExtras(0).Checked
      pizzaArray(itemNo).Ex01 = CheckArrayExtras(1).Checked
      pizzaArray(itemNo).Ex02 = CheckArrayExtras(2).Checked
      pizzaArray(itemNo).Ex03 = CheckArrayExtras(3).Checked
    End If

    pizzaVal = 0 'Reset pizza item value

    For i = 0 To itemNo
      'Calculate total value of pizzas currently selected
      pizzaVal += PizzaPrice(pizzaArray(i).Topp, pizzaArray(i).Base)
      If pizzaArray(itemNo).Ex00 = True Then pizzaVal += ExtraPrice(0)
      If pizzaArray(itemNo).Ex01 = True Then pizzaVal += ExtraPrice(1)
      If pizzaArray(itemNo).Ex02 = True Then pizzaVal += ExtraPrice(2)
      If pizzaArray(itemNo).Ex03 = True Then pizzaVal += ExtraPrice(3)
    Next

    orderVal = pizzaVal + drinkVal 'Calculate order value

    If orderVal >= 10.0 Then
      'If order value is £10.00 or more delivery is free
      delivery = 0.0
    Else
      'If order value is less than £10.00 delivery is £2.00
      delivery = 2.0
    End If

    total = orderVal + delivery 'Calculate total to pay

    'Update order display
    txtOrder.Text = strOrder01
    lblOrderValue.Text = Format(orderVal, "currency")
    lblDeliveryCharge.Text = Format(delivery, "currency")
    lblOrderTotal.Text = Format(total, "currency")
    clearItem() 'clear pizza selection ready for next selection
    If itemNo > 14 Then
      'Number of items per order is limited to 15 - disable input of further items
      MsgBox("You have reached the maximum number of items for a single order.")
      cmdAddItem.Enabled = False
      pnlTopping.Enabled = False
      pnlBase.Enabled = False
      pnlExtras.Enabled = False
    End If
    Return True 'Item was added to order
  End Function

  Sub addDrinks()
    'Get quantities of each drink selected
    drinkSelection.Drink00 = nudDrk00.Value
    drinkSelection.Drink01 = nudDrk01.Value
    drinkSelection.Drink02 = nudDrk02.Value
    drinkSelection.Drink03 = nudDrk03.Value

    drinkVal = 0 'Initialise value of drinks to zero

    'Calculate total value of drinks selected
    drinkVal += DrinkPrice(0) * drinkSelection.Drink00
    drinkVal += DrinkPrice(1) * drinkSelection.Drink01
    drinkVal += DrinkPrice(2) * drinkSelection.Drink02
    drinkVal += DrinkPrice(3) * drinkSelection.Drink03

    orderVal = pizzaVal + drinkVal 'calculate order value

    'Determine whether delivery charge should be applied
    If orderVal >= 10.0 Then
      delivery = 0.0
    Else
      delivery = 2.0
    End If

    total = orderVal + delivery 'calculate total to pay

    'Update order details and clear current pizza item
    txtOrder.Text = strOrder01
    lblOrderValue.Text = Format(orderVal, "currency")
    lblDeliveryCharge.Text = Format(delivery, "currency")
    lblOrderTotal.Text = Format(total, "currency")
    clearItem()
  End Sub

  Sub writeOrder()
    'Construct order string - if order has more than 7 items not including drinks,
    'create a second order string to enable printing of delivery note on two pages
    Dim limit As Integer
    txtOrder.Text = ""
    strOrder01 = ""
    strOrder02 = ""
    If itemNo > -1 Then
      If itemNo > 6 Then
        limit = 6 'Limit first page of delivery note to 7 items
      Else
        limit = itemNo
      End If
      For i = 0 To limit 'Create order string for first page of delivery note
        strOrder01 &= "1 x "
        strOrder01 &= Base(pizzaArray(i).Base) & " "
        strOrder01 &= Topping(pizzaArray(i).Topp)
        If(pizzaArray(i).Ex00 = False And pizzaArray(i).Ex01 = False And _
          pizzaArray(i).Ex02 = False And pizzaArray(i).Ex03 = False) Then
          strOrder01 &= ", no extras."
        Else
          strOrder01 &= ", with extra: "
        End If
        If pizzaArray(i).Ex00 = True Then strOrder01 &= vbNewLine & " " & Extras(0)
        If pizzaArray(i).Ex01 = True Then strOrder01 &= vbNewLine & " " & Extras(1)
        If pizzaArray(i).Ex02 = True Then strOrder01 &= vbNewLine & " " & Extras(2)
        If pizzaArray(i).Ex03 = True Then strOrder01 &= vbNewLine & " " & Extras(3)
        strOrder01 &= vbNewLine & vbNewLine
      Next
      If itemNo > 6 Then 'Create order string for second page of delivery note
        For i = 7 To itemNo
          strOrder02 &= "1 x "
          strOrder02 &= Base(pizzaArray(i).Base) & " "
          strOrder02 &= Topping(pizzaArray(i).Topp)
          If(pizzaArray(i).Ex00 = False And pizzaArray(i).Ex01 = False And _
            pizzaArray(i).Ex02 = False And pizzaArray(i).Ex03 = False) Then
            strOrder02 &= ", no extras."
          Else
            strOrder02 &= ", with extra: "
          End If
          If pizzaArray(i).Ex00 = True Then strOrder02 &= vbNewLine & " " & Extras(0)
          If pizzaArray(i).Ex01 = True Then strOrder02 &= vbNewLine & " " & Extras(1)
          If pizzaArray(i).Ex02 = True Then strOrder02 &= vbNewLine & " " & Extras(2)
          If pizzaArray(i).Ex03 = True Then strOrder02 &= vbNewLine & " " & Extras(3)
          strOrder02 &= vbNewLine & vbNewLine
        Next
      End If
    End If
    writeDrinks() 'Call procedure to create list of drinks ordered
    txtOrder.Text = strOrder01 & strOrder02 & strDrinks 'Concatenate strings for screen output
    'Update display values for goods value, delivery charge and total order value
    lblOrderValue.Text = Format(orderVal, "currency")
    lblDeliveryCharge.Text = Format(delivery, "currency")
    lblOrderTotal.Text = Format(total, "currency")
  End Sub

  Sub writeDrinks()
    'Construct list of drinks and quantities ordered (appended to order string)
    If drinkSelection.Drink00 = 0 And drinkSelection.Drink01 = 0 And _
      drinkSelection.Drink02 = 0 And drinkSelection.Drink03 = 0 Then
      Exit Sub
    End If
    strDrinks = "Drinks:" & vbNewLine
    If drinkSelection.Drink00 > 0 Then
      strDrinks &= " " & drinkSelection.Drink00 & " x " & Drinks(0) & vbNewLine
    End If
    If drinkSelection.Drink01 > 0 Then
      strDrinks &= " " & drinkSelection.Drink01 & " x " & Drinks(1) & vbNewLine
    End If
    If drinkSelection.Drink02 > 0 Then
      strDrinks &= " " & drinkSelection.Drink02 & " x " & Drinks(2) & vbNewLine
    End If
    If drinkSelection.Drink03 > 0 Then
      strDrinks &= " " & drinkSelection.Drink03 & " x " & Drinks(3) & vbNewLine
    End If
    strDrinks &= vbNewLine & vbNewLine
  End Sub

  Private Sub cmdAdd_Click(sender As Object, e As EventArgs) Handles cmdAddItem.Click
    'If user has selected a pizza base and topping, add item to order and update order strings
    If addItem() = False Then
      Exit Sub
    Else
      writeOrder()
    End If
  End Sub

  Private Sub cmdClear_Click(sender As Object, e As EventArgs) Handles cmdClear.Click
    'Clear the current order to cancel, or in readiness for next order
    clearOrder()
    cmdContinue.Enabled = True
    txtTel.Enabled = True
    pnlLeft.Enabled = False
    pnlRight.Enabled = False
  End Sub

  Sub clearOrder()
    'Reset program variables and restore display to initial state
    ds.Clear()
    nudDrk00.Value = 0
    nudDrk01.Value = 0
    nudDrk02.Value = 0
    nudDrk03.Value = 0
    txtTel.Clear()
    txtSurname.Clear()
    txtForename.Clear()
    txtAddress01.Clear()
    txtAddress02.Clear()
    txtTown.Clear()
    txtPostcode.Clear()
    strOrder01 = ""
    txtOrder.Text = ""
    lblOrderValue.Text = ""
    lblDeliveryCharge.Text = ""
    lblOrderTotal.Text = ""
    itemNo = -1
    orderVal = 0
    delivery = 0
    total = 0
    enablePizzaInput()
    clearItem()
  End Sub

  Sub disableCustomerInput()
    'Prevent customer details being accidentally changed
    cmdSave.Enabled = False
    txtSurname.Enabled = False
    txtForename.Enabled = False
    txtAddress01.Enabled = False
    txtAddress02.Enabled = False
    txtTown.Enabled = False
    txtPostcode.Enabled = False
  End Sub

  Sub enableCustomerInput()
    'Allow new customer details to be entered
    cmdSave.Enabled = True
    txtSurname.Enabled = True
    txtForename.Enabled = True
    txtAddress01.Enabled = True
    txtAddress02.Enabled = True
    txtTown.Enabled = True
    txtPostcode.Enabled = True
  End Sub

  Sub enablePizzaInput()
    'Allow further pizza selections to be made
    cmdAddItem.Enabled = True
    pnlTopping.Enabled = True
    pnlBase.Enabled = True
    pnlExtras.Enabled = True
  End Sub

  Sub clearItem()
    'Clear current pizza selection
    For i = 0 To 2
      RadioArrayTopping(i).Checked = False
      RadioArrayBase(i).Checked = False
    Next
    For i = 0 To 3
      CheckArrayExtras(i).Checked = False
    Next
  End Sub

  'update order details and program display if the drink selection changes
  Private Sub nudDrk00_ValueChanged(sender As Object, e As EventArgs) Handles nudDrk00.ValueChanged
    addDrinks()
    writeOrder()
  End Sub

  Private Sub nudDrk01_ValueChanged(sender As Object, e As EventArgs) Handles nudDrk01.ValueChanged
    addDrinks()
    writeOrder()
  End Sub

  Private Sub nudDrk02_ValueChanged(sender As Object, e As EventArgs) Handles nudDrk02.ValueChanged
    addDrinks()
    writeOrder()
  End Sub

  Private Sub nudDrk03_ValueChanged(sender As Object, e As EventArgs) Handles nudDrk03.ValueChanged
    addDrinks()
    writeOrder()
  End Sub

  Private Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
    'Save new customer details to database
    Dim custString As String
    Dim count As Integer = 0

    If checkCustomer() = False Then Exit Sub

    custString = "'" & Replace (txtTel.Text, "'", "''") & "', '" & Replace (txtSurname.Text, "'", "''") _
      & "', '" & Replace (txtForename.Text, "'", "''") & "', '" & Replace (txtAddress01.Text, "'", "''") _
      & "', '" & Replace (txtAddress02.Text, "'", "''") & "', '" & Replace (txtTown.Text, "'", "''") _
      & "', '" & Replace (txtPostcode.Text, "'", "''") & "'"
    con.Open()

    sql = "INSERT into Customer values (" & custString & ") "
    cmd = New OleDb.OleDbCommand (sql, con)
    count = cmd.ExecuteNonQuery
    If count > 0 Then
      MsgBox("Customer record created.")
      disableCustomerInput()
    End If
    con.Close()
  End Sub

  Private Sub cmdPrint_Click(sender As Object, e As EventArgs) Handles cmdPrint.Click
    If checkCustomer() = False Then Exit Sub
    prtDeliveryNote.Print()
    If itemNo > 6 Then
      prtContinuation.Print()
    End If
  End Sub

  Private Sub prtDeliveryNote_PrintPage(sender As Object, e As Drawing.Printing.PrintPageEventArgs) _
    Handles prtDeliveryNote.PrintPage
    'Declare variables for delivery note print procedure (fonts, brushes, print coordinates etc.)
    Dim headerFont As Font = New Font("Arial", 24, GraphicsUnit.Point)
    Dim detailFontBold As Font = New Font("Arial", 10, FontStyle.Bold, GraphicsUnit.Point)
    Dim detailFont As Font = New Font("Arial", 10, GraphicsUnit.Point)
    Dim headerBrush As Brush = Brushes.Blue
    Dim detailBrush As Brush = Brushes.Black
    Dim x As Single
    Dim y As Single
    Dim strOutput As String

    e.Graphics.PageUnit = GraphicsUnit.Inch 'Set print units

    'Most of the code below is setting up parameters for printing various
    'parts of the delivery note and then calling the e.Graphics.DrawString()
    'method to send them to the printer
    strOutput = "Pete's Pizza Delivery Service"
    x = (e.MarginBounds.Left / e.Graphics.DpiX) + 0.5
    y = (e.MarginBounds.Top / e.Graphics.DpiY) + 0.5
    e.Graphics.DrawString(strOutput, headerFont, headerBrush, x, y)
    y += 1
    strOutput = "Delivery address:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    strOutput = txtForename.Text & " " & txtSurname.Text
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    strOutput = txtAddress01.Text
    y += (e.Graphics.MeasureString(strOutput, detailFont).Height)
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    If txtAddress02.Text <> "" Then
      strOutput = txtAddress02.Text
      y += (e.Graphics.MeasureString(strOutput, detailFont).Height)
      e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    End If
    strOutput = txtTown.Text & " " & txtPostcode.Text
    y += (e.Graphics.MeasureString(strOutput, detailFont).Height)
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    y += 0.5
    x -= 1.5
    strOutput = "Telephone:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    strOutput = txtTel.Text
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    y += 0.5
    x -= 1.5
    strOutput = "Order:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    If itemNo <= 6 Then
      strOutput = strOrder01 & strDrinks
    Else
      strOutput = strOrder01 & vbNewLine & vbNewLine & "continued ..."
    End If
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    y = 9
    x = 5.5
    strOutput = "Order value:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    strOutput = "£" & CStr(Format(orderVal, "Fixed")).PadLeft(4)
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    y += 0.5
    x -= 1.5
    strOutput = "Delivery:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    strOutput = "£" & CStr(Format(delivery, "Fixed")).PadLeft(4)
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    y += 0.5
    x -= 1.5
    strOutput = "Total to pay:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    strOutput = "£" & CStr(Format(total, "Fixed")).PadLeft(4)
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    'Return False when no more pages....
    e.HasMorePages = False
  End Sub

  Private Sub prtContinuation_PrintPage(sender As Object, e As Drawing.Printing.PrintPageEventArgs) _
    Handles prtContinuation.PrintPage
    'Print continuation page if more than 7 items ordered (not including drinks)
    Dim headerFont As Font = New Font("Arial", 24, GraphicsUnit.Point)
    Dim detailFontBold As Font = New Font("Arial", 10, FontStyle.Bold, GraphicsUnit.Point)
    Dim detailFont As Font = New Font("Arial", 10, GraphicsUnit.Point)
    Dim headerBrush As Brush = Brushes.Blue
    Dim detailBrush As Brush = Brushes.Black
    Dim x As Single
    Dim y As Single
    Dim strOutput As String

    e.Graphics.PageUnit = GraphicsUnit.Inch
    strOutput = "Pete's Pizza Delivery Service"
    x = (e.MarginBounds.Left / e.Graphics.DpiX) + 0.5
    y = (e.MarginBounds.Top / e.Graphics.DpiY) + 0.5
    e.Graphics.DrawString(strOutput, headerFont, headerBrush, x, y)
    y += 1
    strOutput = "Order continued:"
    e.Graphics.DrawString(strOutput, detailFontBold, detailBrush, x, y)
    x += 1.5
    strOutput = strOrder02 & strDrinks
    e.Graphics.DrawString(strOutput, detailFont, detailBrush, x, y)
    e.HasMorePages = False
  End Sub
End Class


General Notes

This is probably one of the longest pieces of coding featured on these pages to date, which reflects the relative complexity of the program and the large number of controls used. When the program starts, the only active control is the text box that allows the user to enter a customer's telephone number. This hopefully prevents any duplication of effort by making sure that, if the customer details are already stored in the database, they will automatically be displayed in the left-hand panel of the application. If this is the case, the customer information fields are populated using the stored details, and the fields are disabled to prevent inadvertent changes.

If the caller is a new customer, the user is informed, and may enter the new details in the text fields provided. They can also add the new customer details to the database at any point before the order is cleared, so long as the information entered is complete. Once the customer details have been saved, the input boxes will be disabled to prevent further changes.

Note that the application does not currently include an administrative function to allow customer data to be deleted or updated - this is a program feature that could be added (there are no doubt many improvements that could be made!).

Radio buttons are used to allow the user to select exactly one topping and one base per item, and a pizza cannot be added to the order until both have been selected. These parameters must be specified for each pizza item ordered, and will determine the pizza's basic price. The extras are of course optional (by definition) , so if the user does not select any extras the item can still be added to the order.

Because each customer may want a selection of extras (or even all four options), the choices are determined using check boxes. This allows the user to select any of the four extras, regardless of whether or not other extras have already been selected.

Drinks can be added to the order at any time, and are dealt with separately from the pizza items (although note that until at least one pizza item has been added to the order, no drinks may be selected). Drinks are selected using the NumericUpDown control.

The controls for each type of selection are grouped on their own panel, allowing the selection for drinks (for example) to be enabled or disabled independently of the other controls. It is also important for the radio button controls, since it creates a control group in which only one radio button may be checked at any one time; selecting a different radio button will de-select any previously selected radio button automatically.

The other point of interest concerning the controls is that each group of controls has been set up as a control array with similar characteristics to the control arrays found in Visual Basic 6, allowing them to be accessed and manipulated using program loops. The declarations and initialisation statements for the control arrays can be seen at the top of the form's class definition.

Another interesting feature of the code is the use of a structure to group together the variables that store the pizza selection for each pizza item. The choice of topping and base are both stored as integers, while the extras (which are either selected or not selected) are stored as Boolean variables.

The order details displayed to the user are updated in real time as pizza items or drinks are added to the order, including the order value, delivery charge (if applicable) and order total. One fairly obvious shortcoming with the programming as it stands is that, once added to the order, a pizza item cannot be deleted, which means that if the customer changes their mind half way through an order the user must clear the order and start again. Thanks to the fact that each pizza item is stored in a structure, this shortcoming could be remedied relatively easily (I leave this to those of you with the enthusiasm to develop the program further!). The selection of drinks can be changed dynamically, without requiring the user to start again from scratch.

The only feature of the program that introduces anything radically new to these pages is the ability to print a delivery note (which is after all very important for a pizza delivery program!) The code I have used here is perhaps not the most elegant solution, but it appears to work in the (admittedly limited) tests that I have carried out.

The program has deliberately been limited to 15 pizza items in order to reduce the complexity of the print procedure, which allows for up to seven pizza items (plus drinks) to be printed on a single A4 delivery note. More items (up to fifteen in total not including drinks) can be ordered, and the additional items will be printed on a continuation sheet.

The subject of printing with Visual Basic seems to be the cause of some consternation for some student programmers. Hopefully the code provided here, while it may not be the most efficient solution, will at least provide a starting point for those with similar programming problems to solve.

On a final note, the colour scheme chosen by me is purely arbitrary and will probably give those of you that have studied graphic design nightmares. All I can say is that it seemed like a good idea at the time, and I don't really have much incentive at the present time to go back and redesign the interface. My primary interest, after all, is in the code and making it work. I am under no illusions about my prowess (or lack thereof) as a graphic designer, and gladly defer to those better qualified in this respect.