VBA Class Module - When to Stop and Where to declare public constant? - vba

I have been coding vba for quite sometime now and it is only recently that I have begun diving into doing up some class module.
some questions on my mind is when should I stop including functions and properties in a class ?
i.e. I am creating a class module where by it record table properties (i.e. row of header column) I went on further to create a retrieve data function where it gets data from other table with the same class.
Question 1: am I over doing it? I tend to want to put all the function in one class.
Question 2: if I want to set all classes to have the same default initialization do I declare a public const in the class module itself or the normal modules?
Here is my class module :
Private pHeaderNames As Object
Private pHeaderRow As Long
Private pSubHeaderNames As Object
Private pSubHeaderRow As Long
Private pDataRowStart As Long
Private pInputColStart As Long
Private pTableColStart As Long
Private pHeaderLastCol As Long
Private pTblWorksheet As Worksheet
Private pFileURL As String
Private pFileName As String
'---------------------------------------------- Initialization
Private Sub Class_Initialize()
pHeaderRow = 1
pDataRowStart = 2
pTableColStart = 1
pInputColStart = pTableColStart
pSubHeaderRow = pHeaderRow
pHeaderLastCol = Cells(pHeaderRow, Columns.Count).End(xlToLeft).Column
Set pHeaderNames = CreateObject("Scripting.Dictionary")
Set pSubHeaderNames = CreateObject("Scripting.Dictionary")
End Sub
Public Property Get FileURL() As String
FileURL = pFileURL
End Property
Public Property Let FileURL(Value As String)
pFileURL = Value
End Property
Public Property Get FileName() As String
FileName = pFileName
End Property
Public Property Let FileName(Value As String)
pFileName = Value
End Property
Function OpenWorkbook(URL As String, Name As String)
pFileURL = URL
pFileName = Name
Call Workbook_open(pFileURL, pFileName)
End Function
Public Property Let SetSheet(Value As String)
If pFileName - "" Then
Set pTblWorksheet = ActiveWorkbook.Worksheets(Value)
Else
Set pTblWorksheet = Workbook(pFileName).Worksheets(Value)
End If
End Property
Public Property Get TblWorksheet() As Worksheet
TblWorksheet = pTblWorksheet
End Property
Public Property Let TblWorksheet(Sheet As Worksheet)
pTblWorksheet = Sheet
End Property
'---------------------------------------------- HeaderLastCol
Public Property Get HeaderLastCol() As Long
HeaderLastCol = pHeaderLastCol
End Property
Public Property Let HeaderLastCol(Value As Long)
pHeaderLastCol = Value
End Property
'---------------------------------------------- HeaderRow
Public Property Let HeaderRow(Value As Long)
pHeaderLastCol = Cells(pHeaderRow, Columns.Count).End(xlToLeft).Column
pHeaderRow = Value
End Property
Public Property Get HeaderRow() As Long
HeaderRow = pHeaderRow
End Property
'---------------------------------------------- SubHeaderRow
Public Property Let SubHeaderRow(Value As Long)
pSubHeaderRow = Value
End Property
Public Property Get SubHeaderRow() As Long
SubHeaderRow = pSubHeaderRow
End Property
'---------------------------------------------- InputColStart
Sub SetInputColStart(KEY As Variant)
pInputColStart = pHeaderNames(KEY)
End Sub
Public Property Get InputColStart() As Long
InputColStart = pInputColStart
End Property
Public Property Let InputColStart(Value As Long)
pInputColStart = Value
End Property
'---------------------------------------------- DataRowStart
Public Property Get DataRowStart() As Long
DataRowStart = pDataRowStart
End Property
Public Property Let DataRowStart(Value As Long)
pDataRowStart = Value
End Property
'---------------------------------------------- TableColStart
Public Property Get TableColStart() As Long
TableColStart = pTableColStart
End Property
Public Property Let TableColStart(Value As Long)
pTableColStart = Value
End Property
'---------------------------------------------- HeaderName
Sub GetHeaderNames()
With pHeaderNames
For i = pTableColStart To pHeaderLastCol
If Not .Exists(UCase(Cells(pHeaderRow, i).Value)) Then
.Add UCase(Cells(pHeaderRow, i).Value), i
End If
Next i
End With
End Sub
Function HeaderName(KEY As String)
If pHeaderNames.Exists(KEY) Then
HeaderName = pHeaderNames(KEY)
Else
HeaderName = ""
End If
End Function
Function CountHeaderNames()
CountHeaderNames = pHeaderNames.Count
End Function
Function PrintHeaderObject()
For Each KEY In pHeaderNames.keys
Debug.Print KEY, pHeaderNames(KEY)
Next
End Function
'---------------------------------------------- SubHeaderName
Sub GetSubHeaderNames()
With pSubHeaderNames
For i = pTableColStart To pHeaderLastCol
If Not .Exists(UCase(Cells(pSubHeaderRow, i).Value)) Then
.Add UCase(Cells(pSubHeaderRow, i).Value), i
End If
Next i
End With
End Sub
Function SubHeaderName(KEY As String)
If pSubHeaderNames.Exists(KEY) Then
SubHeaderName = pSubHeaderNames(KEY)
Else
SubHeaderName = "" 'or raise an error...
End If
End Function
Function CountSubHeaderNames()
CountSubHeaderNames = pSubHeaderNames.Count
End Function
Function PrintSubHeaderObject()
For Each KEY In pSubHeaderNames.keys
Debug.Print KEY, pSubHeaderNames(KEY)
Next
End Function
Function RetrieveData(FromSht As Worksheet, ByVal FromTable As cTable)
Dim KEY As String
'CurrentSht = ActiveSheet
For i = pTableColStart To pHeaderLastCol
KEY = Cells(pHeaderRow, i).Value
If FromTable.HeaderName(KEY) = "" Then
GoTo Nexti
Else
With FromSht
.Activate
rD_LastRow = 10
Set Source = .Range(.Cells(FromTable.DataRowStart, FromTable.HeaderName(KEY)), _
.Cells(rD_LastRow, FromTable.HeaderName(KEY)))
End With
With CurrentSht
.Activate
.Range(.Cells(DataRowStart, i), _
.Cells(DataRowStart, i)) _
.Resize(Source.Rows.Count, Source.Columns.Count).Cells.Value = Source.Cells.Value
End With
End If
Nexti:
Next i
End Function
Here is the module, so you can see that I have always need to declare headerRow , subHeaderRow and Datarowstart, even thou I have a default initialization set in the class module, is there away to change the default initialization based on the main module? or I just have to do it in the class module? (I trying to make the class portable)
Sub test()
Dim sht As Worksheet
Set wb = ActiveWorkbook
Set sht = wb.Sheets("Skin(Units)")
With Worksheets("Skin(Units)")
.Activate
Set SkinUnits = New cTable
Debug.Print TypeName(SkinUnits)
SkinUnits.HeaderRow = 1
SkinUnits.SubHeaderRow = 3
SkinUnits.DataRowStart = 4
SkinUnits.GetHeaderNames
SkinUnits.GetSubHeaderNames
SkinUnits.PrintHeaderObject
SkinUnits.PrintSubHeaderObject
SkinUnits.SetInputColStart ("Start")
End With
With Worksheets("Pain(Units)")
.Activate
Set PainUnits = New cTable
PainUnits.HeaderRow = 1
PainUnits.SubHeaderRow = 3
PainUnits.DataRowStart = 4
PainUnits.GetHeaderNames
PainUnits.GetSubHeaderNames
PainUnits.PrintHeaderObject
PainUnits.PrintSubHeaderObject
PainUnits.SetInputColStart ("Start")
Debug.Print PainUnits.HeaderName("SKU")
Debug.Print TypeName(sht), TypeName(SkinUnits)
Call test22222(SkinUnits)
Call PainUnits.RetrieveData(sht, SkinUnits)
End With
End Sub
Function test22222(ByVal X As cTable)
Debug.Print X.HeaderRow
End Function

