简体   繁体   中英

using classes to work with multiple ranges in excel vba

There are a couple of very good ansewers on the mechanics of using smple classes in VBA: When to use a Class in VBA? and What are the benefits of using Classes in VBA?

As someone relativley new to OOP and classes, it's hard to know how to implement them, or what is even really possible.

For example, I have to deal with large ranges in multiple sheets and I need to get at many different subsets of the data. "agents who does x" and "clients who have y"...etc. Here's a sub i put together to get at the number of agents who have more than 2 clients:

Sub agent_subset(output_sheet As String, _
                                    Input_sheet_name As String, _
                                    email_col As Integer, _
                                    vendor_count_col As Integer, _
                                    client_count_col As Integer, _
                                    modified_col As Integer, _
                                    num_of_clients As Integer)
'  get a list of all agents with 2 or more clients and put them into a sheet

    Application.DisplayStatusBar = True

    Dim sheet_rows As Long
    sheet_rows = Worksheets(Input_sheet_name).Cells(rows.Count, 1).End(xlUp).Row

    Dim email_range As Range ' range of agent emails
    Dim client_count_range As Range ' range of client count
    Dim vendor_count_range As Range ' range of vendor count
    Dim modified_range As Range ' range of modified at

    With Worksheets(Input_sheet_name)
        Set email_range = .Range(.Cells(2, email_col), .Cells(sheet_rows, email_col))
        Set client_count_range = .Range(.Cells(2, client_count_col), .Cells(sheet_rows, client_count_col))
        Set vendor_count_range = .Range(.Cells(2, vendor_count_col), .Cells(sheet_rows, vendor_count_col))
        Set modified_range = .Range(.Cells(2, modified_col), .Cells(sheet_rows, modified_col))
    End With

    Dim n As Long
    Dim counter As Long
    counter = 0

    Dim modified_array() As String

    For n = 2 To sheet_rows
        If client_count_range(n, 1).Value > num_of_clients Then
            counter = counter + 1
            Worksheets(output_sheet).Cells(counter + 1, 1).Value = email_range(n, 1).Value
            Worksheets(output_sheet).Cells(counter + 1, 2).Value = client_count_range(n, 1).Value
            Worksheets(output_sheet).Cells(counter + 1, 3).Value = vendor_count_range(n, 1).Value
                modified_array() = Split(modified_range(n, 1).Value, "T")
            Worksheets(output_sheet).Cells(counter + 1, 4).Value = modified_array(0)
        End If

         Application.StatusBar = "Loop status: " & n & "of " & sheet_rows

    Next n

Worksheets(output_sheet).Cells(counter + 3, 1).Value = "Last run was " & Now()

Application.StatusBar = False

End Sub

It works great, but now I want to get a an even smaller subset of agents and clients based on other criteria. So, I'm going to write a similar function, manipulating similar data. My gut tells me using classes will make my life easier, but I don't know how to chop up the tasks.

Should there be an Agent class that has all the info about agents? and/or a client class? Or, should the classes be for looking at entire ranges or sheets?

I'm not looking for specific code, but a methodology on how to break things down.

I have to deal with large ranges in multiple sheets

If you think in terms of computers, you're code will be very functional. Those ranges represent something real (an agent, a customer, an invoice, a transaction), so think in those terms.

I would have an Agent class that held all the properties of an agent. I would have an Agents collection class that held all my Agent classes. Then, in my Agents class, I would have Filter methods that return subsets of the Agents class.

Here's an example: I have customers. Customers can be Active or not. Customers also have a template that I use when I email them certain information. When I want to email active customers who use the Table1 template, it looks like this

Set clsCustomersToEmail = clsCustomers.FilterOnActive(True).FilterOnTemplate("Table1")
For Each clsCustomer in clsCustomersToEmail
    'Do stuff
Next clsCustomer`

In my CCustomers collection class, I have a couple of properties that return a CCustomers class with few customers than the big CCustomers class (called clsCustomers)

Public Property Get FilterOnActive() As CCustomers

    Dim clsReturn As CCustomers
    Dim clsCustomer As CCustomer

    Set clsReturn = New CCustomers

    For Each clsCustomer In Me
        If clsCustomer.Active Then
            clsReturn.Add clsCustomer
        End If
    Next clsCustomer

    Set FilterOnActive = clsReturn

End Property
Public Property Get FilterOnTemplate(ByVal sTemplate As String) As CCustomers

    Dim clsReturn As CCustomers
    Dim clsCustomer As CCustomer

    Set clsReturn = New CCustomers

    For Each clsCustomer In Me
        If clsCustomer.Template.TemplateName = sTemplate Then
            clsReturn.Add clsCustomer
        End If
    Next clsCustomer

    Set FilterOnTemplate = clsReturn

End Property

When I want to do stuff like write a bunch of customer data to a range, I make a property that returns an array, and write the array to the range.

Set clsCustomersPastDue = clsCustomers.FilterOnActive(True).FilterOnPastDue(True)
vaWrite = clsCsutomerPastDue.AgingReport
rCell.Resize(UBound(vaWrite,1),UBound(vaWrite,2)).Value = vaWrite

I tend to think of what physical things am I coding. They don't have to be tangible things, but if you can take it back to something that's tangible, that can be helpful.

A transaction is a thing. But if that transaction is an invoice, now determine the properties of that object become easy. For one, you can just look at a paper invoice and see what the properties are.

The next level is relationships. Every Agent class has customers. So your Agent object should have a Customers property that returns a CCustomers class. Or if it's not structured that tightly in real life, maybe your CCustomers class has a FilterOnAgent property that returns the subset of customers you're looking for.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM