Создание пользовательских типов данных в VBA Excel. Оператор Type, его описание и параметры. Создание массива «одномерных массивов» с пользовательскими данными.
Определение пользовательских типов данных
Пользовательский тип данных в VBA Excel представляет из себя набор элементов, каждому из которых пользователем присваивается свой тип данных. Другими словами, пользовательский тип данных — это набор данных разного типа, который может быть присвоен одной переменной.
Если простую переменную (не массив) объявить с пользовательским типом данных, она будет представлять из себя «одномерный массив»* с элементами разных типов данных, определенных пользователем.
Если с пользовательским типом данных объявить переменную массива, она будет представлять из себя массив «одномерных массивов»* пользовательских данных.
* Выражение «одномерный массив» взято в кавычки, так как фактически это не массив, а набор пользовательских данных, но для практического применения это не имеет значения.
Синтаксис оператора Type
Type <strong>Name</strong> <strong>Element</strong>_1 as <strong>Tip</strong> <strong>Element</strong>_2 as <strong>Tip</strong> <strong>Element</strong>_3 as <strong>Tip</strong> ———————— <strong>Element</strong>_n as <strong>Tip</strong> End Type |
Пользовательский тип данных в VBA Excel может быть объявлен с ключевым словом Public или Private, которое явно укажет зону его видимости. Если ключевое слово опущено, конструкция с оператором Type по умолчанию объявляется с зоной видимости Public.
Параметры оператора Type
Параметр | Описание |
---|---|
Name | Имя пользовательского типа данных, по которому этот тип данных будет присваиваться переменным. |
Element | Наименование отдельного элемента пользовательского типа данных. |
Tip | Тип данных отдельного элемента (стандартный тип VBA). |
Применение пользовательских типов данных
Применение пользовательских типов данных в VBA Excel рассмотрим на примере домиков для животных.
Объявление пользовательского типа данных
Объявление пользовательского типа данных (конструкция с оператором Type) размещается в самом начале модуля в разделе Declarations.
Пример 1
Type Domik naimenovaniye As String obyem_m3 As Single material As String kolichestvo As Long End Type |
В этом примере:
- Domik — имя, по которому этот тип данных будет присваиваться переменным;
- naimenovaniye — наименование домика для животных;
- obyem_m3 — объем домика в куб. метрах;
- material — материал, из которого сделан домик;
- kolichestvo — количество домиков на складе.
Заполнение данными массива
Обычно в качестве контейнеров для пользовательских типов данных в VBA Excel используются массивы. В простую переменную можно уместить только один набор пользовательских данных, а в массив — сколько нужно. В следующем примере мы заполним трехэлементный массив тремя наборами пользовательских данных.
Если представить набор пользовательских данных как «одномерный массив», то таким образом мы создадим массив «одномерных массивов» с пользовательскими данными.
Пример 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Sub Primer2() ‘Объявляем трехэлементный массив ‘с пользовательским типом данных Dim a(1 To 3) As Domik ‘Заполняем первый элемент массива a(1).naimenovaniye = «Скворечник» a(1).obyem_m3 = 0.02 a(1).material = «сосна» a(1).kolichestvo = 15 ‘Заполняем второй элемент массива a(2).naimenovaniye = «Собачья будка» a(2).obyem_m3 = 0.8 a(2).material = «береза» a(2).kolichestvo = 5 ‘Заполняем третий элемент массива a(3).naimenovaniye = «Клетка кролика» a(3).obyem_m3 = 0.4 a(3).material = «металл» a(3).kolichestvo = 6 End Sub |
Обращение к пользовательским данным в массиве
Для обращения в коде VBA Excel к пользовательским данным в массиве используется та же конструкция, что и при записи: указывается элемент массива и через точку наименование элемента пользовательских данных.
Пример 3
‘Считываем информацию из массива Dim b As Variant b = a(2).naimenovaniye MsgBox b b = a(3).obyem_m3 MsgBox b b = «Мы продаем следующие товары: « _ & a(1).naimenovaniye & «, « _ & a(2).naimenovaniye & » и « _ & a(3).naimenovaniye MsgBox b |
Для наглядной демонстрации вставьте строки кода Примера 3 перед строкой End Sub Примера 2.
User-defined types are composite data types containing one or more variables of other data types. User-defined types can be used to return multiple values from a function, pass a struct to a DLL procedure, improve efficiency when used in place of a class, and to make code more organized and readable.
User-Defined Types Vs Classes
Although user-defined types can sometimes take the place of using a class, they have several key differences from classes:
- Classes can define methods, user-defined types cannot
- Classes can be instantiated, user-defined types cannot
- Classes require their own dedicated modules, user-defined types do not
- Class instances can be added to a Collection object, user-defined types cannot
- User-defined types are more efficient than classes
Although there are some limitations with user-defined types when compared to classes, user-defined types can be a more efficient and light-weight alternative when all that is needed is a structure containing data fields. User-defined types do not have the overhead of a dedicated module and can help keep the size of a VBA project small when defining a number of data structures. Using a user-defined type with an array is more efficient than using a user-defined class with a Collection object. If a data structure does not need methods or instances then one should consider using a user-defined type instead of a class.
Declaring User-Defined Types
User-defined types are declared using the Type statement. There are a number of rules when declaring user-defined types:
- Must be declared above all procedures in a module.
- Must have at least one member.
- When Public or Private is not specified, user-defined types are Public by default.
- Public types cannot be declared in class modules.
- Private types in a class module cannot be used as parameters for public procedures.
- Private types in a class cannot be return types for public procedures of the class.
- Private types in class modules cannot be public member variables of the class.
- Types cannot contain a member that is declared as its own type. No circular dependencies.
- When a type contains another type as a member, the member’s type must be declared first.
'Standard Module
Option Explicit
Public Type TExample1
Message As String
Number As Double
End Type
Public Type TExample2
Message As String
T1 As TExample1
End Type
Public Sub Example()
Dim T1 As TExample1
T1.Message = "MT1 Message"
T1.Number = 3.5
Dim T2 As TExample2
T2.Message = "T2 Message"
T2.T1 = T1
Debug.Print T2.Message, T2.T1.Message, T2.T1.Number
End Sub
In a standard code module, Private user-defined types can be accessed publicly as a member variable of a Public user-defined type.
'Standard Module: Module1
Option Explicit
Private Type TPrivate
Message As String
Number As Double
End Type
Public Type TPublic
Message As String
Priv As TPrivate
End Type
'Standard Module: Module2
Option Explicit
Public Sub Example()
Dim T As TPublic
T.Priv.Message = "Hello, World!"
T.Priv.Number = 3.5
Debug.Print T.Priv.Message
Debug.Print T.Priv.Number
End Sub
Multiple Return Values
There are times when it may be necessary for a function to return more than one value. A user-defined type can be used to return multiple values from a function.
Option Explicit
Public Type TExample
Message As String
Number As Double
End Type
Public Function GetData() As TExample
GetData.Message = "Hello, World!"
GetData.Number = 3.5
End Function
Public Sub Example()
Dim E As TExample
E = GetData()
Debug.Print E.Message
Debug.Print E.Number
End Sub
User-Defined Type Parameter
User-defined types can be used as parameters of procedures.
Option Explicit
Public Type TExample
Message As String
Number As Double
Bool As Boolean
End Type
Public Sub PrintTExample(T As TExample)
Debug.Print T.Message, T.Number, T.Bool
End Sub
Public Sub Example()
Dim T As TExample
T.Message = "Hello, World!"
T.Number = 3.5
T.Bool = True
PrintTExample T
End Sub
Pass Struct To DLL Procedure
User-defined types can be used to pass or return structs to and from DLL procedures.
// C++ 64-bit DLL
#define DLLExport __declspec(dllexport)
struct RECTANGLE {
int s1;
int s2;
};
extern "C" {
DLLExport int __stdcall CppRectangleArea(RECTANGLE* rect) {
return rect->s1 * rect->s2;
}
}
Option Explicit
Public Type TRectangle
S1 As Long
S2 As Long
End Type
Public Declare PtrSafe Function CppRectangleArea _
Lib "C:ExampleDLL.dll" (ByRef Rect As TRectangle) As Long
Public Sub Example()
Dim Rect As TRectangle
Rect.S1 = 10
Rect.S2 = 20
Dim Area As Long
Area = CppRectangleArea(Rect)
Debug.Print Area
End Sub
Arrays and User-Defined Types
Using an array with a user-defined type is an excellent way of storing tabular data in a type-safe, meaningful, and memory efficient way. Using a user-defined type array instead of a multi-dimensional array of type Variant provides the correct explicit data type for each field, a clear meaning for what each field represents, and saves memory when compared to using Variants. Consider the example below using a multi-dimensional array of type Variant and then again using an array with a user-defined type.
Note: Arrays of user-defined types cannot be iterated over using a For Each loop.
Option Explicit
Public Sub Example()
Dim PersonInfoArray(0 To 2, 0 To 2) As Variant
PersonInfoArray(0, 0) = "Bill"
PersonInfoArray(0, 1) = #01/01/1992#
PersonInfoArray(0, 2) = "New York"
PersonInfoArray(1, 0) = "Bob"
PersonInfoArray(1, 1) = #01/01/1993#
PersonInfoArray(1, 2) = "Chicago"
PersonInfoArray(2, 0) = "Ben"
PersonInfoArray(2, 1) = #01/01/1994#
PersonInfoArray(2, 2) = "Los Angeles"
Dim i As Long
For i = LBound(PersonInfoArray, 1) To UBound(PersonInfoArray, 1)
Debug.Print PersonInfoArray(i, 0), PersonInfoArray(i, 1), PersonInfoArray(i, 2)
Next i
End Sub
Option Explicit
Public Type TPersonInfo
FirstName As String
BirthDate As Date
HomeTown As String
End Type
Public Sub Example()
Dim PersonInfoArray(0 To 2) As TPersonInfo
With PersonInfoArray(0)
.FirstName = "Bill"
.BirthDate = #01/01/1992#
.HomeTown = "New York"
End With
With PersonInfoArray(1)
.FirstName = "Bob"
.BirthDate = #01/01/1993#
.HomeTown = "Chicago"
End With
With PersonInfoArray(2)
.FirstName = "Ben"
.BirthDate = #01/01/1994#
.HomeTown = "Los Angeles"
End With
Dim i As Long
For i = LBound(PersonInfoArray) To UBound(PersonInfoArray)
With PersonInfoArray(i)
Debug.Print .FirstName, .BirthDate, .HomeTown
End With
Next i
End Sub
LSet
LSet can be used with User-Defined Types to assign the values in one type with the values of another type.
Note: It is not recommended to use LSet with user-defined types because there is no guarantee that the members of both types are the same.
Option Explicit
Public Type TExample1
Message As String * 15
Number As Double
End Type
Public Type TExample2
Message As String * 15
Number As Double
End Type
Public Sub Example()
Dim T1 As TExample1
T1.Message = "Hello, World!"
T1.Number = 3.5
Dim T2 As TExample2
LSet T2 = T1
Debug.Print T2.Message
Debug.Print T2.Number
End Sub
Option Explicit
'''VBA does not ensure that user-defined types match
Public Type TExample1
Message As String * 15
Number As Double
End Type
Public Type TExample2
Number As Long
Message As String * 15
End Type
Public Sub Example()
Dim T1 As TExample1
T1.Message = "Hello, World!"
T1.Number = 3.5
Dim T2 As TExample2
LSet T2 = T1
Debug.Print T2.Number 'Prints: '6619208
Debug.Print T2.Message 'Prints: 'llo, World!
End Sub
-
04-25-2017, 07:11 PM
#1
Forum Contributor
how return an array of user defined datatype
Question How return an array of User defined Types
Context of question:
Within one module associated with a single workbook
I have defined a user data type:
Type FieldData
ID As Integer
Elevation As Double
DataType As String * 2
End Typeoutside of several subroutines written in the code section
I wrote a function which I would like to return an array of the above data typeIF I were to write a function which returned just one element of my user defined data type I would have no
problem writing the function. Function Boo (wrkshtPtr as worksheet, something as integer, etc) as FieldDataBUT if I wanted to return an array of FieldData, I have no idea how to write the function returning an array of
Field Data
ie: Function Boo (WrkShtPtr as worksheet, something as integer, etc) Array as FieldData
-
04-25-2017, 07:13 PM
#2
Re: how return an array of user defined datatype
Please use CODE tags when posting code.
Entia non sunt multiplicanda sine necessitate
-
04-25-2017, 07:32 PM
#3
Forum Contributor
Re: how return an array of user defined datatype
SHG,
Thank you for replying.
Please help me understand your answer.
the term «Array» as used in your example…..is it a keyword that has special meaning in VBA or is it an arbitrary term
and the () after FieldData is the clue to VBA that «Array» is an array?Thank you for replying so quickly. Much appreciated.
bil
-
04-25-2017, 08:09 PM
#4
Re: how return an array of user defined datatype
That tells VBA that it’s an array, yes.
-
04-26-2017, 09:00 AM
#5
Forum Contributor
Re: how return an array of user defined datatype
shg,
I apologize….I still do not understand your answer. please be patient with me.
is this how the function would be written?
Function Boo (args) FieldDataArray() as FieldData
what is baffling for me is that normally i would write a function as:
function Boo (args) as datatype
but in your example, it seems as if i am writing more than datatype after Boo(args)please be patient with me.
bil
-
04-26-2017, 11:14 AM
#6
Re: how return an array of user defined datatype
No, it would be written as shown in post #2 (with the args detailed).
-
04-26-2017, 11:20 AM
#7
Re: how return an array of user defined datatype
Hi,
You would omit the Array keyword
the brackets on the end indicate that an array is to be returned.
Don
Please remember to mark your thread ‘Solved’ when appropriate.
-
04-26-2017, 11:48 AM
#8
Forum Contributor
Re: how return an array of user defined datatype
xlnitwit and shg……thank you so much for having spent so much time with my problem
I hope both of you have a wonderful day.
Bil
-
04-26-2017, 03:04 PM
#9
Re: how return an array of user defined datatype
My bad, missed that, sorry.
In my last week’s Blog post I elaborated on data types and their use in VBA.
Beyond using the readily available native data types we’re all familiar with, such as Integer, Date, String and Boolean, we can define our own, user-defined data type.
What is a User-Defined Data Type?
Simply put, a user-defined data type is a group of variables of native data types.
Here’s an example of grouping together several variables to define a new data type representing (or holding) information about a vehicle:
Type Vehicle
VIN as Long
Make as String
Model as String
Year as Integer
End Type
That’s it! As simple as that.
We can now dimension variables of type Vehicle:
Dim vehLeasedCar as Vehicle
We now have a kind of a hierarchy: a variable of type Vehicle containing sub-variables of different (native) types: Long, String and Integer in this example.
We can think of the sub-variables as properties of the Vehicle-type variable and use the “dot” to address each of these sub-variables. Let’s assign some values to our vehLeasedCar variable:
vehLeasedCar.VIN = 4656418
vehLeasedCar.Make = “Ford”
vehLeasedCar.Model = “Taurus”
vehLeasedCar.Year = 2001
In the same way, we can read the values of our variable (or its sub-variables). Let’s print out our vehicle’s model:
Debug.Print vehLeasedCar.Model
Why use User-Defined Data Types?
I can think of two main reasons to make use of user-defined data types:
- They are suitable for records arrangement in a readable format
- They are very efficient to process, even more than collections
Think of a process that needs to store and manipulate 5,000 vehicles.
One way would be to have a two-dimensional array store a table-like structure of the vehicles. This is valid (and you know how much I love arrays), and even performant. However, it would not be that clear by viewing the code what we are doing. What do you find more telling in your code: arrCars(i,j) or arrCars(i).Model?
Let’s define another data type to store information about an employee:
Private Type TEmployeeRecord
Name As String
DOB As Date
Age As Integer
City As String
Score As Integer
End Type
Consider how readable and self-explanatory the following Sub is, tasked with printing out all data of an employee, passed over as a TEmployeeRecord type variable:
Sub PrintEmployeeReport(employee As TEmployeeRecord)
With employee
Debug.Print .Name, .City, .DOB, .Age, .Score
End With
End Sub
Storing Many Records in an Array
Of course, storing a single record, as in the above examples, is not very helpful. We typically need to store many records of data in our program.
For this, we can combine our own defined data type (record structure) with a one-dimensional array.
To illustrate this in an example, let’s pick up a list of employees with some data on them from an Excel table and arrange it in an array of employees’ records. Our table look like this:
We first use a 2-dimensional array as an interim structure to quickly read the table from the Worksheet:
Dim arrEmployees() As Variant
arrEmployees = ThisWorkbook.Worksheets("Scores").Range("ScoresTable[#Data]").Value
Next, we loop our array and transfer each employee (“row”) in the array into a new, 1-dimentional array, holding employees’ records:
Dim employees(5) As TEmployeeRecord
Dim i As Integer
For i = LBound(arrEmployees, 1) To UBound(arrEmployees, 1)
With employees(i - 1)
.Name = arrEmployees(i, 1)
.DOB = arrEmployees(i, 2)
.Age = arrEmployees(i, 3)
.City = arrEmployees(i, 4)
.Score = arrEmployees(i, 5)
End With
Next i
With that, we have an efficient array of employees to work with.
We can now write a function to return the score of an employee, given a pointer to the array of employees we prepared and the employee name to look for.
Function GetScoreOfEmployee(strName As String, employees() As TEmployeeRecord) As Integer
Dim i As Integer
GetScoreOfEmployee = 0
For i = LBound(employees) To UBound(employees)
With employees(i)
If (.Name = strName) Then
GetScoreOfEmployee = .Score
Exit For
End If
End With
Next i
End Function
See how elegant and clear this function is? We’re looping the employees array, checking each employee name to match strName we’re looking for, returning his score upon a successful match.
Here’s how we can make use of the above function to ask the user for a name of an employee and get his score (we’ll store his score in the intScore variable). We’re making use of the employees array we have populated earlier with our employees:
Dim strName As String
Dim intScore As Integer
strName = InputBox("Name of employee:", "Query Employee Form")
intScore = GetScoreOfEmployee(strName, employees)
If (intScore = 0) Then
MsgBox "Employee not found", vbOKOnly + vbInformation, "Employee Error"
Else
MsgBox strName & "'s score: " & intScore, vbOKOnly + vbInformation, "Employee Score Result"
End If
By the way, if you are not familiar with the InputBox function, I have a detailed Blog post about it for you here. Similarly, the MsgBox function is explained here.
Unfortunately, Excel VBA doesn’t allow us to add user-defined type variables to a collection, therefore we’re missing out on a potentially very useful and efficient data structure. One can argue that if a collection is our best structure to maintain our records, we can implement our records as objects defined in a Class Module instead of a user-defined data type. Yes, I have a series of Blog posts about objects and Class Modules starting right here.
The above examples are featured in my flagship on-line course: Computer Programming with Excel VBA, in case they seemed familiar to you 😉.
Hey, a small request from me to you: please share this Blog post so that we can help more colleagues with Excel VBA.
In the previous article, we learned how to use the User Defined Types. User Defined Type refers to a named grouping of built-in data types. Today we will learn to create an Array of User Defined Types. We will learn how to use a UDT and store records from a Table into an Array of UDT.
What is an Array of User Defined Type?
A UDT is a collection of different built-in data type variables known as sub-variables. We need to instantiate a User Defined Type. We can create several user defined type variables by using an array. Each variable of type UDT would have its copy of sub-variables in the computer’s memory. An array of variables of UDT would correspond to several records and each record would correspond to a single element of an array.
Table of Contents
- What is an Array of User Defined Type?
- Syntax – UDT Array
- Type Declaration
- Creating an Array of User Defined Type
- Accessing Sub Vairbles of Array Elements
- Example – Store Values from Table into an Array of UDT
You can also download the practice workbook to follow along.
Syntax – UDT Array
Here were have defined the syntax to use an Array of User Defined Data Type.
Type Declaration
To create a User Defined Array type, we must declare a Type.
'syntax of type declaration
Type <UDT_name>
<var1> As <data_type>
<var2> As <data_type>
<var3> As <data_type>
.
.
.
<varN> As <data_type>
End Type
Here, <var1> or <varn> refer to the sub-variables of the Type.
Creating an Array of User Defined Type
Once we define a UDT, we can declare an array of variables to use it.
Dim <arr_name>([<lower_limit> to] <upper_limit) As <UDT_name>
The following points contain information to make an array of UDT.
- <arr_name> – This is the name of the UDT array.
- <lower_limit> – It is the index of the first array element. This is an optional argument and by default, its value is zero.
- <upper_limit> – This is the index of the last element of the User Defined Type array.
- <UDT_name> – This is the name of the UDT whose array we are about to create.
Accessing Sub Vairbles of Array Elements
The array <arr_name> would contain several elements. We can access the specific elements of an array using its index. Thereafter, we use the dot operator followed by the name of the sub-variable to access it.
<arr_name>(index).<varn>=expression
Example – Store Values from Table into an Array of UDT
In this example, you are going to learn how to store each record of the table in the elements of UDT Array. Follow these steps to learn.
- Prepare a student record data as follows.
- Select the range A1:E6 and press the Ctrl T keys to create a table from this data. Make sure you mark the checkbox for Table Headers.
- Now select the table and go to the Table Design tab on the ribbon. Change the name of the table to MyData.
- Press Alt and F11 keys to open the VBE. Go to the Insert tab and take a new module. Open the module and add the following code to the module.
'define the user defined type
Private Type Student
rno As Integer
name As String
class As String
marks As Byte
fname As String
End Type
Sub exDataFromTableIntoUDTArray()
'array to hold data from table
Dim myArray As Variant
'store the table records into myArray, sheet1 contains the table
myArray = ThisWorkbook.Worksheets("Sheet1").Range("MyData[#Data]").value
'declare an array of UDT
Dim student_arr(4) As Student
'store value from myArray into User Defined Type Array
For i = LBound(myArray, 1) To UBound(myArray, 1)
With student_arr(i - 1)
'accessing the sub variables and assigning values from myArray
.rno = myArray(i, 1)
.name = myArray(i, 2)
.class = myArray(i, 3)
.marks = myArray(i, 4)
.fname = myArray(i, 5)
End With
Next i
For i = 0 To UBound(student_arr, 1)
With student_arr(i)
'printing the values stored in sub variables of elements of student_arr UDT
MsgBox "Roll Number: " & .rno
MsgBox "Student's Name: " & .name
MsgBox "Class: " & .class
MsgBox "Marks: " & .marks
MsgBox "Father Name: " & .fname
End With
Next i
End Sub
Here myArr is variant type.
The UBOUND Function returns the upper limit of specified dimension of an array. It takes two arguments, the array name and the dimension number.
- Place the cursor in sub procedure exDataFromTableIntoUDTArray and press F8 key to execute this line by line or you can just run this sub procedure.
This brings us to an end.
Thank you for reading.
RELATED POSTS
-
For Each Loop VBA – Excel
-
Arrays in VBA – Excel
-
Multidimensional Arrays in VBA – Excel
-
Data Types of Variables in VBA
-
Collections in VBA – Create, Add, Remove Items
-
Variant Data Type in VBA Excel
Let’s say you are trying to create a school management system. Here, you will have different types of variables like student name, student roll no, class, etc. A school also has teachers, so there will be teacher names, teacher subject, classes, etc. Similarly, there will be many other objects like, librarian, classes, principle etc. Now having different variables for each entity in school will be messy work. How about creating a data type of student, teacher, classes, etc that stores values related to them. For this we can use defined data types of VBA.
In this article, we will learn how you can create your own data type in VBA. They are referred to as UDTs of VBA.
Defining a User Defined Data Type
To define a structure or UDTs in VBA we use Type___End Type block. Here’s the syntax of a UDT.
Type Tname_Of_Data_Type var1 as datatype 'datatype can be anything, int, array,or even UDT var2 as datatype Var3() as datatype --- VarN() as datatype End Type
So to define a custom data type in VBA we start with Type Keyword. Then we write the name of our custom data type. It is convention to use T before the Name of Data Type so that you can differentiate between vba collections and UDTs.
The DataTypes can be anything. And Integer, String, Variant, another UDT, Arrays, collections, anything.
To use your UDT in the program declare its variable like any other variable.
Sub UseUDT 'Declaring variable of user defined data type Dim myVar1 as Tname_Of_Data_Type Dim myVar2 as Tname_Of_Data_Type End Sub
Simple. Now to use the variables within this UDT we use dot operator. Use the name of the data type followed by a dot and name of variable within.
Sub UseUDT 'Declaring variable of user defined data type Dim myVar1 as Tname_Of_Data_Type Dim myVar2 as Tname_Of_Data_Type myVar1.var1="Abcd" myVar2.Var2="xyvz" End Sub
Enough of the theory, let’s jump into an example to see how it works.
Create A Student Variable that Stores Information Related to Student
So we have a task to create a user defined data type that stores information related to students.
A student has a first name, last name, roll number, date of birth, class, section, subjects.
So let’s create it.
'Created a Public Student Data Type Public Type Tstudent fName As String 'For First Name lName As String 'For Last Name rNo As Integer 'For Roll Number clss As string 'For Class section As String 'For Section Name subjects() As String 'For Subjects of student End Type 'Use this Tstudent type in subroutine Sub StudentsInfo() 'Creating and initializing student type variable Dim student1 As Tstudent student1.fName = "Manish" student1.lName = "Singh" student1.rNo = 12334 student1.clss = 10 student1.section = "A" ReDim student1.subjects(2) student1.subjects(0) = "physics" student1.subjects(1) = "Math" 'Printing student details. Debug.Print (student1.fName) Debug.Print (student1.lName) Debug.Print (student1.rNo) Debug.Print (student1.clss) Debug.Print (student1.section) Debug.Print (student1.subjects(0)) Debug.Print (student1.subjects(1)) End Sub
When you run the above sub it will print the result as shown below:
Singh
12334
10
A
physics
Math
Creating an Array of UDTs and Accessing Elements
Similarly you can create as many as variables of Tstudent type you need. You can even create an array of Tstudent type like any other data type.
Public Type Tstudent fName As String 'For First Name lName As String 'For Last Name rNo As Integer 'For Roll Number clss As string 'For Class section As String 'For Section Name subjects() As String 'For Subjects of student End Type 'Creating an arrays of Tstudents type Sub SchoolInfo() Dim schoolName As String Dim students() As Tstudent schoolName = "Senior School" ReDim students(10) For i = 0 To 9 students(i).fName = "name" & Str(i + 1) students(i).rNo = i + 1 Next i Debug.Print ("Name : Roll No") For i = 0 To 9 Debug.Print (students(i).fName & " : " & students(i).rNo) Next i End Sub
When you run this code, this will be printed in the immediate window.
name 1 : 1
name 2 : 2
name 3 : 3
name 4 : 4
name 5 : 5
name 6 : 6
name 7 : 7
name 8 : 8
name 9 : 9
name 10 : 10
In the above code, first defined UDT structure before and the sub (I’ll explain later why). The we just created an array using a dim keyword like we do for any variable in VBA.
Then we used Redim to define the size of arrays. Afterwards we use a for loop to initialize the array.
To access the structure’s elements we use another for loop. That is it.
Why Did We Declare UDT on Top of the Module?
If we declare a UDT first in a module, outside of any subroutine or function, it is available to all the modules in the workbook. It means if you have a hundred subs and functions in a module all of them can declare Student type variables in their body.
If the UDT is not private, it will be available to all the modules in the workbook. If want a structure (UDT) to be available only to a containing module, declare it private.
Private Type Tstudent fName As String lName As String rNo As Integer clss As Integer section As String subjects() As String End Type
You can’t have UDT on a procedural level. It means you can’t define a user defined data type inside a subroutine or function.
Nested User Defined Types
Let’s say you have UDT called a car. Car has its own elements. Similarly you have a UDT called a bike that can have its own properties.
Now let’s say you need a data type called vehicle. Vehicle can have a car and bike as its elements. Can we do this? Yes we can do this. See the below code
Private Type Tcar seats As Integer ac As Boolean typ As String color As String manufacturer As String Dop As Date rc_no As String End Type Private Type Tbike seats As Integer typ As String color As String manufacturer As String Dop As Date rc_no As String End Type Private Type Tvehicle number_of_Vehicle As Integer bike As Tbike car As Tcar End Type Sub vehicleVarification() Dim myVehicles As Tvehicle myVehicles.number_of_Vehicle = 2 myVehicles.bike.seats = 1 myVehicles.bike.typ = "Racing" myVehicles.car.seats = "4" myVehicles.car.ac = True Debug.Print myVehicles.number_of_Vehicle Debug.Print myVehicles.bike.typ Debug.Print myVehicles.car.ac End Sub
Here, we have defined three user defined data type. First is Tcar that contains some information related to cars. Second is bike, it also contains some information about bike.
The third UDT is Tvehicle. It contains one variable to store number of vehicles and two variables of Tcar and Tbike type.
Private Type Tvehicle
number_of_Vehicle As Integer
bike As Tbike
car As Tcar
End Type
To access variables of Tcar and Tbike we can use Tvehicle data type. In the sub, we have defined only one variable of Tvehicle type as myVehicles. When we create this variable VBA creates variables of Tcar and Tbike too.
To initialize and access variables of Tcar and Tcar, we can use myVehicle variable. As you can see in the code.
myVehicles.number_of_Vehicle = 2
myVehicles.bike.seats = 1
myVehicles.bike.typ = «Racing»
myVehicles.car.seats = «4»
myVehicles.car.ac = True
When we run the sub, this how result occurs.
This feature really increases the power of programming VBA exponentially. You can structure your data type like real world entities. You can create relationships between data types which can be useful in a big project.
So yeah guys, this is how you can create and use a user defined data type or structure in VBA. I hope I was able to explain it. If you have any questions regarding this article or any other VBA related questions, ask me in the comments section below. I’ll be really happy to hear from you.
Related Articles:
VBA variables in Excel| VBA stands for Visual Basic for Applications. It is a programming language from Microsoft. It is used with Microsoft Office applications such as MSExcel, MS-Word and MS-Access whereas VBA variables are specific keywords.
Excel VBA Variable Scope| In all the programming languages, we have variable access specifiers that define from where a defined variable can be accessed. Excel VBA is no Exception. VBA too has scope specifiers.
ByRef and ByVal Arguments | When an argument is passed as a ByRef argument to a different sub or function, the reference of the actual variable is sent. Any changes made into the copy of the variable, will reflect in the original argument.
Delete sheets without confirmation prompts using VBA in Microsoft Excel | Since you are deleting sheets using VBA, you know what you are doing. You would like to tell Excel not to show this warning and delete the damn sheet.
Add And Save New Workbook Using VBA In Microsoft Excel 2016| In this code, we first created a reference to a workbook object. And then we initialized it with a new workbook object. The benefit of this approach is that you can do operations on this new workbook easily. Like saving, closing, deleting, etc
Display A Message On The Excel VBA Status Bar| The status bar in excel can be used as a code monitor. When your VBA code is lengthy and you do several tasks using VBA, you often disable the screen update so that you don’t see that screen flickering.
Turn Off Warning Messages Using VBA In Microsoft Excel 2016| This code not only disables VBA alerts but also increases the time efficiency of the code. Let’s see how.
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 to filter your data to count specific values. 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.
Probably you have heard something about PHP. If you have, then you know that it supports arrays (and lists and anything you like) and you may declare any type of data in these. In VBA, usually the case is a little different. If you have a list of integers, then you can have only integers in it, and if you have a list of doubles – only doubles.
Anyway, sometimes you may wish that VBA was a little bit like PHP, where you could have declared a list of various variables. Actually, this is possible 🙂
WIth a little work around. You should declare a Private Type, in which you may put strings, integers and anything. Let’s take a look at the example:
Imagine you have to organize a Formula1 Grand Prix. You declare the following private types:
Private Type custCar sCarModel As String iCarSpeed As Integer iCarCylinders As Integer End Type Private Type custRoad sRoadName As String sRoadLocation As String dRoadDate As Date aRoadCars(8) As custCar End Type Private aCustRoads(8) As custRoad |
Then you simply decide to assign values to these types and to let it run. In the following example I have “created” two “roads” with two cars per road. This is how it looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
Sub Formula1() Dim iCustRoad As Integer Dim iCustCar As Integer Dim iLoop As Integer Dim iLoop2 As Integer Dim bPrintMe As Boolean iCustRoad = 0 iCustCar = 0 aCustRoads(iCustRoad).sRoadName = «The road close to Sofia.» aCustRoads(iCustRoad).sRoadLocation = «Close to Sofia.» aCustRoads(iCustRoad).dRoadDate = Now() aCustRoads(iCustRoad).aRoadCars(iCustCar).sCarModel = «Ford» aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarSpeed = 90 aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarCylinders = 8 iCustCar = 1 aCustRoads(iCustRoad).aRoadCars(iCustCar).sCarModel = «Lada» aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarSpeed = 80 aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarCylinders = 4 iCustRoad = 1 iCustCar = 0 aCustRoads(iCustRoad).sRoadName = «The road close to Plovdiv.» aCustRoads(iCustRoad).sRoadLocation = «Close to Plovdiv.» aCustRoads(iCustRoad).dRoadDate = Now() aCustRoads(iCustRoad).aRoadCars(iCustCar).sCarModel = «Ferrari» aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarSpeed = 95 aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarCylinders = 10 iCustCar = 1 aCustRoads(iCustRoad).aRoadCars(iCustCar).sCarModel = «Moskvich» aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarSpeed = 81 aCustRoads(iCustRoad).aRoadCars(iCustCar).iCarCylinders = 2 bPrintMe = True For iLoop = 0 To 1 Step 1 For iLoop2 = 0 To 1 Step 1 If (bPrintMe) Then Debug.Print aCustRoads(iLoop).sRoadName Debug.Print aCustRoads(iLoop).sRoadLocation Debug.Print aCustRoads(iLoop).dRoadDate End If Debug.Print aCustRoads(iLoop).aRoadCars(iLoop2).sCarModel Debug.Print aCustRoads(iLoop).aRoadCars(iLoop2).iCarSpeed Debug.Print aCustRoads(iLoop).aRoadCars(iLoop2).iCarCylinders bPrintMe = False Next iLoop2 bPrintMe = True Debug.Print ‘this is for space Next iLoop End Sub |
This is the result in the immediate window:
It is actually cool, if you can use it. 🙂 Or at least, you can use it to show, that you can put various types of data in a List or array. Which is a good usage as well 😀