Related

Adding a custom class collection to another custom class collection

Ok to start off, I read through this.
It is close although it doesn't answer my specific question. This talks about taking smaller collections and adding items to a larger main collection. Then destroying the smaller collection.
I have two definitions under Class Modules.
TimeDet
Option Explicit
Public recDate As String
Public recQty As String
Public recDieNo As String
Public recCatID As String
Public recCatName As String
Public recGroupID As String
Public recGroupName As String
TimeRec
Option Explicit
Private objTimeRec As Collection
Private Sub Class_Initialize()
Set objTimeRec = New Collection
End Sub
Private Sub Class_Terminate()
Set objTimeRec = Nothing
End Sub
Public Property Get NewEnum() As IUnknown
Set NewEnum = objTimeRec.[_NewEnum]
End Property
Public Sub Add(obj As TimeDet)
objTimeRec.Add obj
End Sub
Public Sub Remove(Index As Variant)
objTimeRec.Remove Index
End Sub
Public Property Get Item(Index As Variant) As TimeDet
Set Item = objTimeRec.Item(Index)
End Property
Property Get Count() As Long
Count = objTimeRec.Count
End Property
Public Sub Clear()
Set objTimeRec = New Collection
End Sub
Public Sub FillFromArray(Arr As Variant)
Dim i As Long, obj As TimeDet
For i = 1 To UBound(Arr)
Set obj = New TimeDet
obj.recDate = Arr(i, 1)
obj.recQty = Arr(i, 2)
obj.recDieNo = Arr(i, 3)
obj.recCatID = Arr(i, 4)
obj.recCatName = Arr(i, 5)
obj.recGroupID = Arr(i, 6)
obj.recGroupName = Arr(i, 7)
Me.Add obj
Next
End Sub
Then in the code I am using it this way:
Sub Test()
Dim RecSet1 As TimeRec, Record As TimeDet
Dim fSet1 As TimeRec, fRecord As TimeDet
Dim repArray() As Variant
Dim startDT As Date, endDT As Date, dieNo As String
repArray() = Sheet4.Range("A2:G" & Sheet4.Range("A2").End(xlDown).Row)
Set RecSet1 = New TimeRec
Set fSet1 = New TimeRec
RecSet1.FillFromArray (repArray())
startDT = "1-1-2015"
endDT = "1-1-2016"
dieNo = "16185"
For Each Record In RecSet1
If Record.recDate <= endDT And Record.recDate >= startDT And Record.recDieNo = dieNo Then
fSet1.Add (Record)
End If
Next
End Sub
I am getting an error when I try to add the Record object to the fSet1 object.
"Object doesn't support this method or property"
The Record object is Type TimeDet which as you can see up in the class module my Add method is expecting type TimeDet.
Either I am missing something very simple and have blinders on, or this is a bigger issue.
The array has 200,000 records roughly. I am attempting to create a smaller subset of filtered data. Maybe I am approaching this from the wrong way.
Your error is not at Add but at For Each
Most likely you copied your TimeRec Class. In VBA, you can't create enumerable classes inside the VBE (VBA IDE). There's a different way of creating Enumerable classes.
Open a notepad, copy all your class code and then add this attribute to NewEnum property Attribute NewEnum.VB_UserMemId = -4
Then import the class.
This is always hidden in VBA code, but can be seen in text editors.
Also add this attribute to Item property, it will make it default and allows syntax like ClassName(1)
Attribute Item.VB_UserMemId = 0
So , your code in text editor/ notepad should be:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Class1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private objTimeRec As Collection
Private Sub Class_Initialize()
Set objTimeRec = New Collection
End Sub
Private Sub Class_Terminate()
Set objTimeRec = Nothing
End Sub
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = objTimeRec.[_NewEnum]
End Property
Public Sub Add(obj As Class2)
objTimeRec.Add obj
End Sub
Public Sub Remove(Index As Variant)
objTimeRec.Remove Index
End Sub
Public Property Get Item(Index As Variant) As Class2
Attribute Item.VB_UserMemId = 0
Set Item = objTimeRec.Item(Index)
End Property
Property Get Count() As Long
Count = objTimeRec.Count
End Property
Public Sub Clear()
Set objTimeRec = New Collection
End Sub
The answer to this particular problem was to remove the parenthesis form my Add method. That being said, the attribute info being hidden was really good info and would have probably contributed to the problem after I figured out that removing the parenthesis fixed it.

