Vba for excel classes

The VBA Class allows you to define your own objects with unique properties and methods in VBA. Classes in at the core of all Object Oriented Programming languages. Although we can argue how much is VBA actually an Object Oriented Programming language, there is no doubt that VBA allows you to create Classes similarly as in Java or C#. But what is a Class? A Class allows you to encapsulate any level of abstraction and complexity into a single object and facilitate only an interface (certain procedures or methods if you prefer) to this object.

Head First Object Oriented Analysis and Design

Best book to learn OOP concepts (link to Amazon)

Personally I am a fan of (VBA) Classes as they require abstract thinking and a modular approach to writing code (in this case VBA). If you have seen a lot of VBA code, not once were you probably horrified to see a junkyard of random Subs and Functions with no obvious relationship between them. Classes whereas “require” that you encapsulate a certain “amount of functionality” into a single object which maps similarly to the world around us which is represented by single objects which can help us yield certain results. In my opinion this is an easy concept to grasp as everyday we are dealing with individual tools and objects that allow us to achieve certain goals. Sometime we are not necessary sure how these objects work (a PC) but we know how to use their interface to achieve an objective (send an email). Let’s use a simple analogy as we move forward through this tutorial…

VBA Class example

Before I explain more let us see a very simple Class example. To create a class insert a “Class” module to the “Class Modules” folder:
vba class example
Next I inserted some example code to my class below and renamed my class (in the Properties panel) to MyClass.

Public name As String

Public Sub Hello()
    Debug.Print "Hello my name is " & name
End Sub

If you want to use your class you can create a simple VBA Sub in any module:

Sub Main()
  Dim class as New MyClass
  class.name = "John"
  class.Hello
End Sub

Output:

Hello my name is John

The Car – Class Analogy

One of my personal favorite analogies of a Class is the Car Class. Let us say we want to create a Class for a Car object. Now an object of this class (a Car) will have certain properties like the brand of the Car, the color, the license plate numbers, as well as will have certain behaviors (called methods in Computer Programming) like driving forward, turning left, breaking etc. See below a simple example of how this translates to a VBA Class.

car class

This approach makes it easier for someone who does not understand/know the underlying implementation to easily start using the Car Class object, as the Car object encapsulates everything that has to do with a single Car object the user can seamlessly reuse this object.

Creating a new VBA Class

Let’s start our journey by creating a new empty VBA Class. To add a new VBA Class go to the menu and select Insert then select Class Module.

Alternatively, right-click on any item in your VBA Project and select Class Module like shown below:
vba class

Classes in VBA are similar to regular VBA modules. They have their own namespace and can consist of procedures, functions, variables etc. There are other things you will find in a VBA Class, but we will get to that.

Next let’s make sure to name our Class appropriately:

vba class name

Make sure that the Class name is not identical to a module or procedure within your VBA project or this will make it complicated to use this Class.

Now you have a new empty Class. It doesn’t do much except exist. But before we put some life into it let’s test that indeed it works. I have created a simple VBA Class which I named CarClass. The example below will create the new class.

Sub TestCarClass()
Hello 

Notice that when defining the Car variable I used the Set clause. This is because each Class is an object and the Car variable contains only a reference to this object. If you are not familiar with handling VBA Objects read here. Now let’s animate our class by adding some procedures (behaviors/methods) and some properties.

Variables, Procedures and Functions

A VBA Class can contain variables, procedures and functions just like regular VBA modules.

Let’s extend our VBA Class CarClass with some additional procedures and variables common to our abstract model of a car.

Public Speed As Integer
Public LicensePlate as String

Sub DriveForward()
    Speed = IIf(Speed < 0, -Speed, Speed)
End Sub

Sub DriveBack()
    Speed = IIf(Speed < 0, Speed, -Speed)
End Sub

We can now create a new object of Class CarClass and start working with it:

Sub TestCarClass()
    Dim Car As CarClass
    Set Car = New CarClass
    Car.LicensePlate = "34344W"
    Car.Speed = 100 'set speed to 100 mph
    
    Car.DriveBack 'set speed to -100 mph

    Car.DriveForward 'set speed to 100 mph
End Sub

Properties – Get, Let and Set

A Class should encapsulate abstraction and complexity. With our current CarClass we don’t have much control over the values users provide for the Speed and LicensePlate variables. What if the user sets the speed to some non-sense value like 1000mph? What if we want to validate the LicensePlate before setting it? Fortunately, the VBA Class introduces Get, Let and Set procedures that address that.

  • Get – return value of the property
  • Let – set the value of the property
  • Set – set the object value of the property (if applies)

The Get and Let procedures manage the process of retrieving and defining the value of a specific Class property. The Set procedure is basically a Setter aimed at properties which are objects not native VBA data structures. Let look at another simple example with our CarClass:

Let’s replace this:

Public Speed As Integer
Public LicensePlate as String

With this:

Dim vSpeed As Integer
Dim vLicensePlate As String

Public Property Get Speed() As Integer
    Speed = vSpeed
End Property

Public Property Let Speed(sp As Integer)
    vSpeed = Application.WorksheetFunction.Min(sp, 100)
    vSpeed = Application.WorksheetFunction.Max(vSpeed, -100)
End Property

Public Property Get LicensePlate() As String
    LicensePlate = vLicensePlate
End Property

Public Property Let LicensePlate(lp As String)
    If Len(lp) <> 6 Then Err.Raise (xlErrValue) 'Raise error
    vLicensePlate = lp
End Property

Notice the highlighted rows above where I introduced the new Get and Let property procedures. As you can see now I am getting and setting the Speed and LicensePlate value via the property procedures. This is more convenient than making a variable Public within the class, as it gives you more control on the value of the variable. Remember that a Class should encapsulate abstraction and complexity. A perfect Class object prevents the user from any restricted behaviors with this object.

Notice that you use properties similarly as you would use Public variables:

Dim car As CarClass
Set car = New CarClass
car.Speed = 10
Debug.Print car.Speed '10
    
car.Speed = 12345
Debug.Print car.Speed '100
    
car.LicensePlate = "123456"
Debug.Print car.LicensePlate '123456
    
car.LicensePlate = "1234567" 'Error!

Events – Initialize and Terminate

The Class module provides 2 default event procedures Class_Initialize() and Class_Terminate():

  • Private Sub Class_Initialize() – fired when the Class object is initialized e.g.
    Set car = New CarClass
  • Private Sub Class_Terminate() – fired when the Class object is destroyed e.g.
    Set car = Nothing

These 2 procedures are meant to facilitate the following objectives:

  • Initializing the Class object to prepare it for use i.e. initializing objects associated with the Class like Collections, setting default value of Class variables
  • Terminate the Class object and any objects associated with the Class i.e. free allocated memory

Let’s now extend our CarClass with a the following event procedures:

Dim SpeedRegister As Collection

Private Sub Class_Initialize()
    Set SpeedRegister = New Collection
    vSpeed = 0 'Set speed to 0
    vLicensePlate = "XXXXXX" 'Set unknown License Plate
End Sub

Private Sub Class_Terminate()
    Set SpeedRegister = Nothing
End Sub

We will use the SpeedRegister to record any changes in the speed of our Car. See full code of our CarClass :

Dim vSpeed As Integer
Dim vLicensePlate As String
Dim SpeedRegister As Collection

Public Property Get Speed() As Integer
    Speed = vSpeed
End Property

Public Property Let Speed(sp As Integer)
    vSpeed = Application.WorksheetFunction.Min(sp, 100)
    vSpeed = Application.WorksheetFunction.Max(vSpeed, -100)
    SpeedRegister.Add sp
End Property

Public Property Get LicensePlate() As String
    LicensePlate = vLicensePlate
End Property

Public Property Let LicensePlate(lp As String)
    If Len(lp) <> 6 Then Err.Raise (xlErrValue) 'Raise error
    vLicensePlate = lp
End Property

Sub DriveForward()
    Speed = IIf(Speed < 0, -Speed, Speed)
End Sub

Sub DriveBack()
    Speed = IIf(Speed < 0, Speed, -Speed)
End Sub

Private Sub Class_Initialize()
    Set SpeedRegister = New Collection
End Sub

Private Sub Class_Terminate()
    Set SpeedRegister = Nothing
End Sub

Instancing – Private vs. PublicNonCreatable

VBA In the properties section of the VBA Class you will find a property call Instancing. You are probably wondering what this property does. There are two available options – Private and PublicNonCreatable:
vba class instancing

  • Private – the Class cannot be created and referenced outside the VBA Project. It is “Private” to the VBA Project
  • PublicNonCreatable – the Class is Public and can be referenced out the VBA Project. It cannot be however created outside the project using the New clause

But why would you want to set your Class to PublicNonCreatable? Whenever you want to use it outside your VBA Project e.g. from a separate Excel, Access, MS Office VBA Project file currently open. This is especially useful if you have a Class you want to use within multiple VBA Projects and not having to copy the Class code to every project. You can consider creating a simple Excel AddIn and include the Class code in the VBA Project. If the AddIn is placed in your C:usernameAppDataRoamingMicrosoftAddIns directory it will open automatically with your MS Office applications.

But how are we supposed to use this Class if we can create this object? We need to create a dedicated function that will return the object. Let’s make an effort now to reuse our CarClass Class within a separate VBA Project:

Add a new Module and add a function

First we need to use an existing or create a new Module in which we will place our function which initializes the CarClass :

Public Function New_CarClass()
  Set New_CarClass = New CarClass
End Function

Notice that the Class needs to be Public so it can be referenced from the other VBA Project.

Set the Class to PublicNonCreatable

Click on the Class (CarClass) and change Instancing from Private to PublicNonCreatable.

Create the Class using the defined function

You are ready to reuse the CarClass in a different VBA Project:

Dim car as Object
Set car = New_CarClass
'Use the Class normally...

That’s it!

VBA Class Module vs. Standard Module

What is the difference between a standard Module and a Class Module? A Class instance is basically and Object and has all the properties of Objects in VBA. Here are some key differences worth highlighting:

  • There is only one copy of standard module data. A Class module, however, is created separately for each instance of the class. Hence each Class instance has it’s own set of Class variables individual to the object
  • Data in a standard module exists as long as your program scope – the life of you VBA Project. Only when you close your Excel/Access/Word/PowerPoint file will the data be lost for all global variables. In a Class module, however, data for each instance exists only for the lifetime of the object. It ceases to exist the moment the Class Object is destroyed e.g. when the Class object is set to Nothing
  • Variables declared Public in a standard module are visible anywhere in your project. However, Public variables in a Class module are only accessed if you have an object variable containing a reference to a particular instance of a class

Conclusions

Hopefully this tutorial has familiarized you with the VBA Class enough to start using it. As mentioned I think it is really worth making the effort to learn the VBA Class as using classes makes your code more readable and manageable. Classes encapsulate abstraction and complexity – it makes life easier when you or others need to reuse your code without necessarily needing to review the code and implementation.

If you feel you mastered Classes in Excel macros do check out my VBA Implements Tutorial as well!

Let me know what you think! Be sure to follow me on Twitter and Facebook for upcoming posts and tutorials!

“Classes struggle, some classes triumph, others are eliminated. Such is history” – Chairman Mao

A Quick Guide to the VBA Class Module

Item Explanation
Class Module Allows the user to create their own objects.
Method A public function or sub in the class module.
Member variable A variable declared in the class module.
Property Special function/subs that behave like variables when used
Property types Get, Set and Let.
Event — Initialize Sub that automatically runs when the class module object is created.
Event — Terminate Sub that automatically runs when the class module object is deleted.
Declaring and Creating
— Static
Dim o As New Class1
Declaring and Creating — Dynamic Dim o As Class1
Set o = New Class1
Calling a class module sub o.WriteValues Total
Calling a class module function Amount = o.Calculate()
Using a class module property o.Amount = 1
Total = o.Amount

The Webinar

Members of the Webinar Archives can access the webinar for this article by clicking on the image below.

(Note: Archive members have access to the webinar archive.)

vba class modules video

Introduction

VBA Class Modules allow the user to create their own objects. If you are not familiar with objects then I would highly recommend that you first check out my previous post VBA Objects – The Ultimate Guide.

In languages such as C# and Java, classes are used to create objects. Class Modules are the VBA equivalent of these classes. The major difference is that VBA Class Modules have a very limited type of Inheritance* compared to classes in the other languages. In VBA, Inheritance works in a similar way to Interfaces** in C#Java.

In VBA we have built-in objects such as the Collection, Workbook, Worksheet and so on. The purpose of VBA Class Modules is to allow us to custom build our own objects.

Let’s start this post by looking at why we use objects in the first place.

*Inheritance is using an existing class to build a new class.
**Interfaces are a form of Inheritance that forces a class to implement specifics procedures or properties.
 

Download the Source Code

Why Do We Use Objects

Using objects allows us to build our applications like we are using building blocks.

The idea is that the code of each object is self-contained. It is completely independent of any other code in our application.

This is similar to how things are built using Lego® bricks. There are many different types of Lego® components used. For example, a block, steering wheel, and laser are different items. They behave completely independently of each other. The wheel spins, the laser rotates etc. Yet we can connect them together to create a building, vehicle, space station and so on.

If you are still not clear about this then don’t worry. We’ll be breaking it all down into simple terms in the rest of this post.

Advantages of Using Objects

Treating parts of our code as blocks provide us with a lot of great advantages

  1. It allows us to build an application one block at a time.
  2. It is much easier to test individual parts of an application.
  3. Updating code won’t cause problems in other parts of the application.
  4. It is easy to add objects between applications.

VBA Class Modules

Not a good look for your code © BigStockPhoto.com

Disadvantages of Using Objects

With most things in life there are pros and cons. Using VBA class modules is no different. The following are the disadvantages of using class module to create objects

  1. It takes more time initially to build applications*.
  2. It is not always easy to clearly define what an object is.
  3. People new to classes and objects can find them difficult to understand at first.

*If you create an application using objects it will take longer to create it initially as you have to spend more time planning and designing it. However, in the long run it will save you a huge amount of time. Your code will be easier to manage, update and reuse.

Creating a Simple Class Module

If you would like to see working examples of this code you can download the source code from the top of this post.

Let’s look at a very simple example of creating a class module and using it in our code.

To create a class module we right-click in the Project window and then select Insert and Class Module

VBA Class Module

Adding a Class Module

Our new class is called Class1. We can change the name in the Properties window as the following screenshot shows:

VBA Application

Let’s change the name of the class module to clsCustomer. Then we will add a variable to the class module like this:

Public Name As String

 
creating a class module

 
We can now use this class module in any module(standard or class) in our workbook. For example

' Create the object from the class module 
Dim oCustomer As New clsCustomer

' Set the customer name
oCustomer.Name = "John"

' Print the name to the Immediate Window(Ctrl + G)
Debug.Print oCustomer.Name

Class Module versus Objects

People who are new to using classes and VBA class modules, often get confused between what is a class and what is an object.

Let’s look at a real world example. Think of a mass produced item like a coffee mug. A design of the mug is created first. Then, thousands of coffee mugs are created from this design.

This is similar to how class modules and objects work.

The class module can be thought of as the design.

The object can be thought of as the item that is created from the design.

The New keyword in VBA is what we use to create an object from a class module. For example:

' Creating objects using new
Dim oItem As New Class1
Dim oCustomer1 As New clsCustomer
Dim coll As New Collection

Note: We don’t use New with items such as Workbooks and Worksheets. See When New is not required for more information.

VBA Class Modules Versus VBA Normal Modules

Writing code in a class module is almost the same as writing code in a normal module. We can use the same code we use in normal modules. It’s how this code is used which is very different.

Let’s look at the two main differences between the class and the normal module. These often cause confusion among new users.

Difference 1 – How the modules are used

If you want to use a sub/function etc. from a class module you must create the object first.

For example, imagine we have two identical PrintCustomer subs. One is in a class module and one is in a normal module…

' CLASS MODULE CODE - clsCustomer
Public Sub PrintCustomer()
    Debug.Print "Sample Output"
End Sub
' NORMAL MODULE CODE 
Public Sub PrintCustomer()
    Debug.Print "Sample Output"
End Sub

You will notice the code for both is exactly the same.

To use the PrintCustomer sub from the class module, you must first create an object of that type

' Other Module
' https://excelmacromastery.com/
Sub UseCustomer()

    Dim oCust As New clsCustomer
    oCust.PrintCustomer

End Sub

To use PrintCustomer from the normal module you can call it directly

' Other Module
' https://excelmacromastery.com/
Sub UseCustomer()

    PrintCustomer

End Sub

Difference 2 – Number of copies

When you create a variable in a normal module there is only one copy of it. For a class module, there is one copy of the variable for each object you create.

For example, imagine we create a variable StudentName in both a class and normal module:

' NORMAL MODULE
Public StudentName As String
' CLASS MODULE called clsStudent
Public StudentName As String

For the normal module variable there will only be one copy of this variable in our application.

StudentName = "John"

For the class module, a new copy of the variable StudentName is created each time a new object is created.

