Pass an object as parameter from a UserForm to another one - excel

I create a Class type Employee
Private emplId As String
Private name As String
Private rank As String
Private post As String
I create a module with a function Inside who return an object type Employee.
Public Function FuncNewPerson(Emplid As String) As Employee
Dim newPerson As New Employee
With newPerson
newPerson.SetEmplid = Emplid
newPerson.SetName = mytab(25, 1)
newPerson.SetRank = mytab(23, 1)
newPerson.SetPost = mytab(27, 1)
Set FuncNewPerson = newPerson
I use two UserForms, in the first one after selection of an emplId via a ComboBox it initialize an object type Employee, then I fill all the TextBox of the first UserForm with the get property of the object :
RequestForm.TxtBoxPerson = person.GetName
RequestForm.txtBoxRank = person.GetRank
On this UserForm i have a Button who calls the second one :
Public Sub BtnVerify_Click()
Me.Hide
ValidationForm.Show
End Sub
In the second UserForm I have some other TextBox to fill :
ValidationForm.TxtBoxEmployee = person.GetEmplid
ValidationForm.txtBoxRank = person.GetRank
ValidationForm.txtBoxPost = person.GetPost
I would like to use the object who is already in memory so my first idea is to pass it as an argument from the first form to the second one.
Of course i already searched the web but i'm now more confused about it, that's why i ask some help here in order to :
get some clues
get a feedback about my way of doing this
Thank you

In the second form, create a suitable variable
Private Person as Employee
Then create a property
Property Set CurrentPerson(p as Employee)
set person = p
End Property
Then set this property in the code from your first form
Public Sub BtnVerify_Click()
Me.Hide
ValidationForm.Show
Set validationform.currentperson = person
End Sub

Related

How can I get a reference to a TextBox itself instead of to its default value in Excel vba?

Windows 10 Pro 64, Office 365 Excel vba
ClassCounter is a class that operates on a Long value it stores internally and then displays that value in a TextBox in an active UserForm. I want to be able to assign the TextBox to the ClassCounter object dynamically, so that I can use the same class to instantiate a number of objects, each of which references its own TextBox in the same UserForm.
It has the following private members declared at the class level:
Private mctrLinked As ClassCounter
Private mnCount As Long
Private mtbxDisplay As TextBox
The Initialize subroutine makes the connection between displayTextBox (the textbox used to display the value) and the object. linkCounter provides the opportunity to link to another object of the same class and fire off the same operation on it in a daisychain fashion.
Public Sub Initialize(ByRef displayTextBox As msforms.TextBox, Optional linkCounter As ClassCounter = Nothing)
Const kstrMethodName As String = "Initialize"
Set mtbxDisplay = displayTextBox
Set mctrLinked = linkCounter
Clear
End Sub ' Initialize
The class is instantiated in another class, as follows:
Private mobjAllBlankCounter As New ClassCounter
Private mobjAllEnteredCounter As New ClassCounter
Private mobjAllFoundCounter As New ClassCounter
Private mobjAllIssuesCounter As New ClassCounter
...
And the connection between the TextBox and the ClassCounter object is established by calling the Initialize subroutine in this way:
Public Sub InitializeAllCounters()
With mufMCP
mobjAllBlankCounter.Initialize .tbxBlankCountAll
mobjAllEnteredCounter.Initialize .tbxEnteredCountAll
mobjAllFoundCounter.Initialize .tbxFoundCountAll
mobjAllIssuesCounter.Initialize .tbxIssuesCountAll
End With
End Sub ' InitializeAllCounters
where mufMCP is the UserForm in which the TextBoxes are defined.
Ultimately, the Increment function (and others like it) will operate on the stored variable and then display it in the referenced TextBox as follows:
Public Sub Increment()
Const kstrMethodName As String = "Increment"
If (mtbxDisplay Is Nothing) Then
Err.Raise gknErrNoControlForCounter, mkstrModuleName & "." & kstrMethodName, "Attempt to Increment Counter with no associated control."
Else
mnCount = mnCount + 1
mtbxDisplay.Text = CStr(mnCount)
If (Not (mctrLinked Is Nothing)) Then
mctrLinked.Increment
End If
End If
End Sub ' Increment
The problem I'm having is in the Initialize subroutine where I attempt to assign the value of the TextBox argument to the local variable. Instead of assigning a reference to the TextBox itself, the right side of the assignment is evaluating to the TextBox's default value, which is its Text property. As a result, I get a type mismatch error.
How can I get it to evaluate to a reference to the TextBox itself? I've spent a couple of days searching for the answer and found several sources that said that using ByRef displayTextBox As msforms.TextBox to define the parameter would do the trick, but I'm still getting the control's default value.
As FaneDuru writes, TextBox and MsForms.TextBox are two different object types. A TextBox is a textbox (Form Control, not Active X Control) placed on a sheet. A MsForms.TextBox is a textbox places on a user form.
Bad thing (1): The name "Form Control" related to sheet controls is misleading, it is not the same as a control placed on a user form.
Bad thing (2): As the Form Control Textbox is no longer available from the Developer menu, it is not easy to proof. If you are interested: You can still create them using VBA.
Dim tb1 As TextBox
Set tb1 = ActiveSheet.TextBoxes.Add(255, 243, 73.5, 22.5)
Dim tb2 As msforms.TextBox
UserForm1.Show False
Set tb2 = UserForm1.TextBox1
Checking both objects in the Locals window of the VBA editor, type for both is displayed as "Textbox/Textbox". However, when you look at the properties of the objects, you see that they are different.
So declare all your (userform) controls with the suffix msforms to be sure that you are dealing with the right object types.

