Now that you have defined the Item object and have the helper functions in place, you are ready to use your linked list. Listing 34.12 shows the linked list in action after a couple of operations have been performed on it. You should experiment with this sample to discover advantages and disadvantages of this linked list compared to arrays and Visual Basic collections.
Listing 34.12 shows one way to populate and destroy the linked list. Although this example is rather simple, it does highlight some of the challenges of using linked lists. The list initially begins with a head element and three additional objects. After you build the initial list, the mclsCurItem pointer points to the last item added to the list.
Listing 34.12 - LISTDEMO.FRM - Building and Destroying the List
'********************************************************************* ' ListDemo - Demonstrates one way to build and use a linked list '********************************************************************* Option Explicit '********************************************************************* ' Form-level pointers to the head and current item in the linked list '********************************************************************* Private mclsHead As New clsItem Private mclsCurItem As clsItem '********************************************************************* ' Builds the initial list, sets the head, and does some prep work '********************************************************************* Private Sub Form_Load() Dim i As Integer '***************************************************************** ' Optional - label the head (helpful during debugging) '***************************************************************** mclsHead.strData = "Head" '***************************************************************** ' Set the current item to the head '***************************************************************** Set mclsCurItem = mclsHead '***************************************************************** ' Create three items to give the user something to play with '***************************************************************** For i = 1 To 3 Set mclsCurItem = _ InsertAfter(mclsCurItem, "Item " & CStr(i), i) Next i ... ' Code has been intentionally omitted from this listing End Sub '********************************************************************* ' Although VB is supposed to do cleanup, I feel better freeing the ' list myself. This is not a required element of this program. '********************************************************************* Private Sub Form_Unload(Cancel As Integer) '***************************************************************** ' Let's be good citizens and free the list ourselves '***************************************************************** Dim clsCurItem As clsItem Set clsCurItem = mclsHead.clsItemNext '***************************************************************** ' Remove all of the items in the list (printing the count in the ' Immediate window) '***************************************************************** Do While Not (clsCurItem.clsItemNext Is Nothing) Set clsCurItem = RemoveItem(clsCurItem) Debug.Print basListHelpers.Count Loop End Sub
The Form_Unload() event demonstrates the concept of traversing the list to destroy all its elements. You specifically unload this list because you cannot rely on Visual Basic doing the proper cleanup of these objects itself.
After you create the initial list and load the form, the user is in control of the linked list. The user can add or remove any items by using the cmdInsertBefore and cmdRemoveItem command buttons. Listing 34.13 describes each of these controls' click events in detail.
Listing 34.13 - LISTDEMO.FRM - Adding and Removing Items
'********************************************************************* ' Inserts an item in the list before the item specified by the user '********************************************************************* Private Sub cmdInsertBefore_Click() '***************************************************************** ' Get a pointer to the item that will be after the newly inserted ' item. '***************************************************************** Set mclsCurItem = GetIndex(mclsHead, , Val(InputBox( _ "Enter a integer index:", "InsertBefore", _ CStr(mclsCurItem.intData)))) '***************************************************************** ' Insert the item in the list (using some generated default data) '***************************************************************** Set mclsCurItem = InsertBefore(mclsCurItem, "Item " & _ CStr(basListHelpers.Count + 1), basListHelpers.Count + 1) '***************************************************************** ' If InsertBefore worked, then update the list box and labels '***************************************************************** If Not (mclsCurItem Is Nothing) Then UpdateFormItems End Sub '********************************************************************* ' Removes the currently selected item '********************************************************************* Private Sub cmdRemoveItem_Click() '***************************************************************** ' RemoveItem returns a pointer to another item in the list, so ' keep that value for further processing. '***************************************************************** Dim clsReturn As clsItem '***************************************************************** ' Don't let the user remove the head (optional) '***************************************************************** If mclsCurItem.strData = mclsHead.strData Then MsgBox "You can't remove the head. Please select another item." Exit Sub End If '***************************************************************** ' If there is more than one item in the list... '***************************************************************** If basListHelpers.Count > 1 Then '************************************************************* ' Remove the current item and catch the pointer to the item ' returned by RemoveItem. '************************************************************* Set clsReturn = RemoveItem(mclsCurItem) '************************************************************* ' If clsReturn doesn't have an item in front of it, then it ' is the tail. '************************************************************* If clsReturn.clsItemNext Is Nothing Then '********************************************************* ' If nothing is before the item returned, then clsReturn ' is the last item in the list (which is the head) '********************************************************* If clsReturn.clsItemPrev Is Nothing Then Set mclsCurItem = Nothing '********************************************************* ' Otherwise set the current item to the 2nd to last item '********************************************************* Else Set mclsCurItem = clsReturn.clsItemPrev End If '************************************************************* ' Otherwise, set the current item to whatever is in front of ' clsReturn (because clsReturn could be the head) '************************************************************* Else Set mclsCurItem = clsReturn.clsItemNext End If '************************************************************* ' Update the list box and labels to reflect this change '************************************************************* UpdateFormItems End If End Sub
Adding items is rather simple. You ask the user where to add the item and then let InsertBefore do the dirty work. Adding the new item updates the form-level pointer, mclsCurItem , to the current item in the list. If the item is added successfully, you update the display.
Removing items is a little more tedious because you have to test for special cases such as deleting the head or tail. After removing the item, you check to ensure that a valid pointer was returned. If the pointer is valid, you set the mclsCurItem variable to a valid object. Finally, you update the display to reflect the modified list's contents.