Add Class objects to Collection using a Function in VBA

I have this class:
Option Explicit
Public Code As String
Public ArticleType As String
Public Division As String
Public Devise As String
Public GroupePrix As String
Property Get CodeOnly() As String
CodeOnly = Replace(Code, "*", "")
End Property
And this function:
Function addFabricant(cod As String, art As String, div As String, dev As String, grp As String) As Fabricant
Dim Fab As New Fabricant
Fab.Code = cod
Fab.ArticleType = art
Fab.Division = div
Fab.Devise = dev
Fab.GroupePrix = grp
Set addFabricant = Fab
End Function
And I want to do something like this:
Set Fabricants = New Collection
'This is where the code fail with error 438
Fabricants.Add (addFabricant("Code", "Sample", " ", "DogeCoin", "420"))
...
But it does not work. I'm new to VBA so I may be missing something.
I know that :
Set test = addFabricant("Code", "Sample", " ", "DogeCoin", "420")
Fabricants.Add (test)
is working, but it would add double the code to add all the Fabricant this way.
I think you want "user defined types"
Public Type MyType
MyInt As Integer
MyString As String
MyDoubleArr(2) As Double
End Type
Then use it as a collection or an array.
Dim MyArr(2) As MyType
MyArr(0).MyInt = 31
MyArr(0).MyString = "VBA"
MyArr(0).MyDoubleArr(0) = 1
MyArr(0).MyDoubleArr(1) = 2
MyArr(0).MyDoubleArr(2) = 3
MyArr(1).MyInt = 32
MyArr(1).MyString = "is"
MyArr(1).MyDoubleArr(0) = 11
MyArr(1).MyDoubleArr(1) = 22
MyArr(1).MyDoubleArr(2) = 33
MyArr(2).MyInt = 33
MyArr(2).MyString = "cool"
MyArr(2).MyDoubleArr(0) = 111
MyArr(2).MyDoubleArr(1) = 222
MyArr(2).MyDoubleArr(2) = 333
I would create a wrapper class for your collection and add methods to the FabricantCollection to do what you want. Here is a FabricantCollection started for you:
Option Compare Database
Option Explicit
Private Const MODULE_NAME As String = "FabricantCollection"
Private m_oCollection As Collection
Private Sub Class_Initialize()
Set m_oCollection = New Collection
End Sub
Private Sub Class_Terminate()
If Not m_oCollection Is Nothing Then
Set m_oCollection = Nothing
End If
End Sub
Public Function Add(oFabricant As Fabricant) As Long
m_oCollection.Add oFabricant, oFabricant.Code
Add = m_oCollection.Count
End Function
Public Sub Clear()
Set m_oCollection = New BaseCollection
End Sub
Public Property Get Count() As Long
Count = m_oCollection.Count
End Property
Public Function Item(ByVal vKey As Variant) As Fabricant
Set Item = m_oCollection.Item(vKey)
End Function
Public Function Remove(ByVal vKey As Variant) As Fabricant
Set Remove = m_oCollection.Item(vKey)
m_oCollection.Remove vKey
End Function
Public Function AddNew( _
ByVal sCode As String, _
ByVal sArt As String, _
ByVal sDiv As String, _
ByVal sDev As String, _
ByVal sGrp As String) As Fabricant
Dim oFabricant As Fabricant
If Not oFabricant Is Nothing Then
Err.Raise vbObjectError + 3334, MODULE_NAME & ".AddNew", "Item already exists with that key: " & sCode
Exit Function
End If
Set oFabricant = New Fabricant
With oFabricant
.Code = sCode
.ArticleType = sArt
.Division = sDiv
.Devise = sDev
.GroupePrix = sGrp
End With
Add oFabricant
Set AddNew = oFabricant
End Function
Public Property Get Fabricant( _
ByVal sCode As String) As Variant
Set Fabricant = m_oCollection.Item(sCode)
End Property

VBA map implementation

I need good map class implementation in VBA.
This is my implementation for integer key
Box class:
Private key As Long 'Key, only positive digit
Private value As String 'Value, only
'Value getter
Public Function GetValue() As String
GetValue = value
End Function
'Value setter
Public Function setValue(pValue As String)
value = pValue
End Function
'Ket setter
Public Function setKey(pKey As Long)
Key = pKey
End Function
'Key getter
Public Function GetKey() As Long
GetKey = Key
End Function
Private Sub Class_Initialize()
End Sub
Private Sub Class_Terminate()
End Sub
Map class:
Private boxCollection As Collection
'Init
Private Sub Class_Initialize()
Set boxCollection = New Collection
End Sub
'Destroy
Private Sub Class_Terminate()
Set boxCollection = Nothing
End Sub
'Add element(Box) to collection
Public Function Add(Key As Long, value As String)
If (Key > 0) And (containsKey(Key) Is Nothing) Then
Dim aBox As New Box
With aBox
.setKey (Key)
.setValue (value)
End With
boxCollection.Add aBox
Else
MsgBox ("В словаре уже содержится элемент с ключем " + CStr(Key))
End If
End Function
'Get key by value or -1
Public Function GetKey(value As String) As Long
Dim gkBox As Box
Set gkBox = containsValue(value)
If gkBox Is Nothing Then
GetKey = -1
Else
GetKey = gkBox.GetKey
End If
End Function
'Get value by key or message
Public Function GetValue(Key As Long) As String
Dim gvBox As Box
Set gvBox = containsKey(Key)
If gvBox Is Nothing Then
MsgBox ("Key " + CStr(Key) + " dont exist")
Else
GetValue = gvBox.GetValue
End If
End Function
'Remove element from collection
Public Function Remove(Key As Long)
Dim index As Long
index = getIndex(Key)
If index > 0 Then
boxCollection.Remove (index)
End If
End Function
'Get count of element in collection
Public Function GetCount() As Long
GetCount = boxCollection.Count
End Function
'Get object by key
Private Function containsKey(Key As Long) As Box
If boxCollection.Count > 0 Then
Dim i As Long
For i = 1 To boxCollection.Count
Dim fBox As Box
Set fBox = boxCollection.Item(i)
If fBox.GetKey = Key Then Set containsKey = fBox
Next i
End If
End Function
'Get object by value
Private Function containsValue(value As String) As Box
If boxCollection.Count > 0 Then
Dim i As Long
For i = 1 To boxCollection.Count
Dim fBox As Box
Set fBox = boxCollection.Item(i)
If fBox.GetValue = value Then Set containsValue = fBox
Next i
End If
End Function
'Get element index by key
Private Function getIndex(Key As Long) As Long
getIndex = -1
If boxCollection.Count > 0 Then
For i = 1 To boxCollection.Count
Dim fBox As Box
Set fBox = boxCollection.Item(i)
If fBox.GetKey = Key Then getIndex = i
Next i
End If
End Function
All ok if i insert 1000 pairs key-value. But if 50000, a program freezes.
How i can solve this problem? Or maybe there more better solution?
Main problem with your implementation is that the operation containsKey is quite expensive (O(n) complex) and it is called at every insert and it never breaks even when it "knows" what would be the result.
This might help a little:
...
If fBox.GetKey = Key Then
Set containsKey = fBox
Exit Function
End If
...
In order to reduce the containsKey complexity typical things to do would be
keep the keys sorted so that you can use binary search instead of linear search
keep the keys in tree or in a hashed buckets
The most straightforward thing to do would be using the Collection's built-in (hopefully optimized) ability to store/retrieve items by a key.
Store:
...
boxCollection.Add Item := aBox, Key := CStr(Key)
...
Retrieve (not tested, based on this answer):
Private Function containsKey(Key As Long) As Box
On Error GoTo err
Set containsKey = boxCollection.Item(CStr(Key))
Exit Function
err:
Set containsKey = Nothing
End Function
See also:
MSDN: How to: Add, Delete, and Retrieve Items of a Collection (Visual Basic)
Stack Overflow: Does VBA have Dictionary Structure?
Newton Excel Bach: Arrays vs Collections vs Dictionary Objects (and Dictionary help)

Application-defined or object-defined error (VBA)

I keep getting the annoying error message: Application-defined or object-defined error (VBA).
Background: I have a worksheet that contains rows and columns (some rows & columns are merged), I have a button on the worksheet that I would like to use to validate the worksheet e.g. to report any errors if a cell is not filled in i.e. empty. In additions, I would like empty cells to become red when the button is clicked on an a particular range of cells contain no values.
I created a VBA Bean to hold all rows of data that are pulled from the worksheet. This class will contain procedures and/or functions that validate the class and hopefully report back to the user any errors encountered. The button calls the print_cheque_Click() (worksheet code below). Any suggestions here would be much appreciated. Thanks in advance.
line where error is occurring: Range(cCel).Interior.Color = RGB(255, 0, 0)
error
Public Sub validate()
Dim str As String
Dim cCel As String
Dim WS As Worksheet
Set WS = Worksheets("EFF_PAYROLL")
WS.Select
With Selection
If Me.getJournalYear = "" Then
cCel = Me.getJournalYearCell
**Range(cCel).Interior.Color = RGB(255, 0, 0)**
Else
**Range(cCel).Interior.Color = RGB(255, 255, 255)**
End If
End With
End Sub
class employee
Option Explicit
'****************************
'class definition of Employee
'VBA Bean
'****************************
'******************
'private Attributes
'******************
Private eID As Integer
Private jYear As String
Private jYearCell As String
Private eRegion As String
Private eRegionCell As String
Private eDistrict As String
Private eDistrictCell As String
Private eJournalNumber As String
Private eJournalNumberCell As String
Private eName As String
Private eNameCell As String
Private class_code As String
Private class_codeCell As String
Private hourly_rate As String
Private hourly_rateCell As String
Private eCertNumber As String
Private eCertNumberCell As String
Private eRegRate As String
Private eRegRateCell As String
Private eRegHours As String
Private eRegHoursCell As String
Private eOvertimeRate As String
Private eOvertimeRateCell As String
Private eOvertimeHours As String
Private eOvertimeHoursCell As String
Private eRegTotal As String
Private eRegTotalCell As String
Private eOvertimeTotal As String
Private eOvertimeTotalCell As String
Private eVacationTotal As String
Private eVacactionTotalCell As String
Private eTotalPay As String
Private eTotalPayCell As String
Private eCommissary As String
Private eCommissaryCell As String
Private eTotalCommissary As String
Private eTotalCommissaryCell As String
Private eNetPay As String
Private eNetPayCell As String
Private eDay As String
Private eDayCell As String
Private eMonth As String
Private eMonthCell As String
Private eYear As String
Private eYearCell As String
Private eChequeNo As String
Private eChequeNoCell As String
Private eAddress1 As String
Private eAddress1Cell As String
Private eAddress2 As String
Private eAddress2Cell As String
Private eAuthorizedOfficer As String
Private eAuthorizedOfficerCell As String
Private ePrintedName As String
Private ePrintedNameCell As String
Private ePreparedBy As String
Private ePreparedByCell As String
'***************
'Get/Set Methods
'***************
'*******************************************
'eID section
Public Property Get getID() As String
getID = eID
End Property
Public Property Let setID(value As String)
setID = value
End Property
'END eID section
'*******************************************
'journal year
Public Property Get getJournalYear() As String
getJournalYear = jYear
End Property
Public Property Let setJournalYear(value As String)
jYear = value
End Property
'end journal year
'setJournalYearCell
Public Property Get getJournalYearCell() As String
getJournalYearCell = jYearCell
End Property
Public Property Let setJournalYearCell(value As String)
jYearCell = value
End Property
'end setJournalYearCell
'class code
Public Property Get getClassCode() As String
getClassCode = class_code
End Property
Public Property Let setClassCode(value As String)
class_code = value
End Property
'end class code
'class code cell
Public Property Get getClassCodeCell() As String
getClassCodeCell = class_codeCell
End Property
Public Property Let setClassCodeCell(value As String)
class_codeCell = value
End Property
'end class code code cell
'hourly rate
Public Property Get getHourlyRate() As String
getHourlyRate = hourly_rate
End Property
Public Property Let setHourlyRate(value As String)
hourly_rate = value
End Property
'end hourly rate
'hourly rate cell
Public Property Get getHourlyRatCell() As String
getHourlyRateCell = hourly_rateCell
End Property
Public Property Let setHourlyRateCell(value As String)
hourly_rateCell = value
End Property
'end hourly rate cell
'chequeNo
Public Property Get getChequeNo() As String
getChequeNo = eChequeNo
End Property
Public Property Let setchequeNo(value As String)
eChequeNo = value
End Property
'end chequeNo
'chequeNoCell
Public Property Get getChequeNoCell() As String
getChequeNoCell = eChequeNoCell
End Property
Public Property Let setChequeNoCell(value As String)
eChequeNoCell = value
End Property
'end chequeCell
'prepredBy
Public Property Get getPreparedBy() As String
getPreparedBy = ePreparedBy
End Property
Public Property Let setPreparedBy(value As String)
ePreparedBy = value
End Property
'end preparedBy
'preparedByCell
Public Property Get getPreparedByCell() As String
getPreparedByCell = ePreparedByCell
End Property
Public Property Let setPreparedByCell(value As String)
ePreparedByCell = value
End Property
'end preparedByCell
'region
Public Property Get getRegion() As String
getRegion = eRegion
End Property
Public Property Let setRegion(value As String)
eRegion = value
End Property
'end region
'regionCell
Public Property Get getRegionCell() As String
getRegionCell = eRegionCell
End Property
Public Property Let setRegionCell(value As String)
eRegionCell = value
End Property
'end regionCell
'BEGIN
'district
Public Property Get getDistrict() As String
getDistrict = eDistrict
End Property
Public Property Let setDistrict(value As String)
eDistrict = value
End Property
'end district
'districtCell
Public Property Get getDistrictCell() As String
getDistrictCell = eDistrictCell
End Property
Public Property Let setDistrictCell(value As String)
eDistrictCell = value
End Property
'end districtCell
'eYear section
Public Property Get getYear() As String
getYear = eYear
End Property
Public Property Let setYear(value As String)
eYear = value
End Property
'END eYear Section
'eYearCell
Public Property Get getEYearCell() As String
getEYearCell = eYearCell
End Property
Public Property Let setEYearCell(value As String)
eYearCell = value
End Property
'end eYearCell
'eMonth section
Public Property Get getMonth() As String
getMonth = eMonth
End Property
Public Property Let setMonth(value As String)
eMonth = value
End Property
'END eMonth Section
'eMonthCell
Public Property Get getEMonthCell() As String
getEMonthCell = eMonthCell
End Property
Public Property Let setEMonthCell(value As String)
eMonthCell = value
End Property
'end eMonthCell
'eDay section
Public Property Get getDay() As String
getDay = eDay
End Property
Public Property Let setDay(value As String)
eDay = value
End Property
'END eDay Section
'eDayCell
Public Property Get getEDayCell() As String
getEDayCell = eDayCell
End Property
Public Property Let setEDayCell(value As String)
eDayCell = value
End Property
'end eDayCell
'eJournalNumber section
Public Property Get getJournalNumber() As String
getJournalNumber = eJournalNumber
End Property
Public Property Let setJournalNumber(value As String)
eJournalNumber = value
End Property
'end journal number
'eJournalNumberCell
Public Property Get getJournalNumberCell() As String
getJournalNumberCell = eJournalNumberCell
End Property
Public Property Let setJournalNumberCell(value As String)
eJournalNumberCell = value
End Property
'end eJournalNumberCell
'eName Section
Public Property Get getName() As String
getName = eName
End Property
Public Property Let setName(value As String)
eName = value
End Property
'END eName section
'eNameCell
Public Property Get getNameCell() As String
getNameCell = eNameCell
End Property
Public Property Let setNameCell(value As String)
eNameCell = value
End Property
'end eNameCell
'address1
Public Property Get getAddress1() As String
getAddress1 = eAddress1
End Property
Public Property Let setAddress1(value As String)
eAddress1 = value
End Property
'end address1
'adress1Cell
Public Property Get getAddress1Cell() As String
getAddress1Cell = eAddress1Cell
End Property
Public Property Let setAAddress1Cell(value As String)
eAddress1Cell = value
End Property
'end address1Cell
'address2
Public Property Get getAddress2() As String
getAddress2 = eAddress2
End Property
Public Property Let setAddress2(value As String)
eAddress2 = value
End Property
'end address2
'address2Cell
Public Property Get getAddress2Cell() As String
getAddress2Cell = eAddress2
End Property
Public Property Let setAddress2cell(value As String)
eAddress2Cell = value
End Property
'end address2Cell
'certNumber
Public Property Get getCertNumber() As String
getCertNumber = eCertNumber
End Property
Public Property Let setCertNumber(value As String)
eCertNumber = value
End Property
'end certNumber
'certNumberCell
Public Property Get getCertNumberCell() As String
getCertNumberCell = eCertNumberCell
End Property
Public Property Let setCertNumberCell(value As String)
eCertNumberCell = value
End Property
'end CertNumberCell
'regRate
Public Property Get getRegRate() As String
getRegRate = eRegRate
End Property
Public Property Let setRegRate(value As String)
eRegRate = value
End Property
'end regRate
'regRateCell
Public Property Get getRegRateCell() As String
getRegRateCell = eRegRateCell
End Property
Public Property Let setRegRateCell(value As String)
eRegRateCell = value
End Property
'end regRateCell
'regHours
Public Property Get getRegHours() As String
getRegHours = eRegHours
End Property
Public Property Let setRegHours(value As String)
eRegHours = value
End Property
'end regHours
'regHoursCell
Public Property Get getRegHoursCell() As String
getRegHours = eRegHoursCell
End Property
Public Property Let setRegHoursCell(value As String)
eRegHoursCell = value
End Property
'end regHoursCell
'overtimeRate
Public Property Get getOvertimeRate() As String
getOvertimeRate = eOvertimeRate
End Property
Public Property Let setOvertimeRate(value As String)
eOvertimeRate = value
End Property
'end overtimeRate
'overtimeRateCell
Public Property Get getOvertimeRateCell() As String
getOvertimeRateCell = eOvertimeRateCell
End Property
'end
Public Property Let setOvertimeRateCell(value As String)
eOvertimeRateCell = value
End Property
'end overtimeRateCell
'overtimeHours
Public Property Get getOvertimeHours() As String
getOvertimeHours = eOvertimeHours
End Property
Public Property Let setOvertimeHours(value As String)
eOvertimeHours = value
End Property
'end overtimeHours
'overtimeHoursCell
Public Property Get getOvertimeHoursCell() As String
getOvertimeHoursCell = eOvertimeHoursCell
End Property
Public Property Let setOvertimeHoursCell(value As String)
eOvertimeHoursCell = value
End Property
'end overtimeHoursCell
'regTotal
Public Property Get getRegTotal() As String
getRegTotal = eRegTotal
End Property
Public Property Let setRegTotal(value As String)
eRegTotal = value
End Property
'end regTotal
'regTotalCell
Public Property Get getRegTotalCell() As String
getRegTotalCell = eRegTotalCell
End Property
Public Property Let setRegTotalCell(value As String)
eRegTotalCell = value
End Property
'end regTotalCell
'overtimeTotal
Public Property Get getOvertimeTotal() As String
getOvertimeTotal = eOvertimeTotal
End Property
Public Property Let setOvertimeTotal(value As String)
eOvertimeTotal = value
End Property
'end overtimeTotal
'overtimeTotalCell
Public Property Get getOvertimeTotalCell() As String
getOvertimeTotalCell = eOvertimeTotalCell
End Property
Public Property Let setOvertimeTotalCell(value As String)
eOvertimeTotalCell = value
End Property
'end overtimeTotalCell
'vacationTotal
Public Property Get getVacationTotal() As String
getVacationTotal = eVacationTotal
End Property
Public Property Let setVacationTotal(value As String)
eVacationTotal = value
End Property
'end vacationTotal
'vacationTotalCell
Public Property Get getVacationTotalCell() As String
getVacationTotalCell = eVacationTotalCell
End Property
Public Property Let setVacationTotalCell(value As String)
eVacationTotalCell = value
End Property
'end vacationTotalCell
'totalPay
Public Property Get getTotalPay() As String
getTotalPay = eTotalPay
End Property
Public Property Let setTotalPay(value As String)
eTotalPay = value
End Property
'end totalPay
'totalPayCell
Public Property Get getTotalPayCell() As String
getTotalPayCell = eTotalPayCell
End Property
Public Property Let setTotalPayCell(value As String)
eTotalPayCell = value
End Property
'end totalPayCell
'revisit
'************ buffer issue ? ********************
'commissary
Public Property Get getCommissary() As String
getCommissary = eCommissary
End Property
Public Property Let setCommissary(value As String)
eCommissary = value
End Property
'end commissary
'commissary
Public Property Get getCommissaryCell() As String
getCommissaryCell = eCommissaryCell
End Property
Public Property Let setCommissaryCell(value As String)
eCommissaryCell = value
End Property
'end commissary
'totalCommissary
Public Property Get getTotalCommissary() As String
getTotalCommissary = eTotalCommissary
End Property
Public Property Let setTotalCommissary(value As String)
eTotalCommissary = value
End Property
'end totalCommissary
'totalCommissaryCell
Public Property Get getTotalCommissaryCell() As String
getTotalCommissaryCell = eTotalCommissary
End Property
Public Property Let setTotalCommissaryCell(value As String)
eTotalCommissaryCell = value
End Property
'end totalCommissaryCell
'netPay
Public Property Get getNetPay() As String
getNetPay = eNetPay
End Property
Public Property Let setNetPay(value As String)
eNetPay = value
End Property
'end netPay
'netPayCell
Public Property Get getNetPayCell() As String
getNetPayCell = eNetPayCell
End Property
Public Property Let setNetPayCell(value As String)
eNetPayCell = value
End Property
'end netPayCell
'authorizedOfficer
Public Property Get getAuthorizedOfficer() As String
getAuthorizedOfficer = eAuthorizedOfficer
End Property
Public Property Let setAuthorizedOfficer(value As String)
eAuthorizedOfficer = value
End Property
'end authorizedOfficer
'authorizedOfficerCell
Public Property Get getAuthorizedOfficerCell() As String
getAuthorizedOfficerCelll = eAuthorizedOfficerCell
End Property
Public Property Let setAuthorizedOfficerCell(value As String)
eAuthorizedOfficerCell = value
End Property
'end authorizedOfficer
'printedName
Public Property Get getPrintedName() As String
getPrintedName = ePrintedName
End Property
Public Property Let setPrintedName(value As String)
ePrintedName = value
End Property
'end printedName
'printedNameCell
Public Property Get getPrintedNameCell() As String
getPrintedNameCell = ePrintedNameCell
End Property
Public Property Let setPritnedNameCell(value As String)
ePrintedNameCell = value
End Property
'end printedNameCell
'***************
'Procedure / Function
'***************
Public Sub validate()
Dim str As String
Dim cCel As String
Dim WS As Worksheet
Set WS = Worksheets("EFF_PAYROLL")
WS.Select
With Selection
If Me.getJournalYear = "" Then
cCel = Me.getJournalYearCell
Range(cCel).Interior.Color = RGB(255, 0, 0)
Else
Range(cCel).Interior.Color = RGB(255, 255, 255)
End If
End With
End Sub
'constructor
Private Sub Class_Initialize()
'assign an ID to each new employee object
eID = eID + 1
End Sub
'end constructor
worksheet code
Private Sub print_cheque_Click()
Dim template As Worksheet
Dim rng As Range
Dim journal As Range
Dim iReply As Integer
Dim row As Range
Dim cell As Range
Dim employeeCollection As Collection
Set employeeCollection = New Collection
'EFF_PAYROLL fields
Dim dayStr As String
Dim monthStr As String
'boolean flag - if error is raised don't print cheque
Dim errorFlag As Boolean
errorFlag = True 'raise error if no fields are filled in
Dim str As String
'*************************
'work with Employee Object
'*************************
'find the number of cheques to be created by cheque number
Set rng = Sheets("EFF_PAYROLL").Range("a7:a35")
'define employee object
Dim emp As employee
'********local variables **********
'**********************************
Dim year As String
Dim cell_address As String
Dim name As String
For Each row In rng.Rows
'create new employee foreach row
Set emp = New employee
For Each cell In row.Cells
'++++++++++++++++++++++++++++++++++++
'grab all values from payroll_journal
'populate VBA Bean - Employee Type
'++++++++++++++++++++++++++++++++++++
'*** header info *******************************************
emp.setJournalYear = Sheets("EFF_PAYROLL").Range("O3").value
emp.setJournalYearCell = "O3"
emp.setRegion = Sheets("EFF_PAYROLL").Range("P3").value
emp.setRegionCell = "P3"
emp.setDistrict = Sheets("EFF_PAYROLL").Range("Q3").value
emp.setDistrictCell = "Q3"
emp.setJournalNumber = Sheets("EFF_PAYROLL").Range("R3").value
emp.setJournalNumberCell = "R3"
'*** end header info *****************************************
'*** employee line item **************************************
emp.setName = cell.value
emp.setNameCell = cell.Address
emp.setClassCode = cell.Offset(0, 1)
emp.setClassCodeCell = cell.Offset(0, 1).Address
emp.setHourlyRate = cell.Offset(0, 2)
emp.setHourlyRateCell = cell.Offset(0, 2).Address
emp.setCertNumber = cell.Offset(0, 3)
emp.setCertNumberCell = cell.Offset(0, 3).Address
emp.setCommissary = cell.Offset(0, 46)
emp.setCommissaryCell = cell.Offset(0, 46).Address
emp.setTotalCommissary = cell.Offset(0, 46)
emp.setTotalCommissaryCell = cell.Offset(0, 46).Address
emp.setDay = cell.Offset(0, 51)
emp.setEDayCell = cell.Offset(0, 51).Address
emp.setMonth = cell.Offset(0, 52)
emp.setEMonthCell = cell.Offset(0, 52).Address
emp.setYear = cell.Offset(0, 53)
emp.setEYearCell = cell.Offset(0, 52).Address
emp.setchequeNo = cell.Offset(0, 54)
emp.setChequeNoCell = cell.Offset(0, 54).Address
emp.setAddress1 = cell.Offset(0, 57)
emp.setAAddress1Cell = cell.Offset(0, 57).Address
emp.setAddress2 = cell.Offset(1, 57)
emp.setAddress2cell = cell.Offset(1, 57).Address
'*** end employee line item *********************************
'*************footer info ***********************************
emp.setPreparedBy = Sheets("EFF_PAYROLL").Range("J39").value
emp.setPreparedByCell = Sheets("EFF_PAYROLL").Range("J39").Address
emp.setAuthorizedOfficer = Sheets("EFF_PAYROLL").Range("AE39").value
emp.setAuthorizedOfficerCell = Sheets("EFF_PAYROLL").Range("AE39").Address
emp.setPrintedName = Sheets("EFF_PAYROLL").Range("AD44").value
emp.setPritnedNameCell = Sheets("EFF_PAYROLL").Range("AD44").Address
'*************end footer info *******************************
employeeCollection.Add emp
' For Each emp In employeeCollection
' Debug.Print emp.getID & " " & emp.getName _
' ; vbCrLf & emp.getClassCode & " " _
' ; emp.getClassCodeCell
'
'
' Next emp
'
'
' Debug.Print employeeCollection.Count
'
'++++++++++++++++++++++++++++++++++++++
'END fetch of data from payroll_journal
'++++++++++++++++++++++++++++++++++++++
' If Not IsEmpty(cell.value) And errorFlag = False Then
'
'
'
' 'unprotect worksheets during writing process
' unProtectWS ("Cheque Template")
'
' ' unprotect workbook
' ActiveWorkbook.Unprotect ("***")
'
'
' Sheets("Cheque Template").Copy After:=Sheets(Sheets.Count)
' ActiveSheet.name = emp.name
'
'
'
'
' '******
' '** populate cheque with corresponding values - cell.Value
' '******
' 'Sheets(employee_name).Range("B7").Value = employee_name
' Sheets(emp.name).Range("B7").value = emp.name
'
'
' Sheets(emp.name).Range("D4").value = dayStr
' Sheets(emp.name).Range("C4").value = monthStr
' Sheets(emp.name).Range("B4").value = emp.year
' Sheets(emp.name).Range("H8").value = emp.certNumber
'
' Sheets(emp.name).Range("B8").value = emp.address1
' Sheets(emp.name).Range("B9").value = emp.address2
'
' 'journal number
' Sheets(emp.name).Range("H4").value = emp.year
' Sheets(emp.name).Range("I4").value = emp.region
' Sheets(emp.name).Range("J4").value = emp.district
' Sheets(emp.name).Range("K4").value = emp.journalNumber
' 'end journal number
'
' Sheets(emp.name).Range("B14").value = emp.regRate
' Sheets(emp.name).Range("F14").value = emp.regHours
'
' 'overtime hours and rate
' Sheets(emp.name).Range("B16").value = emp.overtimeRate
' Sheets(emp.name).Range("F16").value = emp.overtimeHours
' 'END overtime hours and rate
'
' Sheets(emp.name).Range("H14").value = emp.regTotal
' Sheets(emp.name).Range("H16").value = emp.overtimeTotal
' Sheets(emp.name).Range("B24").value = emp.commissary
' Sheets(emp.name).Range("H24").value = emp.totalCommissary
' Sheets(emp.name).Range("H18").value = emp.vacationTotal
' Sheets(emp.name).Range("H20").value = emp.totalPay
' Sheets(emp.name).Range("H29").value = emp.netPay
'
' 'cheque printout (bottom)
' Sheets(emp.name).Range("B47").value = emp.name
' Sheets(emp.name).Range("B48").value = emp.address1
' Sheets(emp.name).Range("B49").value = emp.address2
' Sheets(emp.name).Range("B43").value = Module3.SpellNumber(emp.netPay)
' Sheets(emp.name).Range("K45").value = Round(emp.netPay, 2)
'
' 'month and str on cheque portion
' Sheets(emp.name).Range("K40").value = emp.year & "/" & monthStr & "/" & dayStr
'
' 'printed name aka persons that approves cheque
' Sheets(emp.name).Range("J51").value = emp.printedName
'
'
'
'
'
'
' 'For Each emp In employeeCollection
' ' Perform validation on that employee
' ' Debug.Print emp.Name
' 'Next emp
'
'
'
'
'
'
'
'
'
'
' 'Module6.printWorksheet (emp.name)
' 'Module6.deleteWorksheet (emp.name)
'
'
'
' 'protect/lock cheque template before closing
'
' 'protectWS ("EFF_PAYROLL")
' protectWS ("Cheque Template")
'
' 'protect/lock workbook before closing
' ActiveWorkbook.Protect ("***")
'
' 'add employee to collection - used for later use
' 'employeeCollection.Add emp
'
'
' 'MsgBox "Cheque(s) will be printed."
'
'
' End If
Next cell
Next row
emp.validate
Exit Sub
End Sub
I notice in your code you have some lines commented out that previously appeared to have protected/unprotected the worksheet. If the sheet is still in a protected state, you will not be able to do this operation, and it will raise the 1004 error.
Solution
Unprotect the sheet (manually or via code) before formatting the cell.
OR, in the protection dialog, ensure that users are allowed to format cells:

