First Attempt at Object Oriented VBA fails - excel

Question: Why do I get nothing but 0 out of this code? (via the MsgBox)
Context: Newbie trying to learn to use my own classes in Excel VBA.
Class1 is a class Module which has the code here:
Private pPhone As Integer
Public Property Get Phone() As Integer
Phone = pPhone
End Property
Public Property Let Phone(Value As Integer)
pPhone = Phone
End Property
And Test() is a sub in Module1 as you see here
Dim Home As Class1
Public Sub Test()
Set Home = New Class1
Home.Phone = 3
MsgBox Home.Phone
End Sub
The code executes, but Home.Phone is only reported as 0 (I guess the initial value) What am I doing wrong?

Change pPhone = Phone to pPhone = Value
It should be
Public Property Let Phone(Value As Integer)
pPhone = Value
End Property

Related

Parent Object for Custom Class of variable Type

I'm programming quite a complex thing in VBA I think and even though I did a lot of research I couldn't come up with a solution to my problem so far. And unfortunately I'm no expert :)
I have two classes, e.g. clsBuilding and clsFactory, which both have an instance of clsHeatDemand. Now I'm trying to implement a parent-Property to access some values from the base classes I need for the calculation, based on this idea.
Friend Property Get Parent() As clsBuilding
Set Parent = ObjFromPtr(parentPtr)
End Property
Friend Property Set Parent(obj As clsBuilding)
parentPtr = ObjPtr(obj)
End Property
My problem now is that the parent can be of two different types even though they have the same parameters I need. So what I'm trying to ask is if there is a way to hand over the instances simply as obj As Object and still access its properties?
I also tried this with Interfaces but I would be happy if there is another easier solution.
I don't know if this can help you, have a look at it.
' Class which has different parent
Option Explicit
Private m_parent As Variant
Public Property Get Parent() As Variant
Set Parent = m_parent
End Property
Public Property Set Parent(ByVal vNewValue As Variant)
Set m_parent = vNewValue
End Property
Public Function Name()
If TypeName(m_parent) = "ParentA" Then
Name = m_parent.Name
Else
Err.Raise 123, "Parent doesn't have Name"
End If
End Function
Public Function Height()
If TypeName(m_parent) = "ParentB" Then
Height = m_parent.Height
Else
Err.Raise 456, "Parent doesn't have Height"
End If
End Function
' ParentA
Public Name As String
Public Age As Integer
' ParentB
Public Height As Double
Public Weight As Double
' Test
Sub test()
Dim c As Class
Set c = New Class
Dim pa As ParentA
Set pa = New ParentA
pa.Age = 5
pa.Name = "Parent A"
Dim pb As ParentB
Set pb = New ParentB
pb.Height = 15.5
pb.Weight = 50.5
Set c.Parent = pa
Debug.Print c.Name
Set c.Parent = pb
Debug.Print c.Height
Debug.Print c.Name
End Sub

Properly coding a constructor

