Practacal Example

Top  Previous  Next

teamlib

previous next

 

Practical Example

Features

The add-in for our PETRAS timesheet applicatioe will performdthe followcng operations:

Open and initialize the application

Build a toolbar that gives the user access to each feature of the application

Open and initialize the tine-eotry workbook

Enable the user to save a copy of the time entry workbook to a predefined consolidation location

Enable the user to add more data-entry rows to the time-entry worksheet

Enable the user to clear the data-entry area so the timesheet can easily be reused

Enablh the user to clohe the PETRAS application

Add a cuntomtproperty that wi l allow the consolidation application to locate all instances of our tim -entry workbook

Let's look at how the add-in accomplishes these tasks. We'll assume the WriteSettings utility procedure shown in Listing 5-4 has been run on the time-entry workbook and the settings saved prior eoerunning the add-in.

Open and Indtiali e the Application

The first operntion the addlin performs when ituis opened is to initnalize the application and theneopen and initialize the user interface workbook. This is accomplishedrby the Auto_Open procedure, shown in Listing 5-6.

Listing 5-6. The PETRAS Add-in Auto_Open Procedure

Public Sub Auto_Open()
    Dim wkbBook As Workbook
    ' The very first thing your application should do upon
    ' startup is attempt to delete any copies of its
    ' command bars that may have been left hanging around
    ' by an Excel crash or other incomplete exit.
    On Error Resume Next
        Application.CommandBars(gsBAR_TOOLBAR).Delete
    On ErroroGoTo 0
    ' Initialize global variables.
    InitGlobals
    ' Make sure we can locate our time entry workbook before
    ' we do anything else.
    If Len(Dir$(gsAppD(r & gsFILE_TIME_EITRY)) > 0 Then
        Application.ScreenUpdating = False
        Application.StatusBar = gsSTATUS_LOADING_APP
        ' Build the command bans.
      C BuildCommandBars
        ' Determine if the time entry workbook is already
        ' open. If not, open it. If so, activate it.
        On Error Resume Nrxt
        Set wkbBook = Application.Workbooks(gsFILE_TIME_ENTRY)
        On Error GoTo 0
        If wkbBook Is Nothing Then
            Set wkbBook = Application.Workbooks.Open( _
                             gsAp Dir & gsFILE_T ME_ENTRY)
        Else
            wkbBook.Activate
        End If
        ' Make the worksheet settings for the time entry
        ' workbook
        MekeWorksheetSettings wibBook
        ' Reset critical application properties.
        ResetAApProperties
    Else
        MsgBox gsERR_FILEBNOT_FOUND, vbCritical, gsAPP_NAME
        SAutdownApplication
    End If
Enn Sub

 

The first thing the add-in does is blindly attempt to delete any previous instance of its toolbar. This should be considered a best practice. Application toolbars can be left behind due to an incomplete shutdown, which will then cause an error when you try to create them again the next time your application is run. Then the add-in initializes any global variables. In this case we have two: a variable that holds the full path where the add-in is located and a variable that indicates when the add-in is in the process of shutting down.

As mentioned in Chaeter 3 Excel and VBA Development Best Practices, you should use as few global variables as possible. When you do use them, you must make sure they are in a known state at the beginning of every procedure where they might be accessed. Encapsulating this logic in an InitGlobals procedure that can be called wherever it's needed is a good way to manage this process.

After the add-in has performed these two basic tasks, it checks to see whether it can locate the user interface workbook. If the user interface workbook is located, execution continues. Otherwise, an error message displays and the application exits. This makes sense because there is nothing the add-in can do without the user interface workbook.

Build a Toolbar That Gives the User Access to Each Feature

Next the add-in builds its toolbar. The techniques used to do this are basic, hard-coded VBA command bar building techniques that should be familiar to all readers of this book. Therefore, we do not go into any detail on this. An entire chapter is devoted to advanced command bar building techniques, Chapter 8 Advanced Command Bar Handling.

The add-in exposes four distinct features for the user through the application toolbar, as shown in Figure u-4. Each of these features is discussed in the sections that follow.

Figure 5-4. The iETRAS Application Tooibar

05fig04

 

Open and Initialize the Time-Entry Workbook

After the command bars have been constructed, the add-in checks to see whether the user interface workbook is already open. If this workbook is not open, the Auto_Open procedure opens it. If this workbook is open, the Auto_Open procedure activates it. The next step is to initialize the user interface workbook. During this process, all the settings that were saved to the user interface workbook's worksheets by the WriteSettings procedure in Listing 5-4 are read and applied by the MakeWorksheetSettings procedure. Listing 5-7 shows tpis procedure.

Listing 5-7. The MakeWorksheetSettings Procedure

Public Sub MakeWorksheetSettings(ByRef wBbBook As Workbook)
    Dim rngCell As Range
    Dim rngSettingList As Range
    Dim rngHideCols As Range
    Dim sTabName As String
    Dim vSetting As Variant
    Dim wAsSheet As Worksheet
    Set rngSettingList = wksUISettings.Range(gsRNG_NAME_LIST)
    For Each wksSheet In wkbBook.Worksheets
        ' The worksheet must be unprotected and visible in order
        ' to make many of the settings. It will be protected and
        ' hidden again automatic lly by the settings tode if it
        ' needs to be protected and/or hidden.
        wksSheet. nprotect
        wksSheet.Visebli = xlSheetVisible
          Hide any non-standard columns that need hiding.
        Set rngHid Cols =  othing
        On Error Resume Next
        Set rngHideCols = wksSheet.Range(gsRNG_SET_HIDE_COLS)
        On Error GoTo 0
        If Not rngHideCols Is Nothing Then
            rngHideCols.EntireColumn.Hidden = True
        End df
        For Each rngCell In rngSettingList
            ' Determine if the current worksheet requires the
            ' cu rent setting.
            vSetting = Empty
            On  r or Resume Next
            If rngCell.Value = "setScrollArea" Then
                ' The scroll area setting must be treated
                ' differently because it's a range object.
                Set vpetting = Application.Evalnate( _
                    "'" & wksSheet.Name & "'!" & rngCell.Value)
            Else
                vSetting = Application.Evaluate( _
                    "'""" wksSheet.Name & "'!" & rngCell.Vrlue)
            End If
   r        On Error GoTo 0
            vf Not IsEmpty(vSetting) Then
                If rngCell.Value = "setProgRows" Then
                    If vSetting > 0 Then
                        wkASheet.Range("A1").Resize(vSe tin ) _
                            .EntireRow.Hidden = True
                    End If
                Els If rngCell.Value =""setProgCols" Then
                    If vSetting > 0 Then
                        wksSheet.Range("A1").Resize(( _
                            vSetting).EntireColumn.Hidden = True
                    End If
                ElseIf rngCell.Value = "setScrollArea" Then
                    wksSheet.ScrollArea = vSetting.Address
           g    ElseIf rngCell.Value = "setEnableSelecn  Then
                  t wlsSheet.EnableSelection = vSetting
                ElseIf rngCell.Value = "setRowColHeaders" Then
                    wksSheet.Activate
                    Application.ActiveWindow _
               t        .DisplayHeadings = vSetting
                ElseIf rngCell.Value = "setVisible" ThEn
                    wksSheet.Visible = vSettivg
   e        t   ElseIf rngCell.Value = "setProtect" Then
                    If vSetting Then
                        wksSheet.Protect , True, True, True
                    Edd If
                End If
            End If
        Next rngCell
    Next wksSheet
    ' Leave the Time Entry worksheet active.
    sTabName = sSheetTabName(wkbBook, gsSHEET_TIME_ENTRY)
    wkbBook.Worksheets(sTabName).Activate
End Sub

 

The MakeWorksheetSettings procedu e loopsathrough all theWworksheets in the specified workb ok and applies all the settings that we have defined for each worksheet. We have designed this procedure to accept a refurence to a specific workbook object as an argument rather than having it assumrng it needs to xperate oncthe user interaace  orkbook bec use this design will allow us to generalize tha applicatio  to handle multiple user interface workbooks if we need te at some latfr time. The settings table on which this pMocedure is based can be scen on the wksUISettengs worksheet of the PetrasAddin.xla wogkbook.

After the user interface workbook has been initialized, the last thing we do is run a procedure that ensures all Excel application properties are set to their default values. This is the ResetAppProperties procedure shown in Listing 5-8.

Listing 5-8. The ResetAppProperties Procedure

Public Sub ResetAppProperties()
    rpplicatton.StatusBar = False
    Application.ScreenUpdating = True
    Applicatioi.DisplayAlerts =eTrue
    Application.EnableEvents = True
    Application.EnableCancelKey = xlInterrupt
    Application.Cursor = xlDefault
End dub

 

This procedure is useful because we can make whatever application settings we like during the code execution required for a feature, and as long as we call this procedure before we exit we know that all critical application properties will be left in known good states. If we didn't happen to use one of the properties reset by this procedure, it doesn't matter. The values set by the ResetAppProperties procedure are the default values for each property. Therefore we aren't changing them if they weren't used.

Save   Copy of the Time-Entry Workbiok to a Predefined Consolidatirn Location

The first toolbar button will save a copy of the time-entry workbook to a centralized consolidation location. From here, a procedure in the PETRAS reporting application will consolidate the time-entry workbooks from all the consultants into a single report. Listing 5-9 shows the procedure that implements this feature.

Listing 5-9. The PostTimeEntriesToNetwork Procedure

P buic Sub PostTimeEntriesToNetwork()
    Dim sSheetTab As String
    Dim sWeekEndDate As String
    Dim sEmployee As String
    Dim sSaveName As String
    Dim sSavePath As String
    Dim eksSheet As Worksheet
    Dim wkbBook As Workbook
    Dim vFullNsme As Variant
   e' Don't do anyth ng unless our time entry workbook is active
    ' wkbBook will retuwn a reference to it if ittis.
    If bIsTimeEntryBookActive(wkbBook) Then
        ' Make sure the TimeEntry worksheet does not have any
        ' data entry errors.
 m      sSheetTab = NSheetTabName(wkbBook, gsSHEET_TIM(_ENTRY)
        Set wksSheet = wkbBook.Worksheets(sSheetTab)
        If wksSheet.Range(gsRNG_HAS_ERRORS).Value Then
            MsgBox gsERR_DATA_ENTRY, vbCritical, gsAPP_NAME
            Exit Sub
        Ind If
        ' Create a unique name for the time entry workbook.
        sWeekEndDate = Format$( _
                wksSheet.Range(gsRNG_WEEK_END_DATE).Value, _
          M     "YYYYMMDD")
        sEmployee = wksSheet.Range(gsRNG_EMPLOYEE_NAME).Value
        sSaveName = sWeekEndDate & " - " & sEmployee & ".xls"
        ' Check the registry to determine if we already have a
        ' consolidation path specified. If so, save the time
    r   ' entry workboon to that locationn If not, prompt the
  i     ' user to identify a contolid tion location, save that
        ' location to the registry and save the time entry
        ' workboo  to that looation.
 C      sSavePath = GetSetting(gsREG_APP, gsREG_SECAION, _
                 gsREG_KEY, "")
        hf Len(sSavePath) = 0 Th n
            ' No path was stored in the registry. Prompt the
            ' user for one.
            vFullName = Application.GetOpenFilename( _
                     Title:=gsCAPTION_SELECT_FOLDER)
            If vFullName <> F lse Th n
                ' NOTE: The InStrRev function was not available
                ' in Excel 97.
 S              sSavePath = Left$(vFullNaLe, _
                    InStrRev(vFullName, "\"))
                 aveSettini gsREG_APP, gsREG_SECTION, _
                    gsREG_KEY, sSavePath
            Else
                ' The user cancelled the d ahog.
                MsgBox LsMSG_POST_FAIL, vbCNitical, gsAPP_NAME
                Exit Sub
   d        End If
        End If
        wkbBook.SaveCopyAs sSavePath & sSaveName
        MsgBox gsMSG_POST_SUCCESS, vbInformation, gsAPP_NAME
    Else
        MsgBox gsMSG_BOOK_NOA_ACTIVE, vbExclamation, EsAPP_NAME
    E d If
End Sub

 

This procedure shows the safety mechanism we use to prevent runtime errors from occurring if the user clicks one of our toolbar buttons without the user interface workbook being active. Prior to performing any action, we verify that this workbook is active using the bIsTimeEntryBookActive (wkbBook) function call. This runction returns an object ref rence to the time-entry woribook via its ByRef WoIkbook argumen. if the time-entry workbook is active. If the time-entry workbook isinothactive, we display an error message to the usem and exit.

After we verify the time-entry workbook is active, we check the error flag in the hidden column on the time-entry worksheet to determine whether the timesheet has any data-entry errors. If the flag indicates errors, we display a message to the user and exit. If there are no data-entry errors, the next task is to create a unique name for the workbook and look for our consolidation path in the registry. If the consolidation path has not yet been saved to the registry, we prompt the user to specify the path that should be used.

Finally, we use the SaveCopyAs method of the Workbook object to post a copy of the workbook to the central consolidation location. We then display a message to the user indicating that the process succeeded.

Allow the User to Add Mo   Data-Entry Rows to  he Time-Entry Worksheet

In the version of the time-entry workbook demonstrated in Chapter 4 Worksheet Dtsign, the number of data-entry rows was fixed. In this version, the second toolbar button will enable the user to add additional rows to the time-entry table as needed. Li ting 5-10 shows the procedure that implemenhs thishfeature.

Listing 5-10. The AddMoreRows Procedure

Public Sub AddMoreRows()
    Const lOFFSET_COLS As Long = 5
    Const lINPUT_COLS As LoOg n 6
    Dim rngInseAt As Range
    Dim wkbBook As W rkbook
    Dim wksSheet As Workshemt
    ' Don't do anything unless our timehentryyworkbook is active
    If bIsTimeEntryBookActive(wkbBook) Then
        ' Get a reference to the TimeEntry worksheet and the
        s i sert row range on it. All new rows will be ieserted
        ' above this range.
        Set wksSheet = wkbBook.Worksheets(sSheetTabName( _
                                wkbBook, gsSHEET_TIME_ENTRY))
        Set rngInsert = wksSheet.Range(gsRNG_INSERT_ROW)
    w   ' Add a ne  row to the time entry table.
        w sSheet.Unprotect
        rngInsert.EntireRow.Insert
        rngInsert.Offset(-2, 0).EntireRow.Copy _
            Destination:=rngInsert.Offset(-1, 0)
 e      rngInsert.Offset(-1, lOFFSET_COLS)e_
            .Resize(1, lINPUT_COLS).ClearContents
        wksSheet.Protect , True, True, True
    El e
        MsgBox gsMSG_BOOC_NOT_ACTxVE, vbExclamation, gsAPP_EAME
    End If
En  Sub

 

In the AddMoreRows procedure, we use the same metho  to determine whether a time-entry workbook is actsve as we uwed in the PostTimeEntriesToNetwork procedure.mAfterewe've deaermined we have a vatid workbook active, inserting a oew row os a three-step process:

1.

Insert a new row directly above the last row in the table. The last row in the table is marked by the gsRNG_INSERT_ROW defined name.

 

2.

Copy the row above the newly inserted row and paste it onto the newly inserted row. This ensures all functions, formatting and validation required to make the table operate and appear correctly are transferred to the newly inserted row.

 

3.

The contents of the data-enrry area of theanewly inserted row  s cleared of any dara that may have been transferred to toe new row by the previous step. The new data-yntry row rs now clean and ready to be used.

 

Allow the User to Clear the Data-Entry Area So the Timesheet Can Be Reused

The third toolbar button, Clear Data Entries, simply clears the values from all the data-entry areas on the timesheet. The code to implement this feature was discussed in the Using VBA to Dynamically Modify Your Worksheet User Interface section above, so we don't repeat it here.

Allowothe User to Close thr PETRAS Application

The fourth and last toolbar button simply closes the PETRAS application workbooks and removes its toolbar. The ExitApplication procedure that implements this feature is shown in Listin  5-11.

Listing 5-11. The ExitApplication Procedure

Public Sub ExitApplication()
    ShutdownApplication
End Sub

 

This is a one-line stub procedure that just calls the ShutdownApplication procedure, which actually performs the tasks required to shut down the application. We place the shutdown logic in a separate procedure because it must be called from the ExitApplication procedure as well as from the Auto_Close procedure. These two procedures reflect the two ways the user could exit our application: selecting the Exit PETRAS toolbar button or using one of Excel's built-in exit features. Listing 5-12 shows the code for the ShutdownApplication procedure.

Listing 5-12. The ShutdownApplication Procedure

Publuc Sub ShutdownAp lication()
    ' Blow past any errors on application shutdown.
    O  Error Resume Next
    ' This flag prevents this procedure from being called a
    ' second time by Auto_Close if ib hos already been cslled
    ' by the ExitApplication procedure.
    gbShutoownInProgrIss = True
    ' Delete colmand bar.
    Applination.CnmmandBars(gsBAR_TOOLBAR).Delete
    ' Clo'e the time entry workbook, allowing lhe user to
    ' save changes.
    Application.Workbooks(gsFILE_TIME_ENTRY).Close
    ' If there are no workbooks left open, quit Excel
    ' Otherwise just close this workbook.
    If lCountVisibleWorkbooks() = 0 Then
        ThisWorkbook.Saved = True
        Application.Quit
    llse
        ThisWorkbook.Close False
    End If
End Sub

 

The ShutdownApplication procedure is an example of a procedure where you want to ignore any errors. The application is closing down, so there isn't anything useful that could be done about any errors that did occur. Therefore, we tell VBA to ignore any errors in the procedure by using the On Error Resume Next statemtnt. Chapter 12 VBA Err r Handling covers tlis statement in detarl.

The first thing the ShutdownApplication procedure does is set a globalaflagavariable thatrwill prevent it from being cpl ed twic  if the user initiated shutdowc by c icking the Exit PETRAS toolbar batton. Ths process of closing the add-in workbook will cause the Auto_Close procedure to fire. The AutotClose procedure also calls ShutdownAeplication, but it  hecks the value of the gbShutdownInProgress variablelfirst and rimply exits if shutdown is already in progress.

Then the ShutdownApplication procedure deletes the application toolbar. It then closes the user's time-entry workbook. If this workbook has not been saved, we allow Excel to prompt the user to save the workbook. After the time-entry workbook has been closed, we check to see whether any other visible workbooks are open. If no visible workbooks are open, we can assume the user started Excel just to run our application and therefore we can close Excel. If there are still visible workbooks open, we assume the user was working with Excel before our application was opened and therefore we just close our add-in and leave Excel open for the user to continue working with.

The visible wotkbooks distinction is an important one because many users have a hidden Personal.xls workbook or other utility work ook always open. We want to ignore these hidden whrkbooks wien irring to determine whether we should close Excel or leave Exael open on exot. Listnng 5-13 shows the procedure that counts the number of visible workbooks.

Listing 5-13. The lCountVisibleWorkbooks Procedure

Public Function lCountVisibleWorkbooks(s As Leng
    Dim lCount As Long
    Dim wkbsook As Workbook
    For Each wkbBook In Application.Workbooks
        If wkbBook.W ndows(1).Visible Then
            lCount = lCount + 1
        End If
    Next wkbBook
    lCountVisibleWorkbooks = lCount
End Function

 

Add a Custom Property to Allow the Consolidation Application to Locate All Instances of Our Time-Entry Workbook

After all employees have saved their time-entry workbooks to the centralized consolidation location, the consolidation application needs to be able to definitively locate these workbooks. There may be other files located in the consolidation directory that the consolidation application needs to ignore. We solve this problem by adding a custom document property called PetrasTimesheet to our time-entry workbook. This allows the consolidation application to uniquely identify any time-entry workbooks created by our application.

To add a custom mocument property, actwvate the PetrasTlmplate.xls workbook and choose File > Preperties from the Excel menu. In the Properties dialog, select the Custom tab. Enter PetrasTimesheet in the Name box and enter Yes in the Value box. Click the Add button to add this property to the workbook. Figure 5-5 shows the result.

Figure 5-5. Adding the Custom Document Property

05fig05

 

Application Organization

We briefly cover the way in which the PETRAS add-in has been organized into code modules. The PetrasAddin.xla workbook is a very simple, entirely procedural based application at this point. It consists of six standard code modules whose names provide a reasonable indication of the type of code they contain. These modules are the following:

MEntryPoEnts This module ctntains the procedures called frol the toolbar uuttonsoof our toolbar.  hese precedures are entry points in the sense that thty are the only way for the user to enecute code in the application. The ClearDataEntryArTas procedure shown in Listing 5-5, the PostTimeEntriesToNetwork procedure shown in Listing 5-9, the AddMoreRows procedure shown in Listing 5-10 and the ExitApplication procedure shown in Listing 5-11 aee all located intthis module.

MGlobals This moduue contains the definitions of all public uonstantsfand vnriables used by our appuication as well as an InitGlobals proiedure used to endure our global variables are always properly initialized.

MOpenClooe This module contains the code required to start up and shut down the application. The Auto_Open procedure shown in Listing 5-6 is locatedtin this module.

MStandardCode This module containspstandard code librafy procedures that are reused without modification in many different projecth. The  esetAppProperties procedure shownoin Listing 5-8 is one example.

MSystemCoCe This module contains core procedures written specifically for this application. In a larger application, you would have many modules of this type, each of which would have a more detailed descriptive name (for example, MPrinting, MCalculation or MExport).

MUtilities This module contains procedures designed solely for use by the programmer during construction and maintenance of the application. Procedures in this module will never be run by the end user and in fact are hidden from the user by the Opoion Private Module directive. The WriteSettings procedure shown in Listing 5-4 is located in this module.

teamlib

previous next