Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For Each Class Property in Excel VBA

I have some code that looks like this:

pos.Clutch = sh2.Cells(R, Clutch)
pos.Wiper = sh2.Cells(R, Wiper)
pos.Alternator = sh2.Cells(R, Alternator)
pos.Compressor = sh2.Cells(R, Compressor)
...
pos.Telephone = sh2.Cells(R, Telephone)
poss.Add pos

poss is a collection, and Clutch, Wiper etc. are column indexes (starting from 1). This currently works but is very ugly. I'm looking for a way to do something like this...

Do While i <= classProperty.count
    For each classProperty in pos
        classProperty = sh2.Cells(R + 1, i)
    Next classProperty
Loop

Obviously that wouldn't work but does anyone have any advice on how to make a method or collection within a class that would accomplish roughly the same?

like image 743
Al.Sal Avatar asked Jun 18 '13 20:06

Al.Sal


People also ask

How do you do a foreach loop in Excel VBA?

A For Each loop is used to execute a statement or a group of statements for each element in an array or collection. A For Each loop is similar to For Loop; however, the loop is executed for each element in an array or group. Hence, the step counter won't exist in this type of loop.

What is a property in Excel VBA?

A property is an attribute of an object that defines one of the object's characteristics, such as size, color, or screen location, or an aspect of its behavior, such as whether it is enabled or visible. To change the characteristics of an object, you change the values of its properties.


Video Answer


2 Answers

I don't know of a good way. The only reason it's ugly is because you haven't hidden it in a class yet. Take this procedure

Sub Main()

    Dim clsPos As CPos
    Dim clsPoses As CPoses

    Set clsPoses = New CPoses
    Set clsPos = New CPos

    clsPos.AddFromRange Sheet1.Range("A10:E10")
    clsPoses.Add clsPos

End Sub

Nothing ugly about that. Now the AddFromRange method is a little ugly, but you only have to look at that when you write it or when you're data changes.

Public Sub AddFromRange(ByRef rRng As Range)

    Dim vaValues As Variant

    vaValues = rRng.Rows(1).Value

    Me.Clutch = vaValues(1, 1)
    Me.Wiper = vaValues(1, 2)
    Me.Alternator = vaValues(1, 3)
    Me.Compressor = vaValues(1, 4)
    Me.Telephone = vaValues(1, 5)

End Sub

Update: Alternative method for eating an array instead of a Range.

Public Sub AddFromArray(vaValues as Variant)

    Me.Clutch = vaValues(1, 1)
    Me.Wiper = vaValues(1, 2)
    Me.Alternator = vaValues(1, 3)
    Me.Compressor = vaValues(1, 4)
    Me.Telephone = vaValues(1, 5)

End Sub
like image 118
Dick Kusleika Avatar answered Oct 19 '22 20:10

Dick Kusleika


As others have stated there is no direct way to loop through an object properties. I have a spreadsheet which stores many values which I need to read in at run time, similar to yours. The best method I have found to do this is by using the CallByName method which allows you set or get a property by name.

Now, some might say the initial set up is overkill, but I frequently add and remove these properties so doing likewise with code is even more hassle. So the beauty of this method is you can frequently modify your number of properties without having to change this code. You can use the awesome functions that make use of CallByName from here: https://stackoverflow.com/a/5707956/1733206

Then for your example, I would do the following in my poss collection (note this doesn't do any error checking etc which you may like to do):

Public Sub ReadInData()
    Dim vInputs As Variant, ii As Integer, jj As Integer, cp As pos
    Dim sPropertyName As String, vPropertyValue As Variant

    'Raead in the data.  I've set it from the activesheet, you can do it how you like
    With ActiveSheet
        vInputs = .Range(.Cells(1, 1), .Cells(.UsedRange.Rows.Count, .UsedRange.Columns.Count)).Value2
    End With

    'Look through the rows of data, one row per 'pos' object
    For ii = LBound(vInputs, 1) + 1 To UBound(vInputs, 1)

        'Set up your object
        Set cp = New pos

        'Loop through the columns of data eg Clutch, wiper, etc
        For jj = LBound(vInputs, 2) To UBound(vInputs, 2)
            'Put in seperate variables so its easy to see what's happening
            sPropertyName = vInputs(1, jj)
            vPropertyValue = vInputs(ii, jj)

            'Use the callable method to set the property (from here: https://stackoverflow.com/a/5707956/1733206)
            Call SetProperty(sPropertyName, vPropertyValue, cp)
        Next jj

        Me.Add cp
        Set cp = Nothing
    Next ii
End Sub

Here is an example in a workbook: https://dl.dropboxusercontent.com/u/13173101/VBAObject.xlsm

Edit: Since you will be changing the object often, I've included another module which is really handy and will actually write the pos class for you based on the column headings in your worksheet. That means if you add another column it will add those properties to the object! It assumes that all properties are strings but you can modify to suit.

like image 30
CuberChase Avatar answered Oct 19 '22 20:10

CuberChase