Accessing data from collection VBA

I'm trying to access data from collection by using .item(). What I am trying to do is to collect data in collection function fncPopCcyLst and access it by .item(1) in cbSortCcy to get the row number. This is a test to see if I can store several data in my collection and access them via .item(). However, I get a VBA runtime error '5'. Will someone guide me kindly what I am doing wrong? Thank you.
Below are my codes.
Class Module: clsSngGenUtl
Private prpSngStrVal As String
Private prpSngRowNum As Long
Private prpSngClmNum As Long
'++ Define properties
'== String row number
Public Property Get SngStrVal() As String
SngStrVal = prpSngStrVal
End Property
Public Property Let SngStrVal(ByRef varStrVal As String)
prpSngStrVal = varStrVal
End Property
'++ Define properties
'== Scalar row number
Public Property Get SngRowNum() As Long
SngRowNum = prpSngRowNum
End Property
Public Property Let SngRowNum(ByVal varRowNum As Long)
prpSngRowNum = varRowNum
End Property
'++ Define properties
'== Single column number
Public Property Get SngClmNum() As Long
SngClmNum = prpSngClmNum
End Property
Public Property Let SngClmNum(ByRef varClmNum As Long)
prpSngClmNum = varClmNum
End Property
'++ Define functions
'== function get row number
Public Function fncGetRowNum(ByRef varWbName As Workbook, ByVal varWsName As String, ByRef varSttClm As Long) As Long
On Error GoTo Exception
prpSngRowNum = 0
prpSngRowNum = varWbName.Sheets(Trim(varWsName)).Cells(Rows.Count, varSttClm).End(xlUp).Row
fncGetRowNum = prpSngRowNum
ExitHere:
Exit Function
Exception:
Resume ExitHere
End Function
'== function get column number
Public Function fncGetClmNum(ByRef varWbName As Workbook, ByVal varWsName As String, ByRef varSttRow As Long) As Long
On Error GoTo Exception
prpSngClmNum = 0
prpSngClmNum = varWbName.Sheets(Trim(varWsName)).Cells(varSttRow, Columns.Count).End(xlToLeft).Column
fncGetClmNum = prpSngClmNum
ExitHere:
Exit Function
Exception:
Resume ExitHere
End Function`
Below is my collection class: clsColCcySrt
'++ Declare variables
Private prpColCcySrt As Collection
'++ Define properties
Public Property Get ColCcySrt() As Collection
Set ColCcySrt = prpColCcySrt
End Property
Public Property Set ColCcySrt(varColCcy As Collection)
Set prpColCcySrt = varColCcy
End Property
Public Function fncGetCcyRow(ByRef varStrVal As String) As Long
On Error GoTo Exception
Dim clsSngGen As clsSngGenUtl
Dim varRowNum As Long
varRowNum = 0
For Each clsSngGen In Me.ColCcySrt
varRowNum = clsSngGen.SngRowNum()
Next clsSngGen
'== Return value
fncGetCcyRow = varRowNum
ExitHere:
Exit Function
Exception:
If fncGetCcyRow = 0 Then
MsgBox "Exception: Value is <" & fncGetCcyRow & ">."
End If
Resume ExitHere
End Function
`
"Regular" Module to populate array: fncPopFxLst
`
Public Function fncPopCcyLst(ByRef varWbName As String, ByRef varWsName As String, ByRef varCcyTyp As String) As Collection
Dim clnColCcy As Collection
Dim clsArrGen As clsArrGenUtl
Dim clsSngGen As clsSngGenUtl
Dim varWbName As Workbook
Set clnColCcy = New Collection
'== Start collecting items
Set clsSngGen = New clsSngGenUtl
Set varWbName = ThisWorkbook
clsSngGen.SngStrVal = "Reuters"
clsSngGen.SngRowNum = clsSngGen.fncGetRowNum(varWbName, varWsName, 1)
clnColCcy.Add clsSngGen
Set fncPopCcyLst = clnColCcy
End Function
`
Lastly, the subroutine `
Private Sub cbSortCcy()
Dim clsColCcy As clsColCcySrt
Dim varDirPth As String
Dim varCcySrc As String
Dim varWsStrg As String
Dim varWbStrg As String
varDirPth = tbDirectoryName & "\" & tbFileName
varCcySrc = "Currency"
varWsStrg = "List"
varWbStrg = varDirPth
Set clsColCcy = New clsColCcySrt
Set clsColCcy.ColCcySrt = fncPopCcyLst(varWbStrg, varWsStrg, varCcySrc)
'Debug.Princ clsColCcy.fncGetCcyRow("Reuters")
Debug.Print clsColCcy.ColCcySrt.Item(1)
End Sub
`
VBA Run-time error '5' is:
"Invalid procedure call or argument"
In your class clsColCcySrt, you have a line:
varRowNum = clsSngGen.SngRowNum()
which would be correct if SngRowNum were a function and not a property. Remove the parentheses () to call the property.