Dim student1 As New clsStudent
Dim student2 As New clsStudent

student1.StudentName = "Bill"
student2.StudentName = "Ted"

When you fully understand VBA class modules, these differences will seem obvious.

The Parts of a Class Module

There are four different items in a class module. These are

  1. Methods – functions/subs.
  2. Member variables – variables.
  3. Properties– types of functions/subs that behave like variables.
  4. Events – subs that are triggered by an event.

You can see they are all either functions, subs or variables.

Let’s have a quick look at class that has examples of each of these:

' CLASS MODULE CODE from clsAccount
' https://excelmacromastery.com/vba-class-modules/

' Member variable
Private m_balance As Double

' Properties
Property Get Balance() As Double
    Balance = m_balance
End Property

Property Let Balance(value As Double)
    m_balance = value
End Property

' Event - triggered when class created
Private Sub Class_Initialize()
    m_balance = 100
End Sub

' Methods
Public Sub Withdraw(amount As Double)
    m_balance = m_balance - amount
End Sub

Public Sub Deposit(amount As Double)
    m_balance = m_balance + amount
End Sub

The following code demonstrates how this class could be used:

' This sub uses the clsAccount class
' The results are printed to the Immediate Window(Ctrl + G)
' https://excelmacromastery.com/vba-class-modules/
Sub Demo_clsAccount()

    Dim oAccount As New clsAccount
    
    ' Print the balance
    Debug.Print "Starting balance is: " & oAccount.Balance

    ' Deposit money
    oAccount.Deposit 25

    ' Print the balance
    Debug.Print "Balance after deposit is: " & oAccount.Balance
    
    ' Withdraw Money
    oAccount.Withdraw 100

    ' Print the balance
    Debug.Print "Balance after withdrawl is: " & oAccount.Balance
    
End Sub

If we run the code we will get the following:
Starting balance is: 100
Balance after deposit is: 125
Balance after withdrawl is: 25

Now that we have seen examples, let’s take a look at each of these in turn.

Class Module Methods

Methods refer to the procedures of the class. In VBA procedures are subs and functions. Like member variables they can be Public or Private.

Let’s look at an example:

' CLASS MODULE CODE for clsExample
' https://excelmacromastery.com/vba-class-modules/

' Public procedures can be called from outside the object
Public Sub PrintText(text As String)
    Debug.Print text
End Sub

Public Function Calculate(amount As Double) As Double
    Calculate = amount - GetDeduction
End Function

' private procedures can only be called from within the Class Module
Private Function GetDeduction() As Double
    GetDeduction = 2.78
End Function

We can use the clsExample class module like this:

' Sub used to demonstrate Class clsExample
' https://excelmacromastery.com/vba-class-modules/
Public Sub ClassMembers()
    
    Dim oSimple As New clsExample
    
    oSimple.PrintText "Hello"
     
    Dim total As Double
    total = oSimple.Calculate(22.44)
     
    Debug.Print total

End Sub

Class Module Member Variables

The member variable is very similar to the normal variable we use in VBA. The difference is we use Public or Private instead of Dim.

' CLASS MODULE CODE

Private Balance As Double
Public AccountID As String

Note: Dim and Private do exactly the same thing but the convention is to use Dim in sub/functions and to use Private outside sub/functions.

The Public keyword means the variable can be accessed from outside the class module. For example:

' This code will give an ERROR!!
Sub Demo_BankAccount()

    Dim oAccount As New clsBankAccount
    
    ' Valid - AccountID is public
    oAccount.AccountID = "499789"
    
    ' ERROR - Balance is private
    oAccount.Balance = 678.9
    
End Sub

In the above example, we cannot access Balance because it is declared as Private. We can only use a Private variable within the class module. We can use in a function/sub in the class module e.g.

' CLASS MODULE CODE
' https://excelmacromastery.com/
Private Balance As Double

Public Sub SetBalance()
    Balance = 100
    Debug.Print Balance
End Sub

It is considered poor practice to have public member variables. This is because you are allowing code outside the object to interfere with how the class works. The purpose of the using classes is so that we hide what is happening from the caller.

To avoid the user directly talking to our member variables we use Properties.

Class Module Properties

  1. Get – returns an object or value from the class
  2. Let – sets a value in the class
  3. Set – sets an object in the class

Format of VBA Property

The normal format for the properties are as follows:

Public Property Get () As Type
End Property

Public Property Let (varname As Type )
End Property

Public Property Set (varname As Type )
End Property

We have seen already that the Property is simply a type of sub. The purpose of the Property is to allow the caller to get and set values.

Why we use Properties

Why can’t we just make the variables Public and use them directly?

Let’s explain with some examples. Imagine we have a class that maintains a list of Countries. We could store the list as an array

' Use array to store countries
' https://excelmacromastery.com/
Public arrCountries As Variant

' Set size of array when class is initialized
' https://excelmacromastery.com/
Private Sub Class_Initialize()
    ReDim arrCountries(1 To 1000)
End Sub

When the user wants to get the number of countries in the list they could do this:

' NORMAL MODULE CODE
Dim oCountry As New clsCountry

' Get the number of items
NumCountries = UBound(oCountry.arrCountries) - LBound(oCountry.arrCountries) + 1

There are two major problems with the above code:

  1. To get the number of countries you need to know how the list is stored e.g. Array.
  2. If we change the Array to a Collection, we need to change all code that reference the array directly.

To solve these problems we can create a function to return the number of countries

' CLASS MODULE CODE - clsCountryList
' Array
Private arrCountries() As String

Public Function Count() As Long
    Count = UBound(arrCountries) + 1
End Function

We then use it like this:

' MODULE CODE
Dim oCountries As New clsCountries

Debug.Print "Number of countries is " & oCountries.Count

This code solves the two problems we listed above. We can change our Array to a Collection and the caller code will still work e.g.

' CLASS MODULE CODE
' Collection
' https://excelmacromastery.com/
Private collCountries() As Collection

Public Function Count() As Long
    Count = collCountries.Count
End Function

The caller is oblivious to how the countries are stored. All the caller needs to know is that the Count function will return the number of countries.

As we have just seen, a sub or function provides a solution to the above problems. However, using a Property can provide a more elegant solution.

Using a Property instead of a Function/Sub

Instead of the creating a Count Function we can create a Count Property. As you can see below they are very similar:

' Replace this
Public Function Count() As Long
    Count = UBound(m_countries) - LBound(m_countries) + 1
End Function

' With this
Property Get Count() As Long
    Count = UBound(m_countries) - LBound(m_countries) + 1
End Property

In this scenario, there is not a lot of difference between using the Property and using a function. However, there are differences. We normally create a Get and Let property like this:

' https://excelmacromastery.com/vba-class-modules/

Private m_totalCost As Double

Property Get totalCost() As Long
     totalCost = m_totalCost
End Property

Property Let totalCost(value As Long)
     m_totalCost = value
End Property

Using Let allows us to treat the property like a variable. So we can do this

oAccount.TotalCost = 6

The second difference is that using Let and Get allows us to use the same name when referencing the Get or Let property. So we can use the property like a variable. This is the purpose of using Properties over a sub and function.

oAccount.TotalCost = 6
value = oAccount.TotalCost 

If we used a function and a sub then we cannot get the behaviour of a variable. Instead we have to call two different procedures e.g.

oAccount.SetTotalCost 6
value = oAccount.GetTotalCost

You can also see that when we used Let we can assign the value like a variable. When we use SetTotalCost , we had to pass it as a parameter.

The Property in a Nutshell

  1. The Property hides the details of the implementation from the caller.
  2. The Property allows us to provide the same behaviour as a variable.

Types of VBA Property

There are three types of Properties. We have seen Get and Let already. The one we haven’t looked at is Set.

Set is similar to Let but it is used for an object(see Assigning VBA Objects for more detail about this).

Originally in Visual Basic, the Let keyword was used to assign a variable. In fact, we can still use it if we like.

' These line are equivalent
Let a = 7
a = 7

So we use Let to assign a value to a variable and we use Set to assign an object to an object variable.

' Using Let
Dim a As Long
Let a = 7

' Using Set
Dim coll1 As Collection, coll2 As Collection
Set coll1 = New Collection
Set coll2 = coll1
  • Let is used to assign a value to a basic variable type.
  • Set is used to assign an object to an object variable.

In the following example, we use Get and Let properties for a string variable:

' CLASS MODULE CODE for clsPerson
' https://excelmacromastery.com/vba-class-modules/

' SET/LET PROPERTIES for a variable
Private m_name As String

' Get/Let Properties
Property Get name() As String
    name = m_name
End Property

Property Let name(name As String)
    m_name = name
End Property

We can then use the name properties like this:

' Testing Let and Set for the clsPerson Class
' https://excelmacromastery.com/vba-class-modules/
Sub TestLetSet()

    Dim name As String
    Dim oPerson As New clsPerson
    
    ' Let Property
    oPerson.name = "Bill"
    
    ' Get Property
    name = oPerson.name

End Sub

In the next example, we use Get and Set properties for an object variable:

' CLASS MODULE CODE for clsCurrency
' https://excelmacromastery.com/vba-class-modules/

Private m_Prices As Collection

' Get/Set Properties
Property Get Prices() As Collection
    Set Prices = m_Prices
End Property

Property Set Prices(newPrices As Collection)
    Set m_Prices = newPrices
End Property

We can then use the properties like this:

' The code below demonstrates how to use the LetSet properties with a class.
'
' 1. The sub creates a collection and adds value.
' 2. We then add it to the clsCurrency class object using the Set Property.
' 3. We then read it from the class object usiing the Get property.
'
' https://excelmacromastery.com/vba-class-modules/
Sub TestLetSet()
    
    ' Create a collection and add prices
    Dim Prices As New Collection
    Prices.Add 21.23
    Prices.Add 22.12
    Prices.Add 20.12
        
    Dim oCurrency As New clsCurrency
    
    ' Uses the Set property of clsCurrency to
    ' add the collection to the class
    Set oCurrency.Prices = Prices

    Dim PricesCopy As Collection
    ' Uses the Get property of clsCurrency
    ' to read the collection from the class
    Set PricesCopy = oCurrency.Prices
    
    ' Print the results to the Immediate Window(Ctrl + G)
    PrintCollection Prices, "Prices"
    PrintCollection PricesCopy, "Copy"
    
End Sub

' Print the contents of a Collection to the Immediate Window(Ctrl + G)
Sub PrintCollection(c As Collection, name As String)

    Debug.Print vbNewLine & "Printing " & name & ":"

    Dim item As Variant
    For Each item In c
        Debug.Print item
    Next item

End Sub

We use the Get property to return the values for both items. Notice that even though we use the Get Property to return the Collection, we still need to use the Set keyword to assign it.

One very important thing to understand is that when we use Set we are still referencing the same collection. Set is not creating a copy of the collection. You can read more about this here

Class Module Events

If you to see working examples of this code you can download the source code from the top of this post.

A class module has two events

  1. Initialize – occurs when a new object of the class is created.
  2. Terminate – occurrs when the class object is deleted.

In Object-Oriented languages like C++, these events are referred to as the Constructor and the Destructor. In most languages, you can pass parameters to a constructor but in VBA you cannot. We can use a Class Factory to get around this issue as we will see below.

Initialize

Let’s create a very simple class module called clsSimple with Initialize and Terminate events:

' CLASS MODULE CODE
' https://excelmacromastery.com/
Private Sub Class_Initialize()
    MsgBox "Class is being initialized"
End Sub

Private Sub Class_Terminate()
    MsgBox "Class is being terminated"
End Sub

Public Sub PrintHello()
    Debug.Print "Hello"
End Sub

In the following example, we use Dim and New to create the object.

In this case, oSimple is not created until we reference it for the first time e.g.

' https://excelmacromastery.com/
Sub ClassEventsInit2()

    Dim oSimple As New clsSimple
    
    ' Initialize occurs here
    oSimple.PrintHello

End Sub

When we use Set and New together the behaviour is different. In this case the object is created when Set is used e.g.

' https://excelmacromastery.com/
Sub ClassEventsInit()

    Dim oSimple As clsSimple
    
    ' Initialize occurs here
    Set oSimple = New clsSimple
    
    oSimple.PrintHello
   
End Sub

Note: For more information about the different between using New with Dim and using New with Set see Subtle Differences of Dim Versus Set

As I said earlier, you cannot pass a parameter to Initialize. If you need to do this you need a function to create the object first

' CLASS MODULE - clsSimple
' https://excelmacromastery.com/
Public Sub Init(Price As Double) 

End Sub 

' NORMAL MODULE
Public Sub Test()

    ' Use CreateSimpleObject function
    Dim oSimple As clsSimple
    Set oSimple = CreateSimpleObject(199.99)

End Sub

Public Function CreateSimpleObject(Price As Double) As clsSimple

    Dim oSimple As New clsSimple
    oSimple.Init Price

    Set CreateSimpleObject = oSimple

End Function 

We will expand on this CreateSimpleObject in Example 2 to create a Class Factory.

Terminate

The Terminate event occurs when the class is deleted. This happens when we set it to Nothing

' https://excelmacromastery.com/
Sub ClassEventsTerm()

    Dim oSimple As clsSimple
    Set oSimple = New clsSimple
    
    ' Terminate occurs here
    Set oSimple = Nothing
   
End Sub

If we don’t set the object to Nothing then VBA will automatically delete it when it goes out of scope.

What this means is that if we create an object in a procedure, when that procedure ends VBA will delete any objects that were created.

' https://excelmacromastery.com/
Sub ClassEventsTerm2()

    Dim oSimple As New clsSimple
    
    ' Initialize occurs here
    oSimple.PrintHello

   ' oSimple is deleted when we exit this Sub calling Terminate
End Sub

Class Module Example 1

In this example, we are going to look at a very common use of a Class module.

Imagine we have the following data

Movie Data

We want to read the Albums based on a range of years and then create various reports.

We could use a 2D Array for this or a Collection of collections e.g.

' https://excelmacromastery.com/
For i = 2 To rg.Rows.Count
    
    Year = rg.Cells(i, 3)
    If startYear <= Year And endYear >= Year Then
        
        ' Create a new collection for each row
        Set rowColl = New Collect
 
        ' Add artist 
        rowColl.Add rg.Cells(i, 1).Value
        ' Add Title 
        rowColl.Add rg.Cells(i, 2).Value
        
        ' and so on

        ' Add row collection to main collection
        coll.Add rowColl

    End If
    
Next i

As you can imagine this code would get messy very quickly.

VBA Class Module record

© BigStockPhoto.com

Lucky for us we have VBA class modules to make our life easier. We can create a class module to store the items.

' clsAlbum class module
Private m_sArtist As String
Private m_sTitle As String
Private m_sYear As String
Private m_sGenre As String
Private m_sSales As String

' Properties
' https://excelmacromastery.com/
Public Property Get Artist() As String
    Artist = m_sArtist
End Property
Public Property Let Artist(ByVal sArtist As String)
    m_sArtist = sArtist
End Property

' etc

Each time we want to add a record we can do it as follows:

' Declare the Variable
Dim oAlbum As clsAlbum

' Create new album
Set oAlbum = New clsAlbum

' Add the details
oAlbum.Artist = rg.Cells(i, 1)
oAlbum.Title = rg.Cells(i, 2)
oAlbum.Year = rg.Cells(i, 3)
oAlbum.Genre = rg.Cells(i, 4)
oAlbum.Sales = rg.Cells(i, 5)

' Add the album object to the collection
coll.Add oAlbum

You can see that this makes our code much more readable. It is clear what Artist, Title etc. are being used for.

We can then easily use this data to create reports, write to files etc.

' https://excelmacromastery.com/
Sub PrintAlbum(coll As Collection)
    
    Dim oAlbum As clsAlbum

    For Each oAlbum In coll
        ' Print out the title and artist for each album
        Debug.Print oAlbum.Title, oAlbum.Artist
    Next
    
End Sub

Below is the full code for this example:

' https://excelmacromastery.com/
Sub CreateReport()

    Dim coll As Collection
    ' read the data
    Set coll = ReadAlbums(1990, 2001)
    
    ' Print the album details
    PrintAlbum coll

    ' Print the total sales
    PrintTotalSales coll
    
End Sub

Function ReadAlbums(startYear As Long, endYear As Long) _
              As Collection
    
    Dim rg As Range
    Set rg = Sheet1.Range("A1").CurrentRegion
    
    ' Create a collection to store the albums
    Dim coll As New Collection
    Dim oAlbum As clsAlbum
    
    Dim i As Long, Year As Long
    For i = 2 To rg.Rows.Count
        
        Year = rg.Cells(i, 3)
        If startYear <= Year And endYear >= Year Then
            ' Create new album
            Set oAlbum = New clsAlbum
            ' Add the details
            oAlbum.Artist = rg.Cells(i, 1)
            oAlbum.Title = rg.Cells(i, 2)
            oAlbum.Year = Year
            oAlbum.Genre = rg.Cells(i, 4)
            oAlbum.sales = rg.Cells(i, 5)
            ' Add the album objecdt to the collection
            coll.Add oAlbum
        End If
        
    Next i
    
    Set ReadAlbums = coll
    