I am trying to implement a Model-View-Presenter Userinterface in VBA excel. In order to do this I have been writing different Model classes. Here an Example:
Option Explicit
Private Type TModel
FilterCol As Collection
N As Integer
End Type
Private this As TModel
Public Property Get FilterCol() As Collection
Set FilterCol = this.FilterCol
End Property
Public Property Let FilterCol(ByVal value As Collection)
Set this.FilterCol = value
End Property
Public Property Get N() As Integer
Set N = this.N
End Property
Public Property Let N(ByVal value As Integer)
Set this.N = value
End Property
This class called "FilterModel" is a collection of MSFormObjects. In order to use the collection properly I need to new it. So the code where I use it would look a little like this:
Sub testFilter()
Dim Filterm As FilterModel
Dim DefaultFilterLine As New FilterLine
Set Filterm = New FilterModel
Filterm.FilterCol = New Collection
'Set DefaultFilter
Filterm.FilterCol.Add DefaultFilterLine
'DoStuff
With New frmFilter
Set .Model = Filterm
.Show
End With
End Sub
If I don't new the Property FilterCol before I add something, in this case the defaultfilter, it doesn't work. So here is my Question:
Is there a way to overwrite the new statement for my new class in order to have it also new up the collection FilterCol. My research got me as far as I now know that this would be called a constructor.
But how would one properly implement a constructor for a VBA class?
Somthing like:
Private Sub Class_Initialize()
Set this.FilterCol = New Collection
N = 0
End Sub
If I do this then I get an error in the "Property Let N(Byval Value as integer)" Line. The error message reads "object required".
Here is a working solution. I suggest going through the code line-by-line using F8 to understand what is happening there. Debug.print prints values into the Immediate window.
Here is the FilterModel class:
''' FilterModel class
Option Explicit
Private pFilterCol As Collection
Private pN As Integer
Public Property Get FilterCol() As Collection
Set FilterCol = pFilterCol
End Property
Public Property Let FilterCol(ByVal value As Collection)
Set pFilterCol = value
End Property
Public Property Get N() As Integer
N = pN
End Property
Public Property Let N(ByVal value As Integer)
pN = value
End Property
Private Sub Class_Initialize()
Set pFilterCol = New Collection
pN = 0
End Sub
and here is module code to test it:
''' random module
Option Explicit
Sub testFilter()
Dim Filterm As FilterModel
Set Filterm = New FilterModel
Filterm.FilterCol = New Collection
''' default values (specified in Class_Initialize())
Debug.Print Filterm.N
Debug.Print Filterm.FilterCol.Count
''' set the values through Property Let
Filterm.FilterCol.Add "whatever"
Filterm.FilterCol.Add "whenever"
Filterm.N = 6
''' print the new values (through Property Get)
Debug.Print Filterm.N
Debug.Print Filterm.FilterCol.Count
Debug.Print Filterm.FilterCol(1)
Debug.Print Filterm.FilterCol(2)
End Sub

Property Let and Set not recognized

I'm new in Object Oriented Programming in VBA and I'm trying to write my first class.
I'm following guides on the Internet for it.
But I get errors I don't understand.
Let and Set properties are not recognized and appear in red. The same is true for Sub when I try to pass them Parameters.
Would you happen to know where the issue can come from ?
Option Explicit
Private pNumShare As Integer
Private pNumPlan As Integer
Private pName As String
Public Property Get NumShare() As Integer
NumShare = pNumShare
End Property
Public Property Let NumShare(int AS Integer)
pNumShare = int
End Property
Public Sub Class_Initialize()
NumShare = Empty
NumPlan = Empty
Name = Empty
End Sub
Public Sub setColonne(int As Integer)
End Sub
The expression int is a function and therefore a reserved word in VBA. Use a different variable name.
See here
(And please Edit your question to Add your code...Images for code are not helpful)
Also the syntax is Property Set as in this link

Trying to set up a custom object model using example, not working

I am trying to set up a custom object model using an example I found in an answered question here on stackoverflow.
VBA Classes - How to have a class hold additional classes
Here is the code I have created based on the answer.
Standard Module
Sub test()
Dim i As Long
Dim j As Long
'code to populate some objects
Dim AssemList As Collection
Dim Assem As cAssem
Dim SubAssemList As Collection
Dim SubAssem As cSubAssem
Set AssemList = New Collection
For i = 1 To 3
Set SubAssemList = New Collection
Set Assem = New cAssem
Assem.Description = "Assem " & i
For j = 1 To 3
Set SubAssem = New cSubAssem
SubAssem.Name = "SubAssem" & j
SubAssemList.Add SubAssem
Next j
Set Assem.SubAssemAdd = SubAssemList '<------ Object variable or With Block not Set
AssemList.Add Assem
Next i
Set SubAssemList = Nothing
'write the data backout again
For Each clock In AssemList
Debug.Print Assem.Description
Set SubAssemList = Assem.SubAssems
For Each SubAssem In SubAssemList
Debug.Print SubAssem.Name
Next
Next
End Sub
cAssem Class
Private pDescription As String
Private pSubAssemList As Collection
Private Sub Class_Initialize()
Set pSubAssems = New Collection
End Sub
Public Property Get Description() As String
Description = pDescription
End Property
Public Property Let Description(ByVal sDescription As String)
pDescription = sDescription
End Property
Public Property Get SubAssems() As Collection
Set SubAssems = pSubAssemList
End Property
Public Property Set SubAssemAdd(AssemCollection As Collection)
For Each AssemName In AssemCollection
pSubAssemList.Add AssemName ' <------- This is the line that is triggering the error
Next
End Property
cSubAssem Class
Private pSubAssemName As String
Public Property Get Name() As String
Name = pSubAssemName
End Property
Public Property Let Name(ByVal sName As String)
pSubAssemName = sName
End Property
I have not changed anything in the code except class names and variable names and from my limited point of view I cannot understand the cause of the error.
I am just starting to really dig into objects and Class Modules in VBA so I appreciate any knowledge this community could pass my way.
Many Thanks
You have a typo in your sub class initializer:
Private Sub Class_Initialize()
Set pSubAssems = New Collection
End Sub
should read:
Private Sub Class_Initialize()
Set pSubAssemList = New Collection
End Sub

VBA Class() object as property of another class

I'm trying to create a class to hold a variable number of items (which are themselves another class object).
So, I have Class 2:
' Class 2 contain each individual quote elements (OTC and MRC)
Private pOTC As String
Private pMRC As String
Public Property Get OTC() As String
OTC = pOTC
End Property
Public Property Let OTC(Value As String)
pOTC = Value
End Property
Public Property Get MRC() As String
MRC = pMRC
End Property
Public Property Let MRC(Value As String)
pMRC = Value
End Property
Then Class 1 contains an array of Class 2:
Private pCurr As String
Private pQuote(20) As Class2
Public Property Get Curr() As String
Curr = pCurr
End Property
Public Property Let Curr(Value As String)
pCurr = Value
End Property
Public Property Set Quote(Index As Integer, cQuote As Class2)
Set pQuote(Index) = cQuote
End Property
Public Property Get Quote(Index As Integer) As Class2
Quote = pQuote(Index)
End Property
And what I would like to do is something like:
Dim myQuotes As Class1
Set myQuotes = New Class1
myQuotes.Curr = "GBP"
myQuotes.Quote(3).OTC = "1200"
The first line setting myQuotes.Curr is no problem, however when I try to set a value inside the array the next line errors with Run-time 91 Object variable or With block variable not set
Any pointers as to what I'm doing wrong and how can I set the values for the elements within the class array?
Thanks in advance!
When you myQuotes.Quote(3) you call Property Get Quote which has an issue.
Your internal array of Class2 is not instantiated so pQuote(Index) refers to an array element of Nothing, when you then myQuotes.Quote(3).OTC = you try to assign to Nothing which fails.
You need to make sure pQuote(Index) is instanced; you can do this on demand:
Public Property Get Quote(Index As Integer) As Class2
If (pQuote(Index) Is Nothing) Then Set pQuote(Index) = New Class2
Set Quote = pQuote(Index)
End Property
(Note the required Set)
Or by adding an intitialisation routine to Class1:
Private Sub Class_Initialize()
Dim Index As Long
For Index = 0 To UBound(pQuote)
Set pQuote(Index) = New Class2
Next
End Sub
You need to set them as New Class2 in Class1:
For intI = LBOUND(pQuote) to UBOUND(pQuote)
Set pQuote(intI) = New Class2
Next IntI
Just as you do with Class1 in your final script.
Maybe it should be
Public Property Let Quote(Index As Integer, cQuote As Class2)
Set pQuote(Index) = cQuote
End Property

Resources