VBA Customize collection object

I've been trying to learn how to create customized collections in Excel VBA and I found this piece of code on MSDN. While I understand most of it, can anyone tell me what the last code Set Add = empNew is doing? I don't understand it's comment. Thank you!
' Methods of the Employees collection class.
Public Function Add(ByVal Name As String, _
ByVal Salary As Double) As Employee
Dim empNew As New Employee
Static intEmpNum As Integer
' Using With makes your code faster and more
' concise (.ID vs. empNew.ID).
With empNew
' Generate a unique ID for the new employee.
intEmpNum = intEmpNum + 1
.ID = "E" & Format$(intEmpNum, "00000")
.Name = Name
.Salary = Salary
' Add the Employee object reference to the
' collection, using the ID property as the key.
mcolEmployees.Add empNew, .ID
End With
' Return a reference to the new Employee.
Set Add = empNew
End Function
You will notice that Add is the name of the Function. By issuing Set Add = newEmp your code is declaring that the return value (or object, in this case) of the function, is the newly created employee object newEmp. This means that the function will pass the variable newEmp back to its caller.
Say that you had some procedure calling your function, you would be able to do this:
Sub listEmployees
Dim e As Employee
' Create a new employee, and assign the variable e to point to this object
Set e = Add("John", 1000) ' Notice that the only reason we use "add" here is because it is the name of the function you provided
' e is now an Employee object, after being created in the line above, meaning we can access whatever properties is defined for it. The function Add lists some properties, so we can use those as examples.
Debug.Print e.Name
Debug.Print e.Salary
Debug.Print e.ID
End Sub
First, you need to define the new Type you have created, so put the following code on top of your module:
Public Type Employee
id As String
Name As String
Salary As Long
End Type
Then, inside your Public Function Add , change to Dim empNew As Employee.
Not sure why you need the following line : mcolEmployees.Add empNew, .id ??
and the last line modify to Add = empNew.
Then, when I test this Function from the following Sub:
Sub testEmp()
Dim s As Employee
s = Add("Shai", 50000)
End Sub
I get for s in the immediate window the following values:
s.id = E00001
s.Name = "Shai"
s.Salary = 50000
I hope this is what you intended in your post.

List the properties of a class in VBA 2003