End Function

Sub PrintAlbum(coll As Collection)
    
    Dim oAlbum As clsAlbum
    For Each oAlbum In coll
        Debug.Print oAlbum.Title, oAlbum.Artist
    Next
    
End Sub

Sub PrintTotalSales(coll As Collection)
    
    Dim oAlbum As clsAlbum, sales As Double
    For Each oAlbum In coll
        sales = sales + oAlbum.sales
    Next
    
    Debug.Print "Total number sales is " & sales
    
End Sub

Class Module Example 2

In this example, we’re going to take things a bit further. We’re going to look at some neat tricks when using objects.

Imagine you have a list of products like in the image below.

data film
The products have different fields so we need to use a different class module for each product type. One type for a Book row, one type for a Film row.

We’ll create our class modules first. As you can imagine the are very similar for both product types

' CLASS MODULE - clsBook
' https://excelmacromastery.com/
' Member variables
Private m_Title As String
Private m_Year As Long

' Properties
Property Get ItemType() As String
    ItemType = "Book"
End Property
Property Get Title() As String
    Title = m_Title
End Property
Property Get Year() As Long
    Year = m_Year
End Property

' Methods
Public Sub Init(rg As Range)
    m_Title = rg.Cells(1, 2)
    m_Year = CLng(rg.Cells(1, 4))
End Sub

Public Sub PrintToImmediate()
    Debug.Print ItemType, m_Title, m_Year
End Sub
' CLASS MODULE - clsFilm
' https://excelmacromastery.com/
' Member variables
Private m_Title As String
Private m_Year As Long

' Properties
Property Get ItemType() As String
    ItemType = "Film"
End Property
Property Get Title() As String
    Title = m_Title
End Property
Property Get Year() As Long
    Year = m_Year
End Property

' Methods
Sub Init(rg As Range)
    m_Title = rg.Cells(1, 2)
    m_Year = CLng(rg.Cells(1, 5))
End Sub

Public Sub PrintToImmediate()
    Debug.Print ItemType, m_Title, m_Year
End Sub

As you can see, the only real difference is the Init sub.

When we read each record we need to determine if it is a Book or Film. Then we create the appropriate object. You would imagine we would have to create a variable for each type e.g.

' One variable required for each type
Dim oBook As clsBook
Dim oFilm As clsFilm

' If book do this
Set oBook = New clsBook

' Else If film do this
Set oFilm = New clsFilm

If we had lots of different types this would get very messy indeed. The good news is we only need to use one variable!

In VBA we can declare a variable as a Variant. When we use a Variant we are essentially saying “We will decide the type of variable when the code is running”.

This is very useful when dealing with objects and allows us to get away with using one variable e.g.

' Only one variable required
Dim oItem As Variant

' If book set type to clsBook
Set oItem = New clsBook

' Else If film set type to clsFilm
Set oItem = New clsFilm

This is really useful as we only need one variable no matter how many objects we have.

A second advantage of using a Variant is this. If each Class Module has a sub/function with the same name and parameters, we can use the same variable to call it

So imagine clsBook has a function called InitBook and clsFilm has a function called InitFilm. We would need to do this:

' If clsBook
If Type = "Book" Then
    oItem.InitBook
ElseIf Type = "Film" Then
    oItem.InitFilm

However, if they have the same name, e.g. Init, we can replace the IfElseIf lines of code with one line:

    ' this will call the Init sub of whatever type oItem is set to
    oItem.Init

We can now create a function to create the appropriate object. In Object Oriented Programming, we have what is called a Class Factory. This is simply a function that creates an object based on a given type.

We saw earlier that the Initialize event does not take parameters. We can call Init in the Class Factory to get around this issue.

The full code for the ClassFactory function is here:

' https://excelmacromastery.com/
Function ClassFactory(rg As Range) As Variant

    ' Get product type
    Dim sType As String
    sType = rg.Cells(1, 1)

    ' Create an object based on the type
    Dim oItem As Variant
    Select Case sType
    
        Case "Book":
            Set oItem = New clsBook
        Case "Film":
            Set oItem = New clsFilm
        Case Else
            MsgBox "Invalid type"
    
    End Select
    
    ' Parse the fields to the correct class variables
    oItem.Init rg
    
    ' Return the product object
    Set ClassFactory = oItem
        
End Function

This following is our starting sub. In this sub, we read through the worksheet and pass the range to ClassFactory.

It creates the object, passes the range to the object Parse method. Then it returns the object which we add to our Collection.

' https://excelmacromastery.com/
Sub ReadProducts()
    
    ' Create the collection
    Dim coll As New Collection
    Dim product As Variant
    
    Dim rg As Range


    ' Read products from the worksheet
    Dim i As Long
    For i = 1 To 2
        Set rg = Sheet1.Range("A" & i & ":E" & i)
        Set product = ClassFactory(rg)
        coll.Add product
    Next

    ' Print the product details to the Immediate Window(Ctrl + G)
    PrintCollection coll

End Sub

We can also use the variant object to print the items. As long as both objects have a sub with the same name and parameters(e.g PrintToImmediate) we can call it using a Variant type.

' https://excelmacromastery.com/
Public Sub PrintCollection(ByRef coll As Collection)
    
    Dim v As Variant
    For Each v In coll
        ' Print items
        v.PrintToImmediate
    Next
    
End Sub

The source code for this post also includes this example using Inheritance(i.e. class interfaces). You can download the code here:

Conclusion

That concludes my post on the VBA Class Modules. In this post, we have looked at the parts of the VBA Class Module and two example cases where you would use them.

It’s important to understand that Classes and Objects is a vast topic. There are countless types of objects you can create and ways you can use them.

If you plan to use Class Modules then my advice is to start simple and get familiar with how to create a simple one. Once you have mastered the basics it will be much easier to move onto more challenging scenarios.

What’s Next?

Free VBA Tutorial If you are new to VBA or you want to sharpen your existing VBA skills then why not try out the The Ultimate VBA Tutorial.

Related Training: Get full access to the Excel VBA training webinars and all the tutorials.

(NOTE: Planning to build or manage a VBA Application? Learn how to build 10 Excel VBA applications from scratch.)

ThreeWave
Introduction To Classes

This page is an introduction to Classes.
ShortFadeBar

Classes are a very powerful tool in intermediate to advanced level VBA programming. 
This page is an introduction to what a class and an object are and will
hopefully get you started working with classes. This is by no means a
comprehensive guide. Entire books have been written about Object Oriented Programming, of which classes are an essential component.

In VBA, a class is defined in class module and serves as a
template for an object. The term object is deliberately vague.
An object can be defined to represent whatever you want. Anything that you can describe
conceptually can be represented by a class. The difference between
a class and an object is that a class does nothing and consumes no memory. It is like a blueprint. When
you have a variable of that class type and create instance of that class with the New keyword,
a process called instantiating, it becomes an object and consumes memory and can carry out actions. A
class is defined by its properties, which describe attributes of the class, and
its methods (sub and function procedures), which carry out actions in the object. If a class
is analogous to a noun, a property is like an adjective — it describes the
object. A method is like a verb — it carries out an action.

You must instantiate a class into an object in order to do anything with it. There
is nothing you can do with a class module beyond creating an object from it. An
example of instantiation is shown below:

Dim C As Class1
Set C = New Class1

where Class1 is the name of the class module. Unlike other languages, VB/VBA allows for
only one class in a class module, and the name of the class is the name of the module.
You can now work with the properties and methods defined in Class1 in the C object
variable.

NOTE: It is also possible to combine the two statements above into a single statement:
Dim C As New Class1
This is called an auto-instancing variable. When the variable C is
first encountered in code, a new instance is created. In general, you should avoid auto-instancing variables
for two reasons:

  • First, it adds overhead to the code because the variable must be tested for Nothing every time it is encountered in code.
  • Second, you have no way to test whether a auto-instancing variable is Nothing because the very act of using the variable
    name in an If Obj Is Nothing Then statement will automatically create an instance of the variable.

SectionBreak

Before getting in to classes and objects, it will prove useful to examine
briefly a class’s logical ancestor, the Type declaration. A Type is made up of
other basic variable types. You may be familiar with Types from other programming languages,
in which they are called a struct, structure,
or record. For example, we could declare a Type that describes an
employee:

Type Employee
    Name As String
    Address As String
    Salary As Double
End Type

This defines a single type named Employee which has
three elements: Name, Address,
and Salary. You can then create variables of the
Employee type and give values to the elements. For example,

Dim Manager As Employee
Manager.Name = «Joe Smith»
Manager.Address = «123 Main Street»
Manager.Salary = 40000

Types are quite useful, but have three shortcomings. First, you can’t declare
new instances of a Type. You must declare all the
variables you’ll need at design time or you need a dynamic array that is resized
with Redim Preserve, an awkward and expensive
operation. The second shortcoming of a Type is that
you have no control over what values are assigned to the elements of a
Type. For example, there is nothing to prevent the
assignment of a negative value to the Salary element.
Finally, a Type can’t do anything. It cannot carry out
actions; it is simply a static data structure.

While Types have their place (they are used extensively in Windows API functions),
a class module is often a better solution. New instances of a class may be created
with the New keyword and stored in a Collection or Dictionary object. Next, the properties of a class can be set or retrieved with Property Let
and Property Get procedures, which can contain executable code. Thus, code could
be written to raise an error or take other appropriate action if an invalid value
is used to set a property value, such as a negative value for a Salary. Finally, classes have methods (sub and function procedures) which can
carry out actions. In the example of an employee, there might be a method to print
a paycheck for the employee.

SectionBreak

For illustration, let’s adapt the Employee Type described above into a class. First,
insert a class module into your VBProject (from the Insert menu in the
VBA editor). Name the class CEmployee (it is common practice to use a ‘C’ as the
first letter of a class). There are three properties to create: Name, Address, and
Salary. These values will be stored in private variables within the class. Since
they are declared Private, they cannot be accessed outside the class module.

Private pName As String
Private pAddress As String
Private pSalary As Double

Next, we need to declare Property procedures to allow these variables to be read from
and written to. This is done with Property Get and Property Let functions (or Property
Set

for object type variables).

Public Property Get Name() As String

    Name = pName

End Property

Public Property Let Name(Value As String)

    pName = Value

End Property

Public Property Get Address() As String

    Address = pAddress

End Property

Public Property Let Address(Value As String)

    pAddress = Value

End Property

Public Property Get Salary() As Double

    Salary = pSalary

End Property

Public Property Let Salary(Value As Double)

    pSalary = Value

End Property

The Get procedure is used to return a value out of the class, and the Let procedure
is to put a value into the class.
Note that the return data type of the Get property procedure must be the same data type as the (last) parameter to the
Let property procedure. Otherwise, you’ll get a compiler error. 

Because Property procedures can contain any code you like, the Let Salary procedure
can be written to exclude non-positive values.

Public Property Let Salary(Value As Double)

    If Value > 0 Then
          pSalary = Value

    Else
       
    End If
End Property

A property can be made read-only simply by omitting the Let procedure. For example,
a read-only property might be withholding tax, which is calculated when it is called.
E.g.,

Property Get WithholdingTax() As Double

   
WithholdingTax = calculated value

End Property

Finally, the class can contain methods, such as a PrintPaycheck procedure.

Public Sub PrintPaycheck()

   

End Sub

Now that we have defined the class, we can create objects based on the class. In
a standard code module, declare a variable of type CEmployee.

Dim Emp As CEmployee

Then, Set that variable to a new instance of the class and assign some property values.

Set Emp = New CEmployee
Emp.Name = «Joe Smith»
Emp.Address = «123 Main Street»
Emp.Salary = 40000

SectionBreak

If you need to store multiple instances of a class, such as for a group of employees, you can create mutliple objects from the
class and store them in a Collection or Dictionary object, as shown below.

Dim Employees As Collection

Dim Emp As CEmployee

Set Employees = New Collection

For Each Item In SomeList

    Set Emp = New CEmployee

   

   
Employees.Add Emp

Next Item

Now, you can use a simple For Each loop to loop through the collection and iterate
through the collection and access each instance of CEmployee sequentailly:

Dim Emp As CEmployee
For Each Emp In Employees
    Debug.Print Emp.Name
Next Emp

SectionBreak

The Instancing property of a class controls where that class
may be used. The default value is Private, which means that the class can be used
only in the project in which the class is defined. You
can set the instancing property to PublicNotCreatable, which allows a variable to
be declared as that class type in projects that have a reference to the project
containing the class. The second class may declare a variable of the class type,
but cannot create an instance of the class with the New keyword. See the next section
for more details.

If the Instancing property of the class is PublicNotCreatable a variable
of that class type may be declared in other projects, but cannot be created in that project. You can use a function in the project
containing the class to return a new instance to the caller. First, change the name of the project containing the class from the default value
of VBProject to something meaningful like projSourceProject. Then, in the class that
will use the class, set a reference to projSourceProject. Back in the project containing the class, create a
procedure that will create and return a new instance of the class:

Public Function GetClass() As CEmployee

  
Set GetClass = New CEmployee

End Function

Then call this function in the project that will use the class:

Dim NewEmp As projSourceProject.CEmployee

Set NewEmp = projSourceProject.GetClass()

SectionBreak

Code within a Property or method of a class can refer to its own instance by using the Me reference. For
example,

    Private pName As String
    Property Let Name(S As String)
        pName = S
    End Property
    
    Public Sub SomeMethod()
         
        Me.Name = "ABCD"  
    End Sub

This refers to the Name property of the instance of the class from which it is executed.
Other programming languages, such as C++, C# and Java, use the keyword this to refer to the instance of a class.

SectionBreak

SectionBreak

You can specify a property to be the default property of a class. When you do this,
you can omit that property name and the compiler will use the default property. For
example if you made Name the default property, the following lines of code are functionally
equivalent:

Emp.Name = «Joe Smith»


Emp = «Joe Smith»

See Default Property Of A Class for information and examples of creating a default property.

This page just scratches the surface of what you can do with classes. Consult a good
book on VBA or VB6 programming for a more in depth treatment of classes.

This page last updated: 26-Jan-2012

На чтение 24 мин. Просмотров 22.7k.

VBA Class Modules

Председатель Мао

Классовая борьба, одни классы побеждают, другие исключаются. Такова история

Содержание

  1. Краткое руководство по VBA Class Module
  2. Введение
  3. Почему мы используем объекты
  4. Преимущества использования объектов
  5. Недостатки использования объектов
  6. Создание простого Class Module
  7. Class Module VBA против обычных модулей VBA
  8. Части Class Module
  9. События Class Module
  10. Class Module. Пример 1
  11. Class Module. Пример 2
  12. Заключение

Краткое руководство по VBA Class Module

Пункт Пояснение
Class Module Позволяет пользователю
создавать свои собственные
объекты.
Метод Открытая функция или
подпрограмма в Class Module .
Переменная Переменная, объявленная в Class Module.
Свойство Специальная функция /
подпрограммы, которые ведут
себя как переменные при
использовании
Типы свойств Get, Let и Set.
Событие — инициализация Sub, который автоматически
запускается при создании
объекта Class Module.
Событие — завершение Sub, который автоматически
запускается при удалении
объекта Class Module.
Объявление и создание —
статический
Dim o As New Class1
Объявление и создание —
динамический
Dim o As Class1 
Set o = New Class1 
Вызов подпрограммы Class
Module
o.WriteValues Total
Вызов функции Class Module Amount = o.Calculate()
Использование свойства Class
Module
o.Amount = 1
Total = o.Amount

Введение

Class Module VBA позволяют пользователю создавать свои собственные объекты. Если вы не знакомы с объектами, я настоятельно рекомендую вам сначала ознакомиться с моей статьей Все об объектах VBA Objects.

В таких языках, как C # и Java, классы используются для создания объектов. Class Module являются VBA-эквивалентом этих классов. Основное отличие состоит в том, что Class Module VBA имеют очень ограниченный тип наследования * по сравнению с классами на других языках. В VBA наследование работает аналогично интерфейсам ** в C # Java.

В VBA у нас есть встроенные объекты, такие как Collection, Workbook, Worksheet и так далее. Целью Class Module VBA является предоставление нам возможности создавать собственные объекты.

Давайте начнем эту статью с рассмотрения того, почему мы используем объекты в первую очередь.

*Наследование использует существующий класс для создания нового класса.
**Интерфейсы — это форма наследования, которая заставляет класс реализовывать специфические процедуры или свойства.

Почему мы используем объекты

Использование объектов позволяет нам создавать наши приложения так же, как мы используем строительные блоки.

Идея состоит в том, что код каждого объекта является автономным. Он полностью независим от любого другого кода в нашем приложении.

Это похоже на то, как все строится с использованием кирпичей Lego. Существует много различных типов компонентов Lego. Например, блок, руль и лазер — это разные вещи. Они ведут себя совершенно независимо друг от друга. Но мы можем соединить их вместе, чтобы создать здание, транспортное средство, космическую станцию ​​и так далее.

Если вам все еще неясно, не волнуйтесь. В остальной части этой статьи мы разберем все это на простые термины.

Преимущества использования объектов

Рассматривая части нашего кода как блоки, мы получаем много больших преимуществ.

  1. Это позволяет нам создавать приложения по одному блоку за раз.
  2. Намного проще протестировать отдельные части приложения.
  3. Обновление кода не вызовет проблем в других частях приложения.
  4. Легко добавлять объекты между приложениями.

VBA Class Modules

Недостатки использования объектов

У большинства вещей в жизни есть свои плюсы и минусы. Использование Class Module VBA ничем не отличается. Ниже приведены недостатки использования Class Module для создания объектов.

  1. Первоначально для создания приложений требуется больше времени *.
  2. Не всегда легко четко определить, что такое объект.
  3. Люди, плохо знакомые с классами и предметами, могут сначала найти их трудными для понимания.

*Если вы создаете приложение с использованием объектов, на его создание уйдет больше времени, поскольку вам придется тратить больше времени на планирование и проектирование. Однако в долгосрочной перспективе это сэкономит вам огромное количество времени. Вашим кодом будет легче управлять, обновлять и использовать повторно.

Создание простого Class Module

Давайте рассмотрим очень простой пример создания Class Module и использования его в нашем коде.

Чтобы создать Class Module, мы щелкаем правой кнопкой мыши в окне Project и затем выбираем Insert и Class Module.

VBA Class Module

Наш новый класс называется Class1. Мы можем изменить имя в окне свойств, как показано на следующем скриншоте.

VBA Application

Давайте изменим имя модуля класса на clsCustomer. Затем мы добавим переменную в Class Module следующим образом.

VBA Class Module

Теперь мы можем использовать этот Class Module в любом модуле (стандартном или классе) в нашей рабочей книге. Например:

' Создать объект из Class Module
Dim oCustomer As New clsCustomer

' Установите имя клиента
oCustomer.Name = "Иван"

' Напечатайте имя в Immediate Window(Ctrl + G)
Debug.Print oCustomer.Name

Class Module против Объектов

Люди, которые плохо знакомы с использованием классов и модулей классов VBA, часто путаются между тем, что такое класс и что является объектом.

Давайте посмотрим на пример из реального мира. Думайте о предмете массового производства как кофейная кружка. Дизайн кружки создается в первую очередь. Затем тысячи кофейных кружек создаются из этого дизайна.

Это похоже на работу Class Module и объектов.

Class Module можно рассматривать как дизайн.

Объект можно рассматривать как элемент, созданный из дизайна.

Ключевое слово New в VBA — это то, что мы используем для создания объекта из Class Module. Например:

' Создание объектов с использованием New
Dim oItem As New Class1
Dim oCustomer1 As New clsCustomer
Dim coll As New Collection

Примечание. Мы не используем New для таких элементов, как Workbooks и Worksheets. См. Когда New не требуется для получения дополнительной информации.

Class Module VBA против обычных модулей VBA

Написание кода в Class Module почти такое же, как написание кода в обычном модуле. Мы можем использовать тот же код, который мы используем в обычных модулях. То, как этот код используется, сильно отличается.

Давайте посмотрим на два основных различия между классом и обычным модулем. Это часто вызывает путаницу у новых пользователей.

Разница 1 — Как используются модули

Если вы хотите использовать подпрограмму / функцию и т.д. Из
Class Module, вы должны сначала создать объект.

Например, представьте, что у нас есть два идентичных Sub PrintCustomer. Один находится в Class Module, а другой — в обычном модуле…

' CLASS MODULE Код - clsCustomer
Public Sub PrintCustomer()
    Debug.Print "Пример вывода"
End Sub
' Код обычного модуля 
Public Sub PrintCustomer()
    Debug.Print "Пример вывода"
End Sub

Вы заметите, что коды абсолютно одинаковые.

Чтобы использовать подпрограмму PrintCustomer из Class Module, вы должны сначала создать объект этого типа

' Другой модуль
Sub UseCustomer()

    Dim oCust As New clsCustomer
    oCust.PrintCustomer

End Sub

Чтобы использовать PrintCustomer из обычного модуля, вы можете вызвать его напрямую

' Другой модуль
Sub UseCustomer()

    PrintCustomer

End Sub

Разница 2 — Количество копий

Когда вы создаете переменную в обычном модуле, существует только одна ее копия. Для Class Module существует одна копия переменной для каждого создаваемого вами объекта.

Например, представьте, что мы создаем переменную StudentName как в классе, так и в обычном модуле.

' Обычный модуль
Public StudentName As String
' CLASS MODULE
Public StudentName As String

Для обычной переменной модуля в нашем приложении будет только одна копия этой переменной.

Для Class Module новая копия переменной StudentName создается каждый раз, когда создается новый объект.

Dim student1 As New clsStudent
Dim student2 As New clsStudent

student1.StudentName = "Петр"
student2.StudentName = "Василий"

Когда вы полностью поймете Class Module VBA, эти различия будут казаться очевидными.

Части Class Module

В Class Module есть четыре разных предмета. Это:

  1. Методы — функции / подводные лодки.
  2. Переменные-члены — переменные.
  3. Свойства — типы функций / подпрограмм, которые ведут себя как переменные.
  4. События — подводные лодки, которые запускаются событием

Вы можете видеть, что они все или функции, подпрограммы или переменные.

Давайте кратко рассмотрим некоторые примеры, прежде чем разбираться с ними по очереди.

' CLASS MODULE Код

' Переменная
Private dBalance As Double

' Свойства
Property Get Balance() As Double
    Balance = dBalance
End Property

Property Let Balance(dValue As Double)
    dBalance = dValue 
End Property

' Событие - срабатывает при создании класса
Private Sub Class_Initialize()
    dBalance = 100
End Sub

' Методы
Public Sub Withdraw(dAmount As Double)
    dBalance = dBalance - dAmount
End Sub

Public Sub Deposit(dAmount As Double)
    dBalance = dBalance + dAmount
End Sub

Теперь, когда мы увидели примеры, давайте рассмотрим каждый из них по очереди.

Методы Class Module

Методы относятся к процедурам класса. В VBA есть процедуры и функции. Как и переменные-члены, они могут быть Public или Private.

Давайте посмотрим на пример:

' CLASS MODULE Код

' Имя класса: clsSimple

' Публичные процедуры могут быть вызваны извне объекта
Public Sub PrintText(sText As String)
    Debug.Print sText
End Sub

Public Function Calculate(dAmount As Double) As Double
    Calculate = dAmount - GetDeduction
End Function

' частные процедуры могут быть вызваны только из Class Module
Private Function GetDeduction() As Double
    GetDeduction = 2.78
End Function

Мы можем использовать Class Module clsSimple следующим образом

Sub ClassMembers()
    
    Dim oSimple As New clsSimple
    
    oSimple.PrintText "Hello"
     
    Dim dTotal As Double
    dTotal = oSimple.Calculate(22.44)
     
    Debug.Print dTotal

End Sub

Переменные-члены Class Module

Переменная-член очень похожа на обычную переменную, которую мы используем в VBA. Разница в том, что мы используем Public или Private вместо Dim.

' CLASS MODULE Код

Private Balance As Double
Public AccountID As String

Примечание: Dim и Private делают одно и то же, но соглашение заключается в том, чтобы использовать Dim в sub / functions и использовать Private за пределами sub / functions.

Ключевое слово Public означает, что переменная может быть доступна вне Class Module. Например:

Dim oAccount As New clsAccount

' Действительный - AccountID открыт
oAccount.AccountID = "499789"

' Ошибка - Баланс является частным
oAccount.Balance = 678.90

В приведенном выше примере мы не можем получить доступ к Балансу, потому что он объявлен, как Частный. Мы можем использовать только приватную переменную внутри Class Module. Мы можем использовать функцию / подпрограмму в Class Module, например:

' CLASS MODULE Код
Private Balance As Double

Public Sub SetBalance()
    Balance = 100
    Debug.Print Balance
End Sub

Считается плохой практикой иметь публичные переменные-члены. Это потому, что вы позволяете коду вне объекта мешать работе класса. Цель использования классов состоит в том, чтобы скрыть происходящее от вызывающего.

Чтобы пользователь не общался напрямую с нашими переменными-членами, мы используем Свойства.

Свойства Class Module

  1. Get — возвращает объект или значение из класса
  2. Let — устанавливает значение в классе
  3. Set — устанавливает объект в классе

Формат свойств VBA

Обычный формат для свойств выглядит следующим образом:

Public Property Get () As Type
End Property

Public Property Let (varname As Type )
End Property

Public Property Set (varname As Type )
End Property

Мы уже видели, что свойство это просто тип sub. Назначение свойства — позволить вызывающей стороне получать и устанавливать значения.

Почему мы используем свойства

Почему мы не можем просто сделать переменные общедоступными и использовать их напрямую?

Давайте объясним с некоторыми примерами. Представьте, что у нас есть класс, который ведет список стран. Мы могли бы сохранить список в виде массива:

' Использовать массив для хранения стран
Public arrCountries As Variant

' Установить размер массива при инициализации класса
Private Sub Class_Initialize()
    ReDim arrCountries(1 To 1000)
End Sub

Когда пользователь хочет получить количество стран в списке, он может сделать это:

' Код обычного модуля
Dim oCountry As New clsCountry

' Получить количество элементов
NumCountries = UBound(oCountry.arrCountries) + 1

С приведенным выше кодом есть две основные проблемы

  1. Чтобы узнать количество стран, вам необходимо знать, как хранится список, например, Массив.
  2. Если мы изменим массив на коллекцию, нам нужно будет изменить весь код, который напрямую ссылается на массив

Для решения этих проблем мы можем создать функцию, возвращающую количество стран:

' CLASS MODULE Код - clsCountryList
' Массив
Private arrCountries() As String

Public Function Count() As Long
    Count = UBound(arrCountries) + 1
End Function

Затем мы используем это так

' Код модуля
Dim oCountries As New clsCountries

Debug.Print "Количество стран " & oCountries.Count

Этот код решает две проблемы, которые мы перечислили выше. Мы можем изменить наш массив на коллекцию, и код вызывающего абонента все равно будет работать. Например:

' CLASS MODULE Код
' Коллекция
Private collCountries() As Collection

Public Function Count() As Long
    Count = collCountries.Count
End Function

Вызывающий не замечает, как хранятся страны. Все, что нужно знать вызывающему — это то, что функция Count будет возвращать количество стран.

Как мы только что видели, подпрограмма или функция обеспечивает решение вышеуказанных проблем. Однако использование свойства может обеспечить более элегантное решение.

Использование свойства вместо Function/Sub

Вместо создания функции Count мы можем создать свойство Count. Как вы можете видеть ниже, они очень похожи:

' Замени это 
Public Function Count() As Long
    Count = UBound(arrCountries) + 1
End Function

' На это
Property Get Count() As Long
    Count = UBound(arrCountries) + 1
End Function

В этом сценарии нет большой разницы между использованием свойства и использованием функции. Тем не менее, есть различия. Обычно мы создаем свойство Get и Let так:

' CLASS MODULE Код - clsAccount
Private dTotalCost As Double

Property Get TotalCost() As Long
     TotalCost= dTotalCost 
End Property

Property Let TotalCost(dValue As Long) 
     dTotalCost = dValue 
End Property

Использование Let позволяет нам рассматривать свойство, как переменную. Таким образом, мы можем сделать это:

Второе отличие состоит в том, что использование Let и Get позволяет нам использовать одно и то же имя при обращении к свойству Get или Let. Таким образом, мы можем использовать свойство, как переменную. Это цель использования свойств над подпрограммой и функцией.

oAccount.TotalCost = 6
dValue = oAccount.TotalCost 

Если мы использовали функцию и подпрограмму, то мы не можем получить поведение переменной. Вместо этого мы должны вызвать две разные процедуры, например:

oAccount.SetTotalCost 6
dValue = oAccount.GetTotalCost

Вы также можете видеть, что когда мы использовали Let, мы можем присвоить значение, как переменную. Когда мы используем SetTotalCost, мы должны были передать его в качестве параметра.

О Свойствах в двух словах

  1. Свойство скрывает детали реализации от вызывающей стороны.
  2. Свойство позволяет нам обеспечивать то же поведение, что и переменная.

Типы свойств VBA

Есть три типа свойств. Мы уже видели Get и Let. Но мы еще не рассмотрели Set.

Set похож на Let, но он используется для объекта (подробнее об этом см. Назначение объектов VBA).

Первоначально в Visual Basic ключевое слово Let использовалось для назначения переменной. На самом деле, мы можем использовать его, как захотим.

' Эти строки эквивалентны
Let a = 7
a = 7

Поэтому мы используем Let, чтобы присвоить значение переменной, и мы используем Set, чтобы назначить объект переменной объекта.

' Используем Let
Dim a As Long
Let a = 7

' Используем Set
Dim coll1 As Collection, coll2 As Collection
Set coll1 = New Collection
Set coll2 = coll1
  • Let используется для присвоения значения базовому типу переменной.
  • Set используется для назначения объекта переменной объекта

В следующем примере мы используем свойства Get и Let для строковой переменной

' CLASS MODULE Код

' Свойства SET/LET для переменной
Private m_sName As String

' свойства Get/Let
Property Get Name() As String
    Name = m_sName
End Property

Property Let Name(sName As String)
    m_sName = sName
End Property

Затем мы можем использовать свойства Name так:

Sub TestLetSet()

    Dim sName As String    
    Dim coll As New Collection
    Dim oCurrency As New clsCurrency
    
    ' Свойство Let 
    oCurrency.Name = "USD"
    
    ' Свойство Get 
    sName = oCurrency.Name

End Sub

В следующем примере мы используем свойства Get и Set для переменной объекта

' CLASS MODULE Код

Private m_collPrices As Collection

' Свойства Get/Set 
Property Get Prices() As Collection
    Set Prices = m_collPrices 
End Property

Property Set Prices(collPrices As Collection)
    Set m_collPrices = collPrices
End Property

Затем мы можем использовать свойства так:

Sub TestLetSet()
    
    Dim coll1 As New Collection
    Dim oCurrency As New clsCurrency
    
    ' Свойство Set 
    Set oCurrency.Prices = coll1

    ' Свойство Get 
    Dim coll2 As Collection 
    Set Coll2 = oCurrency.Prices
    
End Sub

Мы используем свойство Get, чтобы вернуть значения для обоих элементов. Обратите внимание, что даже если мы используем свойство Get для возврата коллекции, нам все равно нужно использовать ключевое слово Set для его назначения.

События Class Module

Class Module имеет два события:

  1. Инициализировать — происходит при создании нового объекта класса.
  2. Завершить — происходит, когда объект класса удален.

В объектно-ориентированных языках, таких как C ++, эти события называются Конструктором и Деструктором. В большинстве языков вы можете передавать параметры конструктору, но не в VBA. Мы можем использовать Class Factory, чтобы обойти эту проблему, как показано ниже.

Инициализация

Давайте создадим очень простой Class Module с именем clsSimple с событиями Initialize и Terminate.

' CLASS MODULE Код
Private Sub Class_Initialize()
    MsgBox "Класс инициализируется"
End Sub

Private Sub Class_Terminate()
    MsgBox "Класс прекращается"
End Sub

Public Sub PrintHello()
    Debug.Print "Привет"
End Sub

В следующем примере мы используем Dim и New для создания объекта.

В этом случае oSimple не создается, пока мы не ссылаемся на него в первый раз, например:

Sub ClassEventsInit2()

    Dim oSimple As New clsSimple
    
    ' Инициализация происходит здесь
    oSimple.PrintHello

End Sub

Когда мы используем Set и New вместе, поведение отличается. В этом случае объект создается при использовании Set, например:

Sub ClassEventsInit()

    Dim oSimple As clsSimple
    
    ' Инициализация происходит здесь
    Set oSimple = New clsSimple
    
    oSimple.PrintHello
   
End Sub

Примечание: Для получения дополнительной информации о различиях между использованием New с Dim и использованием New с Set см. Тонкие различия Dim и Set

Как я уже говорил ранее, вы не можете передать параметр в Initialize. Если вам нужно сделать это, вам нужна функция, чтобы сначала создать объект.

' CLASS MODULE - clsSimple
Public Sub Init(Price As Double) 

End Sub 

' обычный модуль
Public Sub Test()

    ' использование функции CreateSimpleObject 
    Dim oSimple As clsSimple
    Set oSimple = CreateSimpleObject(199.99)

End Sub

Public Function CreateSimpleObject(Price As Double) As clsSimple

    Dim oSimple As New clsSimple
    oSimple.Init Price

    Set CreateSimpleObject = oSimple

End Function 

Мы расширим CreateSimpleObject в Примере 2, чтобы создать фабрику классов.

Завершение

Событие Terminate наступает при удалении класса. Это происходит, когда мы устанавливаем значение Nothing.

