Étiquette : excel_vba

  • Accessing Objects Using With in Excel VBA

    The With statement in VBA allows you to execute a series of instructions on a single object efficiently. By establishing the reference to the object once, you can repeatedly apply multiple properties or methods to it without repeating the full object path. This is especially useful when dealing with long object names, making the code clearer and easier to read.

    The basic structure is:

    With Object
        [Statements]
    End With

    Here is an example:

    Sub WithStatementExample()
        With ThisWorkbook.Worksheets("Sheet1").Range("A1:A3")
            .Value = 12.8
            .NumberFormat = "0.000"
            .Font.Size = 24
            .Borders.Weight = xlThick
        End With
    End Sub

    Explanation:

    In this example, several properties of the range A1:A3 are changed within the With block. The value is set to 12.8, the number format is customized, the font size is enlarged, and the border thickness is set to a thick line.

    Within the With block, each property or method reference begins with a dot (.), which clearly indicates that it belongs to the object specified after With. This shorthand avoids the need to repeat the full object reference in each line, improving both readability and performance.

    Nested With Statements

    You can also nest With statements to work with sub-objects or collections. To illustrate, the example from Section 2.4.19, “Sorting a Range with Multiple Keys”, has been rewritten as follows:

    Sub NestedWithExample()
        ThisWorkbook.Worksheets("Sheet4").Activate
        With ActiveSheet.Sort
            With .SortFields
                .Clear
                .Add Range("A1:A5")
                .Add Range("B1:B5")
                .Add Range("C1:C5")
                .Add Range("D1:D5")
                .Add Range("E1:E5")
            End With
            .SetRange Range("A1:E6")
            .Apply
        End With
    End Sub

    Explanation:

    • The outer With works with the Sort object of the active worksheet. This includes accessing the SortFields collection and calling methods like .SetRange and .Apply.
    • The inner With operates on the SortFields collection itself, allowing you to call .Clear and .Add methods multiple times on this collection without repeating the full reference.

    This nesting makes the code more concise and logically structured when working with complex object hierarchies.

  • Referencing Objects with Excel VBA

    When accessing individual objects in VBA, it is best to do so as directly as possible—that is, without unnecessary intermediate steps. Unfortunately, many VBA applications follow a pattern like this:

    • A workbook is activated.
    • A worksheet is activated.
    • A range is selected.
    • Properties of the selected range are modified or methods are applied to it.

    While this approach of activating and selecting is easy to understand, it tends to be slower and more prone to errors.

    Here is an example illustrating this less efficient method:

    Sub ActivateAndSelect()
        ThisWorkbook.Activate
        Worksheets("Sheet1").Activate
        Range("A7:A9").Select
        Selection.Interior.Color = vbYellow
    End Sub

    By referencing objects directly instead, you create applications that run faster and are easier to maintain. Here is an improved version using direct referencing:

    Sub ReferenceDirectly()
        ThisWorkbook.Worksheets("Sheet1"). _
        Range("A10:A12").Interior.Color = vbYellow
    End Sub

    At first glance, this VBA code might seem more complex. However, it follows the object hierarchy logically: workbook, worksheet, cell range, property. Such statements can be longer, but they can be split across multiple lines for readability, as demonstrated above.

    This method reduces unnecessary activation and selection steps, which improves performance and reduces the chance of runtime errors caused by unexpected selections or activations.

  • Object Browser in Excel VBA

    In the Visual Basic Editor (VBE), you can open the Object Browser by pressing the F2 key. This tool provides a comprehensive list of all available classes, along with their properties, methods, and events.

    When you select a class—for example, WORKSHEETS as shown detailed list of that class’s properties, methods, and events appears on the right side of the window.

    Additionally, further assistance is available through the Help menu in the VBE. By choosing the menu item Microsoft Visual Basic for Applications Help, you access Microsoft’s online documentation, which includes the VBA reference for Excel.

    This reference is an invaluable resource for exploring VBA objects, understanding their members, and learning how to use them effectively in your projects.

  • Importing a Module with Excel VBA

    First, in the VBA Project Explorer, select the workbook into which you want to import the module.

    Then, from the File menu, choose the Import File option. This action will open the Import File dialog box. Alternatively, you can access this dialog by right-clicking on the target workbook within the Project Explorer and selecting Import File from the context menu.

    In the dialog, navigate to the folder containing the module you wish to import. Select the module file to import it into the chosen workbook.

    You can identify standard code modules by their .bas file extension, and UserForm modules by their .frm extension.

  • Exporting a Module with Excel VBA

    In the VBA Project Explorer, first select the module you wish to export. This can be any module type—either a standard code module or a UserForm module.

    Next, go to the File menu and choose the Export File option. This action will open the Export File dialog box. Alternatively, you can access this dialog by right-clicking on the module within the Project Explorer and selecting Export File from the context menu.

    In the dialog, select the desired destination folder where you want to save the exported file. For standard code modules, the file will be saved with the extension .bas. For UserForm modules, the exported file will have the extension .frm.

    When exporting a UserForm module, an additional file with the .frx extension is automatically saved in the same directory. This .frx file contains associated binary data such as images and control information necessary for the UserForm.

    If you wish to delete a module, use the Remove option in the same File menu. To prevent accidental deletion, VBA will prompt you to ask if you want to export the module first. If you agree, the Export File dialog box will open, allowing you to save a backup before the module is removed from the project.

  • Code in Another File with Excel VBA

    Below is an example illustrating how to work with procedures and functions located in a different Excel file (workbook). For this to work, the other workbook must be open in Excel.

    First, the following code is located in Module1 of the current workbook:

    Sub ModularOtherFile()
        ' Open the other workbook located in the same folder as the current workbook
        Workbooks.Open ThisWorkbook.Path & "\Mappe5Mod.xlsm"   
        ' Call a procedure in the other workbook, specifying module and parameters
        Application.Run "Mappe5Mod.xlsm!Modul1.Summe5", 3, 5   
        ' Call a function in the other workbook and display the returned result
        MsgBox "Summe 6: " & Application.Run("Mappe5Mod.xlsm!Modul1.Summe6", 3, 5)   
        ' Call a procedure in the class module of the other workbook
        Application.Run "Mappe5Mod.xlsm!Tabelle1.Summe7", 3, 5   
        ' Call a function in the class module of the other workbook and display the result
        MsgBox "Summe 8: " & Application.Run("Mappe5Mod.xlsm!Tabelle1.Summe8", 3, 5)  
        ' Close the other workbook after execution
        Workbooks("Mappe5Mod.xlsm").Close
    End Sub

    In the other workbook named Mappe5Mod.xlsm, within Module1, the following procedure and function are defined:

    Sub Summe5(a As Integer, b As Integer)
        MsgBox "Summe 5: " & (a + b)
    End Sub
    
    Function Summe6(a As Integer, b As Integer) As Integer
        Summe6 = a + b
    End Function

    Additionally, in the class module associated with the worksheet object Tabelle1 of Mappe5Mod.xlsm, the following procedure and function are defined:

    Sub Summe7(a As Integer, b As Integer)
        MsgBox "Summe 7: " & (a + b)
    End Sub
    
    Function Summe8(a As Integer, b As Integer) As Integer
        Summe8 = a + b
    End Function

    Explanation:

    Procedures and functions located in code modules of other workbooks can only be called if that workbook is open in Excel. Therefore, the example code first opens the workbook, executes the calls, and finally closes it.

    If the workbook is already open, this will not cause any issues, assuming the code in the other workbook has not been modified during execution.

    In this example, it is assumed that the other workbook is located in the same directory as the current one. To facilitate this, the path of the current workbook (ThisWorkbook.Path) is used to build the full file path.

    To invoke procedures or functions in another workbook, the Application.Run() method is used. It requires a string as its first argument, which must follow this format:

    « <WorkbookName>!<ModuleName>.<ProcedureOrFunctionName> »

    Additional parameters (if any) follow after the string.

    For example, calling a procedure looks like this:

    Application.Run « <WorkbookName>!<ModuleName>.<ProcedureName> », Parameter1, Parameter2, …

    Calling a function looks like this:

    Result = Application.Run(« <WorkbookName>!<ModuleName>.<FunctionName> », Parameter1, Parameter2, …)

    One important limitation to note: Functions defined inside class modules of another workbook, such as Summe8(), do not return values when called via Application.Run(). This is a restriction of the method and how VBA manages class module members across workbooks.

  • Code Within the Same File with Excel VBA

    First, let’s consider an example demonstrating how procedures and functions can be defined and used within the same VBA project file.

    The following code is located in the standard code module named Module1:

    Sub ModularSameFile()
        ' Calling procedure from another standard module
        Summe1 3, 5
        MsgBox "Sum 2: " & Summe2(3, 5)    
        ' Calling procedure and function from a class module associated with the worksheet object "Sheet1"
        Sheet1.Summe3 3, 5
        MsgBox "Sum 4: " & Sheet1.Summe4(3, 5)
    End Sub
    

    Next, in another standard code module named Module2, we have the following procedure and function:

    Sub Summe1(a As Integer, b As Integer)
        MsgBox "Summe 1: " & (a + b)
    End Sub
    
    Function Summe2(a As Integer, b As Integer) As Integer
        Summe2 = a + b
    End Function

    Finally, within the class module associated with the worksheet object named Tabelle1, the following procedure and function are defined:

    Sub Summe3(a As Integer, b As Integer)
        MsgBox "Summe 3: " & (a + b)
    End Sub
    
    Function Summe4(a As Integer, b As Integer) As Integer
        Summe4 = a + b
    End Function

    Explanation:

    By default, procedures and functions defined in standard code modules have Public visibility, unless explicitly declared as Private Sub or Private Function. This means that the procedure Summe1() and the function Summe2() defined in Module2 can be directly called from anywhere within the VBA project, including from Module1 as shown in ModularGleicheDatei().

    In contrast, procedures and functions within class modules (such as the one tied to the worksheet object Sheet1) have Private visibility by default. Consequently, the procedure Summe3() and the function Summe4() defined in the class module cannot be called directly by their name alone. Instead, you must prefix the call with the class module’s object name—in this case, Sheet1.—to access them. For example, you call Sheet1.Summe3 and Sheet1.Summe4 to invoke these members.

    This distinction is important because it controls the scope and accessibility of code elements, ensuring encapsulation when working with object-oriented structures like class modules, while allowing more open access in standard modules.

  • User-Defined Data Type (UDT) with Excel VBA

    A user-defined data type lets you combine related data of different types into a single structure, clarifying their thematic connection. It’s similar to a struct in other programming languages.

    Key Features

    • Components of a UDT can themselves be arrays.
    • You can create variables and arrays of your new type.
    • Variables of the UDT can be passed as parameters to procedures or functions.
    • UDTs are declared at the module level (outside procedures), typically at the top, right under Option Explicit.

    Example

    Option Explicit
    Type Person
        Name As String
        PNummer As Integer
        Telefon() As String        ' Dynamic array of phone numbers
        Telefax(1 To 2) As String ' Fixed array with 2 elements
        Gehalt As Single
    End Type
    
    Sub Benutzerdefiniert()
        ' Declare a single variable and an array of the user-defined type
        Dim S As Person
        Dim T(1 To 5) As Person   
        ' Assign values to the components of the variable S
        S.Name = "Maier"
        S.PNummer = 17
        S.Telefax(1) = "0965-347767"
        S.Telefax(2) = "0975-227134"
        S.Gehalt = 2652.5  
        ' Dimension the dynamic array before assigning values
        ReDim S.Telefon(1 To 3)
        S.Telefon(1) = "0965-347766"
        S.Telefon(2) = "0189-938439"
        S.Telefon(3) = "0975-227133"   
        ' Assign the variable S to the 5th element of the array T
        T(5) = S  
        ' Output elements of the user-defined variable
        MsgBox T(5).Name & ": " & T(5).Telefon(3) & " und " & T(5).Telefax(2) 
        ' Pass the variable to a procedure
        BDTypAusgabe T(5)
        ' Note: Outputting the entire UDT directly is not possible
        ' MsgBox T(1).Name would show empty because T(1) was not assigned
    End Sub
    
    Sub BDTypAusgabe(x As Person)
        MsgBox x.Name & ": " & x.Telefon(3) & " und " & x.Telefax(2)
    End Sub

    Explanation

    • The UDT Person has five components:
      • Name: String
      • PNummer: Integer
      • Telefon(): Dynamic array of Strings
      • Telefax(1 To 2): Fixed-size array of two Strings
      • Gehalt: Single (decimal number)
    • Before assigning values to the dynamic array component (Telefon), it must be dimensioned with ReDim.
    • Assigning one variable of type Person to another copies all components, including arrays.
    • You cannot output a variable of the entire user-defined type directly (e.g., MsgBox T(5)); instead, you output individual components explicitly.
    • User-defined types declared without Private are project-wide, meaning all modules can see them. Use Private Type to restrict visibility to the declaring module.

    Summary

    User-defined data types allow you to group related, different kinds of data into meaningful units for clearer and better-structured code. This is especially useful when working with complex data sets or when passing related information as a single variable.

  • Recursive Procedures and Functions with Excel VBA

    Functions or procedures can call other functions or procedures at any time. This is known as nested calls. After finishing their execution, control returns back to the calling procedure or function, no matter how deep the nesting goes.

    When a function or procedure calls itself, this is called recursion. Recursive calls must always include a condition to terminate the recursion; otherwise, it will result in an infinite chain of self-calls causing the program to hang or crash.

    Recursion is an elegant way to solve certain problems programmatically.

    Example of Basic Recursion

    Sub RecursiveStart()
        Dim Output As String
        Dim Nr As Integer
        Nr = 1
        MsgBox Nr
        RecursiveRun Nr
        MsgBox "End"
    End Sub
    
    Sub RecursiveRun(Nr As Integer)
        Nr = Nr + 1
        MsgBox Nr
        If Nr < 5 Then RecursiveRun Nr
    End Sub

    Explanation:

    • In the procedure RecursiveStart(), the variable Nr is initialized with the value 1 and displayed.
    • Then, RecursiveRun() is called with the current value of Nr.
    • Inside RecursiveRun(), the value of Nr is incremented by 1 and displayed again.
    • The procedure then calls itself recursively as long as Nr is less than 5.
    • This recursive self-call happens a total of 4 times, incrementing Nr from 2 up to 5.
    • When Nr reaches 5, the recursive calls stop, and the procedure begins to exit.
    • Control returns back step-by-step through all previous recursive calls until returning to RecursiveStart().
    • Finally, RecursiveStart() displays the message « End ».

    Without the terminating condition If Nr < 5 Then …, the procedure would call itself indefinitely, causing an infinite loop.

  • Passing Arrays as Parameters with Excel VBA

    Arrays can also be passed as parameters to procedures or functions. When declaring such parameters, neither the number of elements nor the dimensions need to be specified. This makes the procedure or function more flexible, as it can handle arrays of different sizes and dimensions.

    Example:

    Sub PassArray()
        Dim x(1 To 5, 1 To 3) As Integer
        FillArray x()
        OutputArray x()
    End Sub
    
    Sub FillArray(z() As Integer)
        Dim i As Integer, k As Integer
        For i = LBound(z, 1) To UBound(z, 1)
            For k = LBound(z, 2) To UBound(z, 2)
                z(i, k) = i * k
            Next k
        Next i
    End Sub
    
    Sub OutputArray(z() As Integer)
        Dim i As Integer, k As Integer
        ThisWorkbook.Worksheets("Sheet1").Activate
        For i = LBound(z, 1) To UBound(z, 1)
            For k = LBound(z, 2) To UBound(z, 2)
                Cells(i, k).Value = z(i, k)
            Next k
        Next i
    End Sub

    Explanation:

    • In the procedure PassArray(), a two-dimensional array with 5 rows and 3 columns is declared.
    • The empty array is passed to the procedure FillArray(), where it is filled with values.
    • Because arrays are passed by reference by default, the changes made inside FillArray() persist outside the procedure.
    • The filled array is then passed to the procedure OutputArray(), where its contents are output into an Excel worksheet.
    • Both procedures use the functions LBound() and UBound() to determine the lower and upper bounds of each dimension of the array.
    • This ensures that all elements of the array, regardless of size, are processed correctly.