I've searched all over to see if there is an easy answer to this question, but there doesn't seem to be...
I'm using Excel VBA 2003 (yes, I know it's out-of date, but I can't change this), and all I want to do is list the names and values of all the readable properties in a given custom class.
I'd like to do something like this:
Class definition (for class entitled cFooBar)
Option Explicit
Private pFoo As String
Private pBar As String
Public Property Get Foo() As String
Foo=pFoo
End Property
Public Property Get Bar() As String
Bar=pBar
End Property
Calling code
Dim myFooBar as cFooBar, P as Property
myFooBar=new cFooBar
For Each P in myFooBar.Properties
Debug.Print P.Name, P.Value
Next
Of course, this doesn't work because there doesn't seem to be a "Properties" collection member for custom classes (or at least not one that you can get at), and there isn't a "Property" type either.
Does anybody know a way around this?
TIA,
Campbell
As John mentions above, reflection is not supported in VBA. Here is a hack that I have used before. Basically you can create a Collection or Dictionary object to store your "properties" by name.
Option Explicit
Private pProperties As Object
Public Property Get Properties() As Object
Set Properties=pProperties
End Property
Public Property Let Properties(p as Object)
Set pProperties = p
End Property
Sub Class_Initialize()
Set pProperties = CreateObject("Scripting.Dictionary")
'Add/instantiate your properties here
pProperties("foo") = "this is foo"
pProperties("bar") = "this is bar"
End Sub
Calling code
Dim myFooBar As New cFooBar, P As Variant
For Each P In myFooBar.Properties.Keys()
Debug.Print P, myFooBar.Properties(P)
Next

Build Object Hierarchy in Excel-VBA

I'm losing quite some time copy-pasting identical properties and methods in various vba custom object I'm building. How do I create an custom-object hierarchy in VBA so one object and inherit properties and methods from others.
In python I would prob write something like:
Class Car(Object)
whatever
Class SlowCar(Car)
inherit whatever
Class FastCar(Car)
inherit whatever
tks in advance.
If i understand what you're saying, this can be done via the Class Module.
From the VBA Editor, select Insert > Class Module
Change the name of the class Module to whatever you want (Car for
example) via the Properties Window (press F4 to make it appear if it
does not already)
Now that you've created your class module you can define its variables and/or properties. The example below would go into your Car Class Module creates a object that holds a car name and a speed
Private carName As String
Private carSpeed As Integer
' Car Name
Public Property Get Name() As String
Name = carName
End Property
Public Property Let Name(result As String)
carName = result
End Property
' Car Speed
Public Property Get Speed() As Integer
Speed = carSpeed
End Property
Public Property Let Speed(result As Integer)
carSpeed = result
End Property
Then from your Module, you can do the following
Sub CreateMyCars()
Dim slowCar as Car
Dim fastCar as Car
Set slowCar = New Car
Set fastCar = New Car
slowCar.Name = "GoKart"
slowCar.Speed = 35
fastCar.Name = "Ferarri"
fastCar.Speed = 185
End Sub
VBA supports inheritance through the use of Interfaces, but they only "inherit" the signature of methods, not the implementation.
A way to reuse an object implementation would be through composition.
Class Car(Object)
whatever
Class SlowCar(Car)
Implements Car
private mCar as Car
Private Sub Class_Initialize
set mCar = new Car
End Sub
Private Sub Car_whatever
Call mCar.whatever
End Sub
And same for FastCar.

Dictionary Property in VBA Class

I have been asked to modify an Excel sheet with some arcaic programming. I have decided to rewrite it rather then modify all of the many GOTO statments and static arrays. My background is in C# so it has been a bit of a challenge (note: I am sure the naming convention is bad, I am used to being able to use underscore to define private variables)
I am having trouble inializing an attribute of the type dictionary within a class that I have in a VBA application.
The shortened version of the class looks like this
Private pTerminalCode As String
Private pTerminalName As String
...... other attributes
Private pPayRoll As Dictionary
'Propeties
Public Property Get terminalCode() As String
terminalCode = pTerminalCode
End Property
Public Property Let terminalCode(Value As String)
pTerminalCode = Value
End Property
....... more properties
Public Property Get headCount() As Dictionary
headCount = pHeadCount
End Property
Public Property Let headCount(Value As Dictionary)
pHeadCount = Value
End Property
When I try to use the following I get the error "Argument not optional" within the Get property of the headCount() attribute.
Private Function PopulateTerminal()
Dim terminal As clsTerminal
Set terminal = New clsTerminal
terminal.terminalCode = "Wil"
terminal.headCount.Add "Company", 100
End Function
I assume somewhere I need to inialize the dictionary (i.e. = New Dictionary) however I am strugling with where to place it. In C# I do this in the constructor without issue, not sure what to do here.
Thanks
You can do it in the constructor of the VBA class, like so:-
Public Sub Class_Initialize()
Set myDictionary = New Dictionary
End Sub
Don't forget to always use the Set keyword when assigning an object reference, e.g.:-
Public Property Get Foo() As Dictionary
Set Foo = myDictionary
End Sub

Resources