Sub ClassEventsTerm()

    Dim oSimple As clsSimple
    Set oSimple = New clsSimple
    
    ' Завершение происходит здесь
    Set oSimple = Nothing
   
End Sub

Если мы не установим объект в Nothing, VBA автоматически удалит его, когда он выйдет из области видимости.

Это означает, что если мы создадим объект в процедуре, когда эта процедура завершится, VBA удалит все созданные объекты.

Sub ClassEventsTerm2()

    Dim oSimple As New clsSimple
    
    ' Инициализация происходит здесь
    oSimple.PrintHello

   ' oSimple удаляется, когда мы выходим из этого Sub-вызова Terminate
End Sub

Class Module. Пример 1

В этом примере мы рассмотрим очень распространенное использование Class Module.

Представьте, что у нас есть следующие данные:

Movie Data

Мы хотим читать альбомы по разным годам, а затем создавать различные отчеты.

Мы могли бы использовать для этого 2D-массив или коллекцию коллекций, например:

For i = 2 To rg.Rows.Count
    
    Year = rg.Cells(i, 3)
    If startYear <= Year And endYear >= Year Then
        
        ' Создать новую коллекцию для каждой строки
        Set rowColl = New Collect
 
        ' Добавить исполнителя 
        rowColl.Add rg.Cells(i, 1).Value
        ' Добавить заголовок
        rowColl.Add rg.Cells(i, 2).Value
        
        ' и так далее

        ' Добавить коллекцию строк в основную коллекцию
        coll.Add rowColl

    End If
    
Next i

Как вы можете себе представить, этот код очень быстро запутался.

VBA Class Module record

К счастью для нас, у нас есть Class Module VBA, чтобы сделать нашу жизнь проще. Мы можем создать Class Module для хранения элементов.

' clsAlbum class module
Private m_sArtist As String
Private m_sTitle As String
Private m_sYear As String
Private m_sGenre As String
Private m_sSales As String

' Свойства
Public Property Get Artist() As String
    Artist = m_sArtist
End Property
Public Property Let Artist(ByVal sArtist As String)
    m_sArtist = sArtist
End Property

' и т.д.

Каждый раз, когда мы хотим добавить запись, мы можем сделать это следующим образом:

' Объявить переменную
Dim oAlbum As clsAlbum

' Создать новый альбом
Set oAlbum = New clsAlbum

' Добавить детали
oAlbum.Artist = rg.Cells(i, 1)
oAlbum.Title = rg.Cells(i, 2)
oAlbum.Year = rg.Cells(i, 3)
oAlbum.Genre = rg.Cells(i, 4)
oAlbum.Sales = rg.Cells(i, 5)

' Добавить объект альбома в коллекцию
coll.Add oAlbum

Как видите, это делает наш код более читабельным. Понятно, для чего используются Artist, Title и т.д.

Затем мы можем легко использовать эти данные для создания отчетов, записи в файлы и т.д.

Sub PrintAlbum(coll As Collection)
    
    Dim oAlbum As clsAlbum

    For Each oAlbum In coll
        ' Распечатайте название и исполнителя для каждого альбома
        Debug.Print oAlbum.Title, oAlbum.Artist
    Next
    
End Sub

Ниже приведен полный код для этого примера

Sub CreateReport()

    Dim coll As Collection
    ' читать данные
    Set coll = ReadAlbums(1990, 2001)
    
    ' Распечатать информацию об альбоме
    PrintAlbum coll

    ' Распечатать общий объем продаж
    PrintTotalSales coll
    
End Sub

Function ReadAlbums(startYear As Long, endYear As Long) _
              As Collection
    
    Dim rg As Range
    Set rg = Sheet1.Range("A1").CurrentRegion
    
    ' Создать коллекцию для хранения альбомов
    Dim coll As New Collection
    Dim oAlbum As clsAlbum
    
    Dim i As Long, Year As Long
    For i = 2 To rg.Rows.Count
        
        Year = rg.Cells(i, 3)
        If startYear <= Year And endYear >= Year Then
            ' Создать новый альбом
            Set oAlbum = New clsAlbum
            ' Добавить детали
            oAlbum.Artist = rg.Cells(i, 1)
            oAlbum.Title = rg.Cells(i, 2)
            oAlbum.Year = Year
            oAlbum.Genre = rg.Cells(i, 4)
            oAlbum.sales = rg.Cells(i, 5)
            ' Добавить объект альбома в коллекцию
            coll.Add oAlbum
        End If
        
    Next i
    
    Set ReadAlbums = coll
    
End Function

Sub PrintAlbum(coll As Collection)
    
    Dim oAlbum As clsAlbum
    For Each oAlbum In coll
        Debug.Print oAlbum.Title, oAlbum.Artist
    Next
    
End Sub

Sub PrintTotalSales(coll As Collection)
    
    Dim oAlbum As clsAlbum, sales As Double
    For Each oAlbum In coll
        sales = sales + oAlbum.sales
    Next
    
    Debug.Print "Общее количество продаж составляет " & sales
    
End Sub

Class Module. Пример 2

В этом примере мы пойдем дальше. Мы собираемся взглянуть на некоторые хитрые приемы при использовании объектов.

Представьте, что у вас есть список продуктов, как на картинке ниже.

data film

Продукты имеют разные поля, поэтому нам нужно использовать разные модули классов для каждого типа продуктов. Один тип для строки Книги, один тип для строки Фильмы.

Сначала мы создадим наши модули классов. Они очень похожи для обоих типов продуктов.

' CLASS MODULE - clsBook
' Переменные
Private m_Title As String
Private m_Year As Long

' Свойства
Property Get ItemType() As String
    ItemType = "Book"
End Property
Property Get Title() As String
    Title = m_Title
End Property
Property Get Year() As Long
    Year = m_Year
End Property

' Методы
Public Sub Init(rg As Range)
    m_Title = rg.Cells(1, 2)
    m_Year = CLng(rg.Cells(1, 4))
End Sub

Public Sub PrintToImmediate()
    Debug.Print ItemType, m_Title, m_Year
End Sub
' CLASS MODULE - clsFilm
' Переменные
Private m_Title As String
Private m_Year As Long

' Свойства
Property Get ItemType() As String
    ItemType = "Film"
End Property
Property Get Title() As String
    Title = m_Title
End Property
Property Get Year() As Long
    Year = m_Year
End Property

' Методы
Sub Init(rg As Range)
    m_Title = rg.Cells(1, 2)
    m_Year = CLng(rg.Cells(1, 5))
End Sub

Public Sub PrintToImmediate()
    Debug.Print ItemType, m_Title, m_Year
End Sub

Как видите, единственная реальная разница — это инициализация.

Когда мы читаем каждую запись, нам нужно определить, книга это или фильм. Затем мы создаем соответствующий объект. Представьте, что нам нужно создать переменную для каждого типа, например:

' Для каждого типа требуется одна переменная
Dim oBook As clsBook
Dim oFilm As clsFilm

' Если Книга сделать это
Set oBook = New clsBook

' Если фильм сделать это
Set oFilm = New clsFilm

Если бы у нас было много разных типов, это было бы действительно очень грязно. Хорошей новостью является то, что нам нужно использовать только одну переменную!

В VBA мы можем объявить переменную как вариант. Когда мы используем Variant, мы, по сути, говорим: «Мы определим тип переменной во время выполнения кода».

Это очень полезно при работе с объектами и позволяет нам избежать использования одной переменной, например:

' Требуется только одна переменная
Dim oItem As Variant

' Если книга, указать тип clsBook
Set oItem = New clsBook

' Если фильм, указать тип clsFilm
Set oItem = New clsFilm

Это действительно полезно, так как нам нужна только одна переменная, независимо от того, сколько у нас объектов.

Второе преимущество использования Variant заключается в следующем. Если у каждого Class Module есть подпрограмма / функция с одинаковым именем и параметрами, мы можем использовать одну и ту же переменную для ее вызова.

Представьте, что в clsBook есть функция InitBook, а в clsFilm есть функция InitFilm. Нам нужно сделать это:

' Если clsBook
If Type = "Book" Then
    oItem.InitBook
ElseIf Type = "Film" Then
    oItem.InitFilm

Однако, если они имеют одинаковое имя, например, Init, мы можем заменить строки кода If ElseIf одной строкой:

  ' это вызовет подпрограмму Init любого типа oItem, установленного в
    oItem.Init

Теперь мы можем создать функцию для создания соответствующего объекта. В объектно-ориентированном программировании мы имеем то, что называется фабрикой классов. Это просто функция, которая создает объект на основе заданного типа.

Ранее мы видели, что событие Initialize не принимает параметры. Мы можем позвонить в Init на фабрике классов, чтобы обойти эту проблему.

Полный код для функции ClassFactory здесь:

Function ClassFactory(rg As Range) As Variant

    ' Получить тип продукта
    Dim sType As String
    sType = rg.Cells(1, 1)

    ' Создать объект на основе типа
    Dim oItem As Variant
    Select Case sType
    
        Case "Book":
            Set oItem = New clsBook
        Case "Film":
            Set oItem = New clsFilm
        Case Else
            MsgBox "Invalid type"
    
    End Select
    
    ' Разобрать поля на правильные переменные класса
    oItem.Init rg
    
    ' Вернуть объект продукта
    Set ClassFactory = oItem
        
End Function

Это следующее наше начало. В этом разделе мы читаем таблицу и передаем диапазон в ClassFactory.

Создает объект, передает диапазон в метод Parse объекта. Затем он возвращает объект, который мы добавляем в нашу коллекцию.

Sub ReadProducts()
    
    ' Создать коллекцию
    Dim coll As New Collection
    Dim product As Variant
    
    Dim rg As Range


    ' Читайте продукты с листа
    Dim i As Long
    For i = 1 To 2
        Set rg = Sheet1.Range("A" & i & ":E" & i)
        Set product = ClassFactory(rg)
        coll.Add product
    Next

    ' Распечатать информацию о продукте в Immediate Window(Ctrl + G)
    PrintCollection coll

End Sub

Мы также можем использовать вариант объекта для печати элементов. Пока оба объекта имеют подпрограмму с одинаковым именем и параметрами (например, PrintToImmediate), мы можем вызывать ее, используя тип Variant.

Public Sub PrintCollection(ByRef coll As Collection)
    
    Dim v As Variant
    For Each v In coll
        ' Печать элементов
        v.PrintToImmediate
    Next
    
End Sub

Заключение

На этом я заканчиваю свою статью о Class Module VBA. В этой статье мы рассмотрели части Class Module VBA и два примера, в которых вы могли бы их использовать.

Важно понимать, что классы и объекты — это обширная тема. Существует множество типов объектов, которые вы можете создавать, и способы их использования.

Если вы планируете использовать Class Module, то я советую начать с основ и ознакомиться с тем, как создать простой. Как только вы освоите основы, вам будет намного легче переходить к более сложным сценариям.

Excel VBA Class Module

 VBA class allows us to create our Object function in which we can add any features, details of the command line, and type of function. So, when we create a class in VBA, they act like independent object functions, but they are all connected.

It helps us build applications already there in VBA and Excel. For example, the pedaling cycle wheel rotates. Pedals and wheels are the cycle parts, but both work independently to give the output as a moving cycle.

Table of contents
  • Excel VBA Class Module
    • How to Create Custom Class & Objects in VBA?
    • Pros
    • Cons
    • Things to Remember
    • Recommended Articles

VBA-Class.png

You are free to use this image on your website, templates, etc, Please provide us with an attribution linkArticle Link to be Hyperlinked
For eg:
Source: VBA Class (wallstreetmojo.com)

How to Create Custom Class & Objects in VBA?

You can download this VBA Class Excel Template here – VBA Class Excel Template

Let us consider an example of three different companies’ mobile phones: Apple, Samsung, and Nokia —considering the popular and newly launched mobile phones of these companies, which are the iPhone X, Samsung S8, and Nokia 7+.

We will compare some of the important features of these mobile phones, such as brand, model, screen size, camera type, and charger type. These are important features on that basis. However, we mostly compare any mobile phone. Below we have mapped the above-discussed parameters in a chart.

Mobile Phone Chart

In the VBA window from the Insert menu, select the Class Module, as shown below.

vba class Example 1

We will get the class module window starting with Option ExplicitVBA option explicitly makes a user mandatory to declare all the variables before using them; any undefined variable will throw an error while coding execution. We can enable it for all codes from options to require variable declaration.read more, as shown below.

vba class Example 1-1

Option Explicit ensures that it must declare variables before using. If we do not declare any variable and use it, the system will throw an error. Now, in class, define all the discussed parameters of measurement of mobile phones with the Public. Then, it will make those defined parameters open to use anytime, anywhere, without limitations.

Code:

Option Explicit

'List of properties
Public Brand As String
Public Model As String
Public ScreenSize As String
Public CameraType As String
Public ChargerType As String

vba class Example 1-2

Now, we will add different operating, features, and functions of a mobile phone, such as starting a phone, Switching off the phone, playing music, charging the battery, etc., with a subcategory for each function as shown below. And add a message box in each subcategory loop so we can see which methods are currently running.

Code:

'Possible Techniques

Sub MobileStarts()

MsgBox "Mobile is Turning On"

End Sub

Sub MobileOff()

MsgBox "Mobile is Turning Off"

End Sub

Sub PlayMusic()

MsgBox "Audio system is currently working"

End Sub

Sub BatteryCharge()

MsgBox "Charger is currently plugged-in"

End Sub

vba class Example 1-3

It completes the creation of the class. However, changing the class module’s name is advisable before we move further. Choose any name as per your requirement as we change it to Mobile.

vba class Example 1-4

Now, we will write a code in a module where we will see and compare the features and functions of each mobile phone brand. As shown, first, we need to add a Module under the “Insert” menu.

vba class Example 1-5

We will open a new module with Option Explicit enabled as we work and create a class. Then, write a subcategory in the name of performed functions, as shown below.

vba class Example 1-6

We can also change the module’s name as we did for class. It helps us keep the co-related identity of the created VBA codeVBA code refers to a set of instructions written by the user in the Visual Basic Applications programming language on a Visual Basic Editor (VBE) to perform a specific task.read more. It can be done from properties windows, as shown below.

vba class Example 1-7

We have already defined various features, functions, and methods of all brand mobile phones. Now, let us define three variables in any name (preferably in the name of the mobile phone brand) and assign them to Mobile. Let us start with the iPhone first, as shown below.

vba class Example 1-8

Similarly, do the same for the other mobile phone brands, as shown below.

vba class Example 1-9

By this, we assign the created Class to each dimensional variable of the Mobile brand. Now for each brand, do the same process of assigning the Class.

Now, we need to assign all the features of the Mobile phone and its value. First, use the Set function and assign it to a New Mobile, as shown below.

vba class Example 1-10

Now, open the “With-End” loop for iPhone. It is where we will define each attribute of the mobile.

Example 1-11

As we can see, we have assigned all the defined features of the iPhone brand from class with specific values as String.

Example 1-13

Do the same thing for Samsung and Nokia brands as well.

Example 1-12

Now we will use DebugPrint to print the information on the prompt window. It is useful where we want to see a certain variable in a line of code. First, we will select different features for each Mobile brand, as shown below.

Example 1-14

Now, assign the MobileStarts and MobileOff functional operations, which we defined in the class, to each mobile brand in the same module along with the message box. You may skip the message box here.

Example 1-15

It completes the assigning of classes to the module. Now, compile the code and run using the F5 key. Finally, we will see the message of each mobile brand, as shown below.

Message of mobile brand

Now, if you want to know what variables and functions have what kind of values in them, we must open the Locals window from the “View” tab, which will help us get the details when we compile the code, as shown below.

Local window

The below code is for your Reference.

Code:

Sub VBA_Class()

Dim iPhone As Mobile
Dim Samsung As Mobile
Dim Nokia As Mobile

Set iPhone = New Mobile
With iPhone
.Brand = "iPhone"
.Model = "iPhone X"
.ScreenSize = "6.5 Inches"
.CameraType = "12 MegaPixel"
.ChargerType = "Regular"
End With

Set Samsung = New Mobile
With Samsung
.Brand = "Samsung"
.Model = "Samsung S8"
.ScreenSize = "5.8 Inches"
.CameraType = "12 MegaPixel"
.ChargerType = "Power"
End With

Set Nokia = New Mobile
With Nokia
.Brand = "Nokia"
.Model = "Nokia 7+"
.ScreenSize = "6 Inches"
.CameraType = "12 MegaPixel"
.ChargerType = "Power"
End With

Debug.Print "Phone Screen Size is: " & iPhone.ScreenSize
Debug.Print "Camera of Samsung is: " & Samsung.CameraType
Debug.Print "Charger Type is: " & Nokia.ChargerType

iPhone.MobileStarts
iPhone.MobileOff
MsgBox iPhone.Model

Samsung.MobileStarts
Samsung.MobileOff
MsgBox Samsung.Model

Nokia.MobileStarts
Nokia.MobileOff
MsgBox Nokia.Model

End Sub

Pros

  • We can build our application with a lot of features.
  • Once we create the class, we can update any feature whenever we require it.
  • If we update the code, it won’t cause any problems in other parts of the class.
  • We can test the individual part of the application as per our needs.

Cons

  • Initially, it takes a lot of time to create a class in VBA.
  • New to VBA may find the class very difficult to apply.

Things to Remember

  • As the code can be huge, it is better to compile it step-by-step. By doing this, we would avoid the number of errors, which will be difficult for us to debug and resolve.
  • We can ignore the use of the message box if you are taking and testing the above-written code.
  • You can use lesser techniques or functions to create a class for testing. Then, it can be modified later when we want to add more product functions and techniques.
  • Consider similar or same features when we finish class and assign it to a module. Then, it will help us in comparing the features of different products.

Recommended Articles

This article is a guide to VBA Class. We discuss creating custom VBA classes and objects, examples, and a downloadable Excel template here. Below are some useful articles related to Excel VBA: –

  • VBA Resize
  • Use DateSerial in VBA
  • Named Range in VBA
  • ME Keyword in Excel VBA
  • VBA VARTYPE Function

In this Article

  • VBA Class Modules – Introduction
    • Class Modules vs. Modules
    • Advantages of Using Class Modules
    • Disadvantages of Using Class Modules
  • Inserting a Class Module
  • Creating an Object Item
  • Creating a Collection
  • Using Your New Object
  • Summary of Creating an Object Using a Class Module
  • Using a Class Module to Create a Variable Repository
  • Turning Your Object into an Add-In

This tutorial will teach you about Class Modules in VBA. You’ll learn what they are and how to use them.

VBA Class Modules – Introduction

When you insert modules into the Visual Basic Editor (VBE) in order to enter your code, you may have noticed that you can also insert what is called a ‘Class Module’.

vba class module

Class Modules vs. Modules

The class modules work in a very different way to the ordinary modules in that they facilitate creating a Component Object Model (COM) which can then be used within your normal VBA code

Effectively, you create an object which works in the same way as a built in Excel object such as ‘Worksheets’.  In the Worksheets Object, you have a number of properties and methods which allow you to get the number of worksheets within a workbook or each individual name of a worksheet, or numerous other information

When you create a new Object in this way, you are creating a building block which can be used anywhere within VBA. The Object has a number of properties and methods that can be accessed by your VBA code from anywhere within the workbook without having to keep re-writing the code over again.

As well as referring to your new object from a standard VBA module, you can also use it in the code behind a UserForm that is part of your custom application

You can also use it where you have placed Active X controls onto a worksheet, such as a command button or a drop down. These controls all use VBA, and your new object can easily be incorporated into the event code for these controls.

You can also turn your object into an Excel add-in. Your object will automatically be available to other users who have that add-in loaded.  This adds your own multi-tier architecture to your Excel application

Excel is a multi-tiered application.  There is the client services layer, which drives the actual worksheet window that that the user is familiar with. The Excel object model is the next layer underneath.  Press F2 in a VBA module and you will be able to see the huge number of objects and members of those objects that are the engine of Excel.  Note that your new object will also be displayed here.

Finally, underneath all of this, you have the data services layer which holds all the data that you have entered into the worksheets and cells.  Excel accesses this using the Excel Object model.

excel object model

Creating a Class Module allows you to extend the Excel Object Module with your own custom objects and members

This article explains to you how you to create a simple hierarchy of objects using Class Modules.

Advantages of Using Class Modules

  1. You can develop a robust building block which can be used in any number of different Excel applications
  2. Once it is thoroughly tested, then is can be relied on to always produce the correct results in the same way as the built-in Excel objects
  3. If updates are made to code elsewhere in the application, the new object will still continue to work in the same way
  4. You can use your new object in other Excel applications as an add-in
  5. The objects can be re-used in other applications and helps in debugging

Disadvantages of Using Class Modules

  1. They can be difficult to create and understand.
  2. Naming conventions are very important because this is what you will see when use your object within a normal module.
  3. If you have not created a class module before, they can be difficult to understand and there is a steep learning curve
  4. Impossible to make changes at run-time – you have to re-set the project.
  5. If Properties and Private Variables have the same name then infinite loops can occur resulting in errors

Inserting a Class Module

Select Insert | Class Module from the VBE (Visual Basic Editor) menu. The new Class Module will automatically be called ‘Class 1’, but this needs to be changed immediately to the name that you are going to use for your object

insert class module

You change the name in the Properties window where the arrow is pointing.  You simply type in your new name, and this will change in the Class Modules collection

If the Properties window is not visible, then select View | Properties on the VBE menu or press F4

Call your new class module ‘MyItem’ and double click the name in the tree-view in the Project Explorer to display the code window for it.

Creating an Object Item

This example will create a top-level object called ‘MyItems’ with a member object below it called ‘MyItem’ which will hold the individual data for each item.  Once created it will work in the same way as a built in Excel Object. For example, there is an object called ‘Worksheets’ which is a collection of each worksheet within your workbook. There is also an object called ‘Sheet’ which represents each individual worksheet within your workbook, and holds all the properties and methods for each worksheet.  This object relates to the ‘Worksheets’ collection object.

You can iterate through the ‘Worksheets’ collection, viewing each ‘Sheet’ in turn.  In the same way you will be able to iterate through the ‘MyItems’ collection viewing the properties that you created in the ‘Myitem’ member.

The first thing to do is to create the sub object for the member level which will hold the actual items within the collection of the top-level object.  This is the equivalent of the members (e.g. name, visible, count) within the ‘Sheet’ object in Excel.  This code is entered into the class module called ‘MyItem’

Class modules have Properties and Methods.  Properties are effectively like variables, in that they hold values of data like variables, and Methods are like sub routines or functions.

In the sub object we are going to create two properties for the object – Item and Detail

Initially two string variables need to be declared to hold the values for the properties:

Private mItem As String
Private mDetail As String

These need to be declared in the Declarations section at the top of the code for the class module so that they can be used in all sub routines throughout the module

They need to be given unique names to make them different from the properties that we are going to create, so an ‘m’ (for member) has been put in front of each name.

The variables are declared as Private so they cannot be seen by anyone using the object.  They are working variables for use within the object code and are not there as part of the final object.

The next step is to set up code to give access to the two properties. You do this by means of a Property Let and a Property Get statement for each property.  These must be Public otherwise the top-level object will not have any visible properties

Public Property Let Item(vdata As String)
      mItem = vdata
End Property

Public Property Get Item () As String
      Item = mItem
End Property

Public Property Let Detail (vdata As String)
      mDetail = vdata
End Property

Public Property Get Detail () As String
      Detail = mDetail
End Property

This code creates the means to read and write values to the two properties (Item and Detail) using the two private variables that were defined in the declarations section of the module.

The ‘vdata’ parameter is used to pass data to the property concerned.

It is important that each property has a ‘Let’ and ‘Get’ statement and that the property name is the same in each case. You could end up with two different properties if miss-spelt  – one that you can read from and one that you can write to!

To help with creating this code, you can use Insert | Procedure on the VBE menu to create a code skeleton which will create the initial code for the ‘Get’ and ‘Let’ properties for a given property name

This will display a pop-up window where you type the property name in and select ‘Property’ on the radio buttons:

class module property

Click ‘OK’ and the skeleton code will be added into the class module:

Public Property Get MyProperty() As Variant

End Property

Public Property Let MyProperty(ByVal vNewValue As Variant)

End Property

This prevents any mistakes over names of properties. You simply add your code in between the ‘Public Property’ and ‘End Property’ statements.

You now have an object called ‘MyItem’ which will hold all the data for this exercise.

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!

automacro

Learn More

Creating a Collection

The next stage is to create a top-level object as a Collection object to give access to the properties that you have set up in the ‘MyItem’ object

Again, you need to define a working object to act as the collection object in the same way that you defined the two string variables in the ‘MyItem’ object.

Private mItems As Collection

Again, this this has to have a unique name which is why there is an ‘m’ (member object) in front of the name, and it is also declared as ‘Private’ so that it does not appear when the new object is being used

Next, you need to populate the Class_Initialize code. This runs when you first use the object within your code, and it determines what values will be loaded into the object

You can access this sub routine by selecting ‘Class’ in the first drop down and ‘Initialize’ in the second drop down of the module window

Private Sub Class_Initialize()
Dim objItem As MyItem
Set mItems = New Collection
For n = 1 To 3
       Set objItem = New MyItem
       objItem.Item = Worksheets("Sheet1").Range("a" & n).Value
    objItem.Detail = Worksheets("Sheet1").Range("b" & n).Value
       mItems.Add objItem
Next n
End Sub

The code sets up an object called ‘objItem’ using the definition of ‘MyItem’ which we built as a class module earlier on.

It then creates a new Collection based on the ‘mItems’ object defined earlier

It iterates through values held on Sheet1 of the workbook and puts them into the properties that we created for the ‘MyItem’ object.  Note that when you use ‘objitem’, a drop down appears showing the two properties, exactly as if you were using a built-in Excel object.

The item object is then added into the collection object which now holds all the data in the property values.

The input data does not have to be taken from a worksheet.  It could be static values, or it could come from a connection to a database such as Microsoft Access or SQL Server, or it could come from another worksheet.

You then need to add a public function called ‘Item’

Public Function Item(index As Integer) As MyItem
      Set Item = mItems.Item(index)
End Function

This allows you to refer to individual objects within the collection object by their index number.  This function provides a ‘mirror’ of what is going on in the ‘mMyItems’ collection in the background.

You will also need to add a property called ‘Count’ so that your code can establish how many ‘MyItem’ objects are in the ‘MyItems’ collection, should you wish to iterate through it.

Public Property Get Count() As Long
      Count = mItems.Count
End Property

In this case you only need a ‘Get’ property because it is read-only.  It uses the mItems collection because this already has a count property built into it.

You now have an object (MyItems) with a full hierarchy defined by the object ‘MyItem’

To make the whole thing work, you now need to populate a worksheet (Sheet1) with data so that the Class Initialize routine can collect this into the object

Your spreadsheet should look like this:

class module collection

Using Your New Object

You can now use your Collection object (MyItems) within a standard Excel VBA module. Enter the following code:

Sub test_object()
Dim MyClass As New MyItems, n As Integer
MsgBox MyClass.Count
For n = 1 To MyClass.Count
    MsgBox MyClass.Item(n).Item
    MsgBox MyClass.Item(n).Detail
Next n
End Sub

This code creates an object called ‘MyClass’ based on the collection object that you created called ‘MyItems’. This fire off the ‘Initialize’ routine that extracts all the data from the worksheet into the object.

It displays the number of items in the collection and then iterates through the collection showing the ‘Item’ text and the ‘Detail’ text. You will notice that when you refer to the ‘MyClass’ object in your code, you will see a list of the two member properties which helps in adding the correct property.

If you change the value of a cell in the input data on the spreadsheet, this will automatically be updated in the collection when you run the above code again, since when you dimension the object, the initialize routine runs and picks up all the new data

If you use the word ‘Static’ instead of ‘Dim’ the initialise routine does not run and the old values are kept, so long as the code is continuously running.  If the data on the spreadsheet changes this will not be reflected in the object

Sub Test_Static()
Static Myclass As New MyItems, n As Integer
For n = 1 To Myclass.Count
       MsgBox Myclass.Item(n).Item
    MsgBox Myclass.Item(n).Detail
Next n
End Sub

Summary of Creating an Object Using a Class Module

As you have seen, creating a hierarchy of class modules to use as an object is quite a complicated business, even for a structure as simple as the example provided here.  The scope for making mistakes is enormous!

However, it does have huge advantages in making your code more elegant and easier to read.  It is also easier to share with other Excel applications and developers by turning it into an Add-In.

In this example of how to create an object to hold data, it would be a normal approach to create a multi-dimensional array to hold the multi-column spreadsheet data, and you would write a line of code to update or read each element in the array. This would probably end up being quite messy, and mistakes could easily be made in addressing the various elements.

With your new object, you can simply refer to it and the members that you have created below it to hold the data.

Also, if the data changes in the spreadsheet (or in a linked database if you have used this as a data source within your class module) whenever you use the ‘Dim’ statement the initialize routine will be called and the data will be instantly updated. No need to write code to re-populate your array.

VBA Programming | Code Generator does work for you!

Using a Class Module to Create a Variable Repository

When you write VBA code you use variables all over the place, all with different scopes.  Some may only be defined for a particular procedure, some for a particular module, and some may be global variables that can be used all over the application

You can create a class module that will hold a large number of variables, and because it is an object, it can be used anywhere within your code, even on a user form or in an Active X control that you have placed on a worksheet.

The added advantage is that when you refer to your variable object, you will see a list of all the variable names held in the object sorted into ascending order.

To create a repository, you need to insert a new class module. You do this by using Insert | Class Module from the VB Editor menu

Change the name to ‘MyVariables’ using the same methodology as previously discussed in this article.

Enter the following code:

Private mV As Variant
Public Property Get Variable1() As Variant
Variable1 = mV
End Property

Public Property Let Variable1(ByVal vNewValue As Variant)
mV = vNewValue
End Property

Public Property Get Variable2() As Variant
Variable1 = mV
End Property

Public Property Let Variable2(ByVal vNewValue As Variant)
mV = vNewValue
End Property

This code sets up ‘Let’ and ‘Get’ properties for two variables (‘Variable1’ and ‘Variable2’).  The Let and Get properties are required for each of your variables so that they are read / write

You can use your own names for the variables instead of the sample ones in this code, and you can add further variables, making sure that each new variable has a ‘Let’ and ‘Get’ statement.

The private declaration of the variable ‘mV’ is to create a working variable that is only used within the class module to transfer values.

To use the variable repository, enter the following code into a standard module:

Global VarRepo As New MyVariables
Sub TestVariableRepository()
MsgBox VarRepo.Variable1
VarRepo.Variable1 = 10
MsgBox VarRepo.Variable1
End Sub

This code creates a global instance of your ‘MyVariables’ object that you created.  You only need to do this declaration once from anywhere within your code.

The code first displays the value of ‘Variable1’ to show that it is empty.

A value of 10 is assigned to ‘Variable1’ and the new value within the object is then displayed to show that this property now holds this value.

Because the instance of the ‘MyVariables’ object has been defined globally, you can refer to any of the defined variables within the object from anywhere within your code.

This has a huge advantage in that if you want to use your variables anywhere in your code, you only need to define one global variable, and from that instance, all the variables can be freely accessed and modified throughout your code.

Turning Your Object into an Add-In

So far, the code for the object creation is within your workbook application.  However, if you want to be able to share your object with other developers or in other Excel applications of your own, you can turn it into an Add-In

To do this, all that needs to happen is to save the file as an Add-In.  Select File | Save As and a browser window will appear

Select the file type as Add-In (.xlam) from the file type drop down and click OK.  The file will be saved to the Add-In folder by default, but you can change the location.

You can then incorporate the add-in file into your Excel applications, giving you the flexibility to make use of your new object

vba class module example

To include your new Add-In into Excel, click on File on the Excel ribbon, and then click on Options at the bottom of the left-hand pane

Click on ‘Add-Ins’ in the left-hand pane in the pop-up window that appears.  At the bottom of the window is a button marked ‘Go’

Click on this and an ‘Add-In’ pop-up window will appear. Click on ‘Browse’ and then locate your Add-In file. You will then be able to refer to your object in your code.

vba class module tutorial

Excel VBA Custom Classes & Objects, Class Modules, Custom Events

—————————————————————

Contents:

Custom Classes and Objects

Custom Class Events

—————————————————————

In vba you can create your own custom objects by defining classes & inserting class modules. You can also create your own custom class events, in addition to Excel’s own inbuilt event procedures. In this section we explain how to create custom objects by inserting a class module and how to create your own custom events in a class.

Custom Classes and Objects

In vba you can create your own custom objects by defining classes. Classes act as templates for new objects. The custom object is used to store, process and make data available. A Class contains data and code — data can be accessed with properties (viz. Name property) and the code is referred to as methods (which are defined as Subs and Functions in VBA). Classes are integral to the Object-Oriented Programming (OOP) language. A class is created by inserting a Class Module (in your VBA project) to which you give a name. A Class Module allows you to create your own objects having their own properties and methods much like other objects such as range, worksheet, chart, etc. The Class Module has its own set of vba code (which includes variables, constants and procedures), which defines its properties and methods. The properties of the class object are manipulated in a Class Module with Property procedures which use the Property Let, Property Get, and Property Set statements. To access the properties and methods of the class object from a procedure in a code module, you declare an object variable of the class’s type in that procedure.

You can do all vba programming without creating custom objects which do not really increase code functionality. However, using custom objects makes complex coding look simpler by having related code in one place, makes coding self-documenting with appropriately named classes, properties & methods, and this helps in debugging and reusing code.

Insert a Class Module:

In Visual Basic Editor (VBE), click Insert in the menu bar and then click Class Module. Alternatively, in the Project Explorer in VBE, right click on the VBA Project name or any object or item under it, click Insert and then click Class Module. Or, on the Standard Tool bar in VBE, click the Insert button and then click Class Module. This creates a blank class with the name Class1. To remove or delete a Class Module, right click after selecting it in the Project Explorer in VBE, and then click on Remove.

Name a Class Module:

The name of the selected Class Module appears to the right of (Name) in the Properties Window in VBE, and can be changed therein.

Instancing Property of a Class Module:

The Instancing property of a Class Module is set to Private by default which does not allow an external project from working with and using instances of that class. Set the Instancing property to PublicNotCreatable to allow external projects, with a reference set to the project containing the defined class, to access and use instances of the defined class. Note that the setting of PublicNotCreatable still does not allow the external project to instantiate (ie. create or call into existence) the class object or an instance of the class, which can be instantiated only by the project which contains the definition of the class. Note that the external project can use an instance of the defined class if the referenced project has already created that instance.

Instantiate a Class Object:

As already mentioned, in vba you can create your own custom objects by defining classes. A class is created by inserting a Class Module. To access the properties and methods of the class object from a procedure in a code module, you need to create a new instance of the class object ie. instantiate  (ie. create or call into existence) an instance of the class. Note that multiple number of instances of a class object can be created. There are two ways of doing this, one with a two-line code or alternatively with a single-line code.

Two-line code to instantiate an instance of a class:

Use the Dim statement to create a variable (iStudent) and define it as a reference to the class (clsStudent):

Dim iStudent As clsStudent

Create a new object reference by using the New keyword. Mention the name of the class (clsStudent) you want to instantiate, after the New keyword:

Set iStudent = New clsStudent

Alternate single-line code to instantiate an instance of a class:

In this case the clsStudent object gets instantiated only when the class method is first called ie. iStudent gets instantiated only when first used.

Dim iStudent As New clsStudent

Create Class Properties:

One way to create a class property is by declaring a Public Variable in the Class Module, and this property will be read-write. The other way to create a class property is by using Property Procedures ie. create a private variable to hold values and use property statements (viz. Property Let, Property Set and Property Get). Creating properties using a Public Variable, though simple, may not usually be preferable because it is not flexible. Using property statements will enable to set a read-only or write-only property in addition to read-write, whereas using a public variable will create only read-write properties. Further, using property statements you can execute code to calculate values as properties whereas using a public variable will not allow use of code to set or return the value of a property. For example, in case of an Area property, the area of a rectangle changes per its length-width and in case the length-width is dynamic it should not be stored as a fixed value.

Create methods in a Class Module: In addition to properties, objects can also have one or more methods. A method is defined as Subs and Functions in VBA and is created with Sub-routine and Function procedures. A method is a sub-procedure containing a set of codes which perform an action or an operation on the data within the class, or a function containing a set of codes which returns a value after performing an operation. In a Class Module, only if the method is declared Public can it be called from an instance of this class, else if a method is declared Private it can be called only from other methods within the class. Note, that by default a procedure is Public if the Private or Public keywords are not specified.

Using Property Procedures to Create Properties:

Property Procedure is a set of vba codes that creates and manipulates custom properties for a class module. A Property procedure is declared by a Property Let,  Property Get or Property Set statement and ends with an End Property statement. Property Let (write-only property) is used to assign a value to a property and Property Get (read-only property — which can only be returned but not set) returns or retrieves the value of a property. Property Set (write-only property) is used to set a reference to an object. Property procedures are usually defined in pairs, Property Let and Property Get OR Property Set and Property Get. A Property Let procedure is created to allow the user to change or set the value of a property, whereas the user cannot set or change the value of a read-only property (viz. Property Get).

A property procedure can do whatever can be done within a vba procedure like performing an action or calculation on data. A Property Let (or Property Set) procedure is an independent procedure which can pass arguments, perform actions as per a set of codes and change the value of its arguments like a Property Get procedure or a Function but does not return a value like them. A Property Get procedure is also an independent procedure which can pass arguments, perform actions as per a set of codes and change the value of its arguments like a Property Let (or Property Set) procedure, and can be used similar to a Function to return the value of a property.

A Property Get declaration takes one argument less than in the associated Property Let or Property Set declaration and the Property Get declaration should be of the same data type as the data type of the last argument in the associated Property Let or Property Set declaration. The Property Get declaration will use the same property name as used in the associated Property Let or Property Set declaration.

A Property Let procedure can accept multiple arguments, and in this case the last argument contains the value to be assigned to the property. This last argument in the argument list is the property value set by the calling procedure. The name and data type of each argument in a Property Let procedure and its corresponding Property Get procedure should be the same, except for the last argument in the Property Let procedure which is additional. All arguments before the last argument are passed to the Property Let procedure. In the case of a Property Let procedure with a single argument (at least one argument is required to be defined), this argument contains the value to be assigned to the property and is the value set by the calling procedure. In this case the Property Get procedure will have no argument. It is not a usual practice to pass multiple arguments in property procedures and sub-procedures or Functions are used for this.

A Property Set procedure can accept multiple arguments, and in this case the last argument contains the actual object reference for the property. All arguments before the last argument are passed to the Property Set procedure. In the case of a Property Set procedure with a single argument (at least one argument is required to be defined), this argument contains the object reference for the property. The data type of the last argument or the single argument must be an Object type or a Variant.

The Property Set procedure is similar to and a variation of the Property Let procedure and both are used to set values. A Property Set procedure is used to create object properties which are actually pointers to other objects, whereas a Property Let procedure sets or assigns values to scalar properties like string, integer, date, etc. Using the Property Set statement enables Properties to be represented as objects.

Below is the syntax for the 3 property procedure declarations.

Property Get:

Property Get PropertyName(argument_1, argument_2, …, argument_n) As Type

Property Let:

Property Let PropertyName(argument_1, argument_2, …, argument_n+1)

Property Set:

Property Set PropertyName(argument_1, argument_2, …, argument_n+1)

Examples

Example 1 — Create Class Properties by using Property Procedures. Refer Images 1a & 1b. For live code, click to download excel file.

Insert Code in Class Module named clsStudent:

‘Example — Create Class Properties by using Property Procedures:
Private strStuName As String
Private dblStuMarks As Double

Public Property Let Name(strN As String)
‘declare the property procedure Public so that it can be called from an instance of this class in another module.
‘In the case of a Property Let procedure with a single argument (at least one argument is required to be defined), this argument contains the value to be assigned to the property and is the value set by the calling procedure. In this case the Property Get procedure will have no argument. A Property Let procedure is created to allow the user to change or set the value of a property, whereas the user cannot set or change the value of a read-only property (viz. Property Get).

strStuName = strN

End Property

Public Property Get Name() As String
‘returns the Name property

Name = strStuName

End Property

Public Property Let Marks(iMarks As Double)
‘assigns the Marks property

dblStuMarks = (iMarks / 80) * 100

End Property

Public Property Get Marks() As Double
‘returns the Marks property

Marks = dblStuMarks

End Property

Public Function Grade() As String
‘Create a Method within a Class — declare the method Public so that it can be called from an instance of this class in another module.

Dim strGrade As String

If dblStuMarks >= 80 Then

strGrade = «A»

ElseIf dblStuMarks >= 60 Then

strGrade = «B»

ElseIf dblStuMarks >= 40 Then

strGrade = «C»

Else

strGrade = «Fail»

End If

Grade = strGrade

End Function

Insert Code in a Standard Code Module:

Sub clsStudentRun()
‘this procedure instantiates an instance of a class, sets and calls class properties:

‘use the Dim statement to create a variable and define it as a reference to the class.
Dim iStudent As clsStudent

‘a new object reference is created by using the New keyword. Mention the name of the class you want to instantiate, after the New keyword.
‘following code line (together with the above Dim statement, it is a two-line code to instantiate an instance of a class), instantiates the clsStudent object:
Set iStudent = New clsStudent

‘alternate single-line code to instantiate an instance of a class, however in this case the clsStudent object gets instantiated only when the class method is first called, ie. iStudent gets instantiated only when first used:
‘Dim iStudent As New clsStudent

‘sets the Name property in the clsStudent object to be the string «Peter», and passes this data to the strN variable in the Name property:
iStudent.Name = «Peter»

‘call the Name property in the clsStudent object
MsgBox iStudent.Name

‘sets the Marks property in the clsStudent object to the value 45, and passes this data to the iMarks variable in the Marks property:
iStudent.Marks = 45

‘call the Marks property in the clsStudent object
MsgBox iStudent.Marks

‘call the Grade function from the clsStudent object:
MsgBox iStudent.Grade

MsgBox iStudent.Name & » has got » & iStudent.Marks & » percent marks with a Grade » & iStudent.Grade

End Sub

————————————————————————————————————————

Example 2 — Create Class Properties by using Property Procedures, Property Let procedure accepting multiple arguments. For live code, click to download excel file.

Insert Code in Class Module named clsRectangle:

‘Example — Create Class Properties by using Property Procedures, Property Let procedure accepting multiple arguments.
Private dblA As Double

Public Property Let Area(lngth As Double, wdth As Double, ar As Double)
‘A Property Let procedure can accept multiple arguments, and in this case the last argument contains the value to be assigned to the property. This last argument in the argument list is the property value set by the calling procedure. The name and data type of each argument in a Property Let procedure and its corresponding Property Get procedure should be the same, except for the last argument in the Property Let procedure which is additional. All arguments before the last argument are passed to the Property Let (& Property Get) procedure.

‘In the case of a Property Let procedure with a single argument (at least one argument is required to be defined), this argument contains the value to be assigned to the property and is the value set by the calling procedure. In this case the Property Get procedure will have no argument.

‘It is not a usual practice to pass multiple arguments in property procedures and sub-procedures or Functions are used for this.

dblA = ar

MsgBox «Arguments received — lngth: » & lngth & «, wdth: » & wdth & «, ar: » & ar

End Property

Public Property Get Area(lngth As Double, wdth As Double) As Double

Area = dblA

End Property

Insert Code in a Standard Code Module:

Sub clsRectangleRun()
‘This procedure instantiates an instance of a class, sets and calls class properties, passing multiple arguments to Property Let procedure:

Dim l As Double
Dim w As Double

Dim rect As New clsRectangle

l = InputBox(«Enter Length of rectangle»)
w = InputBox(«Enter Width of rectangle»)

‘setting the property value — passes this data to the ar variable in the Area property:
rect.Area(l, w) = l * w

‘accessing the Area property:
a = rect.Area(l, w)

MsgBox «Area of Rectangle with length » & l & «, width » & w & «, is » & a

End Sub

——————————————————————————————————————

Example 3 — Create Read-Only Class Property with only the PropertyGet_EndProperty block. For live code, click to download excel file.

Insert Code in Class Module named clsRectArea:

‘Example — Create Read-Only Class Property with only the PropertyGet_EndProperty block.
Private dRectL As Double
Private dRectW As Double

Public Property Let Length(l As Double)

dRectL = l

End Property

Public Property Get Length() As Double

Length = dRectL

End Property

Public Property Let Width(w As Double)

dRectW = w

End Property

Public Property Get Width() As Double

Width = dRectW

End Property

Public Property Get rArea() As Double
‘Read-Only property with only the PropertyGet_EndProperty block and no PropertyLet_EndProperty (or PropertySet_EndProperty) block.

rArea = Length * Width

End Property

Insert Code in a Standard Code Module:

Sub clsRectAreaRun()
‘This procedure instantiates an instance of a class, sets and calls class properties.

Dim a As Double
Dim b As Double

Dim areaRect As New clsRectArea

a = InputBox(«Enter Length of rectangle»)
b = InputBox(«Enter Width of rectangle»)

areaRect.Length = a
areaRect.Width = b

MsgBox areaRect.rArea

End Sub

————————————————————————————————————

Example 4 — Using Property Set statement to set a reference to an object.

A Property Set procedure is used to create object properties which are actually pointers to other objects. Refer Images 2a, 2b & 2c. For live code, click to download excel file.

Insert Code in Class Module named clsCar:

‘Example — Using Property Set statement to set a reference to an object. A Property Set procedure is used to create object properties which are actually pointers to other objects.

‘declare a private variable (ie. varCar) to store a reference to the clsMotorCars object:
Private varCar As clsMotorCars

Public Property Set Car(objCar As clsMotorCars)
‘The Property Set statement sets a reference to an object, and assigns Car to an object.

‘create an object variable (ie. varCar) and point it to the clsMotorCars object passed to the procedure:
Set varCar = objCar

End Property

Public Property Get Car() As clsMotorCars

‘return the object variable (ie. varCar) created by the Property Set procedure:
Set Car = varCar

End Property

Insert Code in Class Module named clsMotorCars:

‘Create Class Properties by using Property Procedures:
Private strColor As String
Private strName As String
Private dMG As Double

Property Let Color(clr As String)

strColor = clr

End Property

Property Get Color() As String

Color = strColor

End Property

Property Let Name(nm As String)

strName = nm

End Property

Property Get Name() As String

Name = strName

End Property

Property Let Mileage(milesGallon As Double)

dMG = milesGallon

End Property

Property Get Mileage() As Double

Mileage = dMG

End Property

Function FuelBudget(FuelCost As Double, Distance As Double) As Double

FuelBudget = (Distance / Mileage) * FuelCost

End Function

Insert Code in a Standard Code Module:

Sub propSetCars()
‘Using Property Set statement to set a reference to an object. A Property Set procedure is used to create object properties which are actually pointers to other objects.

Dim dDist As Double
Dim dCost As Double

‘instantiate as a clsCar object ie. create a new instance of the clsCar object. A new object reference is created by using the New keyword.
Dim ownCar As clsCar
Set ownCar = New clsCar

‘Car has been instantiated as a clsMotorCars object (note that Car is a property of the ownCar object). See below how to access the properties & methods of clsMotorCars object:
Set ownCar.Car = New clsMotorCars

‘enter property values:
ownCar.Car.Color = «Yellow»
ownCar.Car.Name = «Ford»
ownCar.Car.Mileage = 50
dDist = InputBox(«Enter Distance in miles, covered by car in a month»)
dCost = InputBox(«Enter Cost of Fuel per gallon»)

‘return values from properties & methods of clsMotorCars object:
MsgBox «Car Color is » & ownCar.Car.Color
MsgBox «Car Model is » & ownCar.Car.Name
MsgBox «Gives a Mileage of » & ownCar.Car.Mileage & » miles per gallon»
‘call the FuelBudget function:
MsgBox «$» & ownCar.Car.FuelBudget(dDist, dCost) & » is the monthly cost of fuel»

End Sub

————————————————————————————————————————

Example 5 — Using Property Set statement to set a reference to a Range object. For live code, click to download excel file.

Insert Code in Class Module named clsSetRange:

‘Example — Using Property Set statement to set a reference to a Range object:
Private intColor As Integer
Private strName As String
‘declare a private variable (ie. rngV) to store a reference to the Range object:
Private rngV As Range

Public Property Set activeRange(oRng As Range)

‘create an object variable (ie. rngV) and point it to the Range object passed to the procedure:

Set rngV = oRng

End Property

Public Property Get activeRange() As Range

Set activeRange = rngV

End Property

Property Let Name(nam As String)

strName = nam

End Property

Property Get Name() As String

Name = strName

End Property

Property Let Color(clr As Integer)

intColor = clr

End Property

Property Get Color() As Integer

Color = intColor

End Property

Sub methodColor()

activeRange.Interior.ColorIndex = Color

End Sub

Insert Code in a Standard Code Module:

Sub clsSetRangeRun()
‘Example — Using Property Set statement to set a reference to a Range object.:

‘Instantiate as a clsRange object ie. create a new instance of the clsSetRange object. A new object reference is created by using the New keyword.
Dim rngActive As clsSetRange
Set rngActive = New clsSetRange

‘Set activeRange property (which is an object property) of clsSetRange object to ActiveCell, and pass this data to the oRng variable in the activeRange property:
Set rngActive.activeRange = ActiveCell

‘enter ColorIndex, value 1 to 56:
‘3 for red, 4 for green & 5 for blue, ….
rngActive.Color = 5

If rngActive.Color < 1 Or rngActive.Color > 56 Then

MsgBox «Error! Enter a value for ColorIndex between 1 and 56»

Exit Sub

End If

‘call sub-procedure named methodColor:
rngActive.methodColor

MsgBox «Interior color, ColorIndex » & rngActive.Color & «, entered in cell » & rngActive.activeRange.Address

End Sub


Custom Class Events

You can create your own class events also. Events are actions performed, or occurences, which trigger a VBA macro. A VBA code is triggered when an event occurs such as, clicking on a button, opening the workbook, selecting a cell or changing cell selection in a worksheet, and so on. Excel also has its own Event Procedures which are triggered by a predefined event and are installed within Excel having a standard & predetermined name viz. like the Worksheet change procedure is installed with the worksheet as «Private Sub Worksheet_Change(ByVal Target As Range)». When content of a worksheet cell changes, VBA calls the Worksheet_Change event procedure and runs the code it contains. Here we explain how to create your own custom events in a class.

Define a Custom Event:

The first step is to declare the event in the declaration section of the class. Use the Event keyword to define a custom event in a class module. It can have any number of arguments, and the event declaration should be Public to make it visible outside the object module. Note that you can declare and raise Events only within object modules (viz. ThisWorkbook module, Sheet modules — worksheets and chart sheets, UserForm modules and Class modules), and not from a standard code module.

Raise an Event:

After declaring an event, use a RaiseEvent Statement to trigger the declared event. The event procedure runs when an event is raised or triggered. The event is raised in a public procedure within the class module where it is declared, using the Event keyword. The RaiseEvent statement passes values for the event’s arguments, which also get passed to the event procedure that runs on raising the event.

External Code to Raise the Event:

However we need an external code to call the public procedure in the class module, which raises the event. This external code determines when the event will be raised by which the event procedure runs.

Create an Event Procedure:

Use the WithEvents keyword to declare an object variable of the custom class (in which the custom event is defined) type. By declaring this object variable, the instance of the custom class which this object variable points to will respond to the event by adding the object to the events list in the Code window. Only variables declared at module level can be used with the WithEvents keyword. Also variables can be declared using the WithEvents keyword only in object modules and not a standard code module. After the object variable declaration, the event procedure stub can be created similar to standard vba procedures — the object variable will be displayed in the Object drop-down list and all its events are listed in the Procedure drop-down list.

Examples

Example 6 — Create a Custom Event:- use a Worksheet_Change procedure to trigger the custom event. Refer Images 3a & 3b. For live code, click to download excel file.

Insert Code in Class Module named clsRange:

‘Example of Creating a Custom Event — use a Worksheet_Change procedure to trigger the custom event:
Private rngVar As Range
Private intColor As Integer
Private strName As String
‘Event declaration: Use the Event keyword to define a custom event (ie. CellSelect event) in a class module (ie. clsRange class). It can have any number of arguments, and the event declaration should be Public to make it visible outside the object module.
Public Event CellSelect(cell As Range)

Public Property Set selectedRange(objRng As Range)

Set rngVar = objRng
‘Trigger the event: the RaiseEvent statement executes & raises the CellSelect event and passes values for its arguments. Note that using the RaiseEvent keyword is similar to using the Call keyword used to call & execute a procedure in vba.
RaiseEvent CellSelect(rngVar)

End Property

Public Property Get selectedRange() As Range

Set selectedRange = rngVar

End Property

Property Let Name(nm As String)

strName = nm

End Property

Property Get Name() As String

Name = strName

End Property

Property Let Color(clr As Integer)

intColor = clr

End Property

Property Get Color() As Integer

Color = intColor

End Property

Sub methodColor()

selectedRange.Interior.ColorIndex = Color

End Sub

Insert Code in a Worksheet (sheet named ‘Sheet1’) Module:

‘Use the WithEvents keyword to declare an object variable (rng) of type clsRange. By declaring this object variable, the instance of the clsRange class which this object variable points to will respond to the event by adding the object to the events list in the Code window. Only variables declared at module level can be used with the WithEvents keyword.
‘After the variable declaration, the event procedure stub can be created similar to standard vba procedures — rng will be displayed in the Object drop-down list and all its events are listed in the Procedure drop-down list.
Private WithEvents rng As clsRange

Private Sub rng_CellSelect(cell As Range)
‘this is an event procedure, consisting of a set of codes, which runs on raising the CellSelect event.

‘enter ColorIndex, value 1 to 56:
‘3 for red, 4 for green & 5 for blue, ….
rng.Color = 4

If rng.Color < 1 Or rng.Color > 56 Then

MsgBox «Error! Enter a value for ColorIndex between 1 and 56»

Exit Sub

End If

rng.Name = «FirstCell»

‘call sub-procedure called methodColor:
rng.methodColor

‘note that rng.selectedRange & rng.Color values have been assigned, because they will lose values while executing below code:
Dim i As Integer
i = rng.Color

rng.selectedRange.Select
Selection.Offset(0, 1).Value = «Cell Name: « & rng.Name
Selection.Offset(0, 2).Value = «Cell Address: « & Selection.Address
Selection.Offset(0, 3).Value = «Cell Interior ColorIndex: « & i
Selection.Offset(0, 4).Value = «Cell Content: « & Selection.Value

End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
‘this worksheet change procedure calls the selectedRange public procedure of the clsRange object.

On Error GoTo ErrorHandler  ‘Enable error-handling routine for any run-time error

‘Instantiate as a clsRange object ie. create a new instance of the clsRange object. A new object reference is created by using the New keyword.
Set rng = New clsRange

‘CHANGE CONTENTS OF CELL A1 IN SHEET1 TO RUN THIS PROCEDURE:
‘Set selectedRange property (which is an object property) of clsRange object to ActiveCell, and pass this data to the objRng variable in the selectedRange property:
If Target.Address = Range(«A1»).Address Then

Set rng.selectedRange = Target

Else

Exit Sub

End If

ErrorHandler:
  Application.EnableEvents = True  ‘EnableEvents is changed back to True on any error

End Sub

————————————————————————————————————————

Example 7 — Create a Custom Event:- initialization of the UserForm triggers the custom event. Refer Images 4a, 4b & 4c. For live code, click to download excel file.

Insert Code in Class Module named clsTextBox:

‘Example of Creating a Custom Event — initialization of the UserForm triggers the custom event:
Private tb As MSForms.TextBox
Private strSeq As String
‘Event declaration: Use the Event keyword to define a custom event (ie. eTxtBx event) in a class module (ie. clsTextBox class). It can have any number of arguments, and the event declaration should be Public to make it visible outside the object module.
Public Event eTxtBx(objTxtBx As MSForms.TextBox)

Public Property Set setTxtBx(objTxtBx As MSForms.TextBox)

Set tb = objTxtBx
‘Trigger the event: the RaiseEvent statement executes & raises the eTxtBx event and passes values (TextBox object) for its arguments (objTxtBx). Note that using the RaiseEvent keyword is similar to using the Call keyword used to call & execute a procedure in vba.
RaiseEvent eTxtBx(tb)

End Property

Public Property Get setTxtBx() As MSForms.TextBox

Set setTxtBx = tb

End Property

Property Let Sequence(tbSeq As String)

strSeq = tbSeq

End Property

Property Get Sequence() As String

Sequence = strSeq

End Property

Insert a UserForm, insert 2 textBox (TextBox1 & TextBox2) and a CommandButton (CommandButton1) within the Form. Insert Code in the UserForm Module:

‘Use the WithEvents keyword to declare an object variable (tx) of type clsTextBox. By declaring this object variable, the instance of the clsTextBox class which this object variable points to will respond to the event by adding the object to the events list in the Code window. Only variables declared at module level can be used with the WithEvents keyword.
‘After the variable declaration, the event procedure stub can be created similar to standard vba procedures — tx will be displayed in the Object drop-down list and all its events are listed in the Procedure drop-down list.
Private WithEvents tx As clsTextBox
Private sq1 As String, sq2 As String

Private Sub CommandButton1_Click()
‘using the excel built-in event Click: procedure runs on clicking the command button:

‘copying the contents of TextBox1 to all other TextBoxes and changing the BackColor of these TextBoxes to red:
Dim objControl As Control
For Each objControl In Me.Controls

If TypeName(objControl) = «TextBox» Then

If Not objControl.Name = «TextBox1» Then

objControl.Value = «copied: « & tx.setTxtBx.Value

objControl.BackColor = vbRed

End If

End If

Next

MsgBox «text copied from the » & sq1 & » to the » & sq2

   

End Sub

Private Sub TextBox1_Change()
‘using the excel built-in event Change: procedure runs on change in TextBox contents:

If tx.setTxtBx.Value = «» Then

tx.setTxtBx.BackColor = vbYellow

Else

tx.setTxtBx.BackColor = vbGreen

End If

End Sub

Private Sub tx_eTxtBx(objTxtBx As MSForms.TextBox)
‘this is an event procedure, consisting of a set of codes, which runs on raising the eTxtBx event.

tx.setTxtBx.BackColor = vbYellow

With Me.TextBox1

tx.Sequence = «First TextBox»

sq1 = tx.Sequence

End With

    With Me.TextBox2

tx.Sequence = «Second TextBox»

sq2 = tx.Sequence

End With

End Sub

Private Sub UserForm_Initialize()
‘initialization of the userform calls the setTxtBx public procedure of the clsTextBox object.

‘Instantiate as a clsTextBox object ie. create a new instance of the clsTextBox object. A new object reference is created by using the New keyword.
Set tx = New clsTextBox

‘Set setTxtBx object property of clsTextBox object, and pass the TextBox object (Me.TextBox1) to the objTxtBx variable in the setTxtBx property:
Set tx.setTxtBx = Me.TextBox1

   
End Sub

—————————————————————————————————————

Example 8 — Create a Custom Event:- use the WithEvents keyword, within the class module, to declare an object variable (Initialize UserForm to start).

For live code, click to download excel file.

Insert Code in Class Module named clsComboBox:

‘Example of Creating a Custom Event — use the WithEvents keyword, within the class module, to declare an object variable:
‘Use the WithEvents keyword to declare an object variable (cBox) of type MSForms.ComboBox. By declaring this object variable here, the excel built-in events associated with this object variable will respond, by adding the object to the events list in the Code window.
Public WithEvents cBox As MSForms.ComboBox

Public Sub setComboBox(objCbx As MSForms.ComboBox)
‘On userform initialization, the ComboBox object (objCbx) is passed to this procedure. This procedure is declared public to make it accessible from outside the class module.

‘ComboBox object (objCbx) is assigned to the object variable (cBox):
Set cBox = objCbx

End Sub

Public Sub cBox_AddItem(strItem As String, Cancel As Boolean)
‘This procedure is declared public to make it accessible from outside the class module. Clicking the command button passes the value for strItem argument, and runs this procedure.

‘adds item to ComboBox list, unless AddItem event is cancelled:
If Cancel = False Then

cBox.AddItem strItem

End If

‘changes BackColor of ComboBox after adding an item:
If strItem <> «» Then
cBox.BackColor = vbGreen
End If

End Sub

Private Sub cBox_Change()
‘using the excel built-in event of Change, this procedure runs when the ComboBox text changes.

‘if ComboBox is blank, its BackColor will change to white:
If cBox.Value = «» Then

cBox.BackColor = vbWhite

End If

End Sub

Insert a UserForm, insert a ComboBox (ComboBox1) and a CommandButton (CommandButton1) within the Form. Insert Code in the UserForm Module:

‘instantiate an instance (cB) of the class object (clsComboBox):
Private cB As New clsComboBox

Private Sub CommandButton1_Click()

‘enter item in the text area of the ComboBox, which you want to add in ComboBox:
Dim strTxt As String
strTxt = cB.cBox.Text

Dim Cancel As Boolean

c = MsgBox(«Do you confirm adding the item in ComboBox?», vbYesNo)
If c = vbNo Then

Cancel = True

End If

‘call the class method cB.cBox_AddItem and pass value and Boolean variable:
Call cB.cBox_AddItem(strTxt, Cancel)

End Sub

Private Sub UserForm_Initialize()

‘call the class method (setComboBox) and pass ComboBox object for its argument’s (objCbx) value:
cB.setComboBox Me.ComboBox1

End Sub

What is a Class in VBA?

A class is a blueprint for an object to be created. A class itself does nothing but using classes you can create multiple identical objects that can perform operations or can be used as a data resource.

In real life, the model (design and functionalities) of a car is a class and the car itself is an object of that class. In the class, we define what the car has in it and what it can do. For example, a car has 4 wheels, 5 gears, steering wheel, etc. These are attributes/properties. We also define what a car can do, like moving forward, backward, turn, etc. These are functions of the car class. A car object created using car class, will have all these properties. If you define a car that has 5 wheels than a car created using this class will have 5 wheels. You get the point.

Enough of theory, now let’s see how you can use a class module in VBA.

Using Excel VBA class module

While working in VBA, you must have used Range(«A1»).select. The Range is pre-defined class in VBA. The select is one of the functions of Range class that select the specified range. Similarly, Debug is class in VBA and print and assert are it’s methods. Worksheets,  Workbooks, Range, etc. all are VBA classes that we use in our subs.

Create your own class

First, we need to add a class  module in VBA

Press ALT+F11 key combination to open excel VBA editor.

    • Right-click on project explorer. Move the cursor to Insert—> Class module. Click on it.  The same thing can be done from the Insert menu.

    • The class will be added to the folder «Class module». The default name is like class1, class2, and so on. You can change the class name from the property window. Let’s name our class «Welcome».

  • Now let’s create add some attributes to our class. Since I want these attributes to be available to the public, I have use accessibility operator public.
    Public name As String
    Public var1 As Integer
    Public var2 As Integer
    
  • Now let’s add a function to this class. I want a function that says Hi! to the user. To do so add a sub and name it sayHiTo.
    Sub sayHiTo(user As String)
        name = user
        MsgBox ("Hi! " & name)
    End Sub
    
  • Now let’s use class in a module. Insert a new module if you don’t have any. Write a sub. I have named my sub Test.
    Sub test()
     Dim wc As New Welcome 'Declared and initialized Welcome object
     wc.sayHiTo ("Jack") 'used sayHiTo method of Welcome Object.
    End Sub
    
  • Run this sub Test using F5 key. It will prompt «Hi! Jack» on excel workbook.

How does it work?

In sub Test, we have created is an object «wc» of Welcome class. An object is created in VBA in two methods. we run the code, Test sub creates an object wc of the Welcome class. This object has all the properties of the Welcome class. We use the sayHiTo method of the Welcome class to say hi to the user.

Object Creation in Excel VBA

    1. Instant creation

In Instant creation, we create an object while declaring the object with the «new» key. In our example above, we have used instant creation.

Dim wc As New Welcome

2. Delayed creation
In delayed creation, we first declare the object only. We don’t use the «new» keyword. In order to use the object, we need to initialize it with the «new» keyword.

Sub test()
 Dim wc As Welcome
 'wc.sayHiTo ("Jack") 'generates error since wc is not initialised yet
'initialising object
Set wc = New Welcome
wc.sayHiTo ("Cory") 'this will work.
End Sub

Accessing Variables of a Class

In the above examples, we have used public variables for class but it is wrong to practice. We should avoid using public variables in a class. Now the question is how would we access variables of the class. Earlier, we used subroutine to access name but VBA classes provide properties that are used to systematically update and retrieve private variable values of the class. The properties are more elegant than sub or function for updating and accessing private variables. Let’s see how.

Syntax of class property

Private name As String
Private var1 As Integer
Private var2 As Integer
Property Let MyName(nm As String)
name = nm
End Property

Property Get MyName() As String
MyName = name
End Property

Let’s use them in a module.

Sub test()
 'creating class object
 Dim wc As New Welcome
 Dim wc1 As New Welcome
 
 'using properties
 wc.MyName = "Exceltip.com"
 wc1.MyName = "ExcelForum.com"
 
 Debug.Print wc.MyName
 Debug.Print wc1.MyName
 
 End Sub

When you will run this test sub, you will get two names printed for two objects of the «Welcome» class.

How properties are different from sub and functions

In the above example, notice that we have used MyName property as a variable. We initialized the value of «Name» variable just by writing wc.MyName=»assdf». This line of command called the property called Property Get MyName() As String. We didn’t pass any value in parenthesis as we did in the beginning.

Similarly, to print the values of «Name» variable we used command Debug.Print wc.MyName. Isn’t it as simple as normal variable initialization? The only difference is that you can do a whole lot in the property segment. You put data validation, calculation, communication, etc. and user will only see the result.

Another difference is that we can use same name of the property to let and get part. This makes it easier and less confusing.

So yeah guys, this was a simple example of a class module in Excel VBA. This is just the tip of the iceberg, there’s a lot of juice in this topic that we will explore in later articles. We will explore each of them one by one in the easiest way possible. I hope I was explanatory enough to make you understand this. If you have any doubts regarding this topic or any other excel VBA topic, mention it in the comments section below.

Related Articles:

Import a module from a file using VBA in Microsoft Excel | Learn how to import entire module from another file using VBA.

Create a new module using VBA in Microsoft Excel | You can use a module to create another model in VBA. This can help you minimize the additional overhead work.

Add a procedure to a module using VBA in Microsoft Excel | To add procedures to modules automatically use this VBA code.

Popular Articles:

50 Excel Shortcuts to Increase Your Productivity | Get faster at your task. These 50 shortcuts will make you work even faster on Excel.

The VLOOKUP Function in Excel | This is one of the most used and popular functions of excel that is used to lookup value from different ranges and sheets. 

COUNTIF in Excel 2016 | Count values with conditions using this amazing function. You don’t need filter your data to count specific value. Countif function is essential to prepare your dashboard.

How to Use SUMIF Function in Excel | This is another dashboard essential function. This helps you sum up values on specific conditions.

Понравилась статья? Поделить с друзьями:
  • Vba for excel activesheet
  • Vba for excel 2016 pdf
  • Vba for excel 2013
  • Vba for excel 2010 pdf
  • Vba for excel 2003