I have a flexgrid with a grouping, and a .subtotal by that grouping. All columns except one are numeric, the one that isn't is in the format 'x/y' e.g. '1/5', i.e. 1 out of 5 items supplied.
if I do a .Subtotal with a flexSTSum it sums up the first number in the pair, i.e. in the above example it would sum up the 1 as a decimal and show 1.00 in the subtotal row
At first I tried to find a way to sum on another column, i.e. I could put individual values into separate columns, give them a .Width of 0 and sum these into the .Subtotal column of the first column, but I can't find a way to do that.
And even if I do find a way to do that I want to be able to custom format the .Subtotal, so it appears as '3/17', i.e. '1/5' and '2/12' subtotal to '3/17' in the subtotal row.
if I can't subtotal off another column I wondered if I could custom access the subtotal row and manually enter the subtotal value of '3/17', but even that seems unavailable.
My question is, is there a way to achieve this?
I assume you are using the VideoSoft FlexGrid which i never used, so I can't help you with the specific methods of that control.
You can do it easily with a standard MSFlexGrid control though, and you can probably do the same with the VideoSoft FlexGrid.
Have a look at the following sample project:
'1 form with :
' 1 msflexgrid control : name=MSFlexGrid1
Option Explicit
Private Sub Form_Load()
Dim lngRow As Long, lngCol As Long
With MSFlexGrid1
.Rows = 10
.Cols = 4
.FixedRows = 0
.FixedCols = 0
For lngRow = 0 To .Rows - 2
For lngCol = 0 To .Cols - 2
.TextMatrix(lngRow, lngCol) = CStr(100 * lngRow + lngCol)
Next lngCol
.TextMatrix(lngRow, .Cols - 1) = CStr(lngRow) & "/" & CStr(lngRow * lngRow)
Next lngRow
End With 'MSFlexGrid1
End Sub
Private Sub Form_Resize()
MSFlexGrid1.Move 0, 0, ScaleWidth, ScaleHeight
End Sub
Private Sub MSFlexGrid1_Click()
Dim lngCol As Long
'calculate subtotals
With MSFlexGrid1
For lngCol = 0 To .Cols - 2
.TextMatrix(.Rows - 1, lngCol) = CStr(GetTotal(lngCol))
Next lngCol
.TextMatrix(.Rows - 1, .Cols - 1) = GetTotalSpecial(.Cols - 1)
End With 'MSFlexGrid1
End Sub
Private Function GetTotal(lngCol As Long) As Long
Dim lngRow As Long
Dim lngTotal As Long
With MSFlexGrid1
lngTotal = 0
For lngRow = 0 To .Rows - 2
lngTotal = lngTotal + Val(.TextMatrix(lngRow, lngCol))
Next lngRow
End With 'MSFlexGrid1
GetTotal = lngTotal
End Function
Private Function GetTotalSpecial(lngCol As Long) As String
Dim lngRow As Long
Dim lngTotal1 As Long, lngTotal2 As Long
Dim strPart() As String
With MSFlexGrid1
lngTotal1 = 0
lngTotal2 = 0
For lngRow = 0 To .Rows - 2
strPart = Split(.TextMatrix(lngRow, .Cols - 1), "/")
If UBound(strPart) = 1 Then
lngTotal1 = lngTotal1 + Val(strPart(0))
lngTotal2 = lngTotal2 + Val(strPart(1))
End If
Next lngRow
End With 'MSFlexGrid1
GetTotalSpecial = CStr(lngTotal1) & "/" & CStr(lngTotal2)
End Function
It will load a grid with some values, and when you click on the grid, the subtotals will be calculated and filled into the last row.
Related
I'm trying to write code that fill array in Function and than return result to main Sub. But this Function called from another Sub (sub-Sub). To understand how this will work I tried go step by step. And wrote this code:
Sub CATMain()
Dim val1
Call WalkDownTree() 'Here I call Sub to walk down Product Tree in CATIA
val1 = ParamTable(PartNumber, Name, Material, Texture, Color, Quantity)
For i=0 To UBound(val1)
MsgBox val1(i)
Next
End Sub
Sub WalkDownTree() 'Simplified code of the walk down tree to understand data transfer
PartNumber = "PartNumber"
Name = "Name"
Material = "Material"
Texture = "Texture"
Color = "Color"
Quantity = 1
Call ParamTable(PartNumber, Name, Material, Texture, Color, Quantity)
End Sub
Function ParamTable(PartNumber, Name, Material, Texture, Color, Quantity) 'Simplified array filing code. At original code I get all data from Part
Dim BOMTable(6,1000)
BOMTable(1,k) = PartNumber
BOMTable(2,k) = Name
BOMTable(3,k) = Material
BOMTable(4,k) = Texture
BOMTable(5,k) = Color
BOMTable(6,k) = 1
ParamTable = BOMTable
End Function
But I have error at line "MsgBox val1(i)": "Subscript out of range".
What did I miss?
And maybe exists more simple way to transfer array from Function to main Sub when Function fill from sub-Sub?
After some time I have a solution
This code works:
Dim PartNumber, Name, Material, Texture, Color, Quantity, k
Dim BOMTable(6,1000)
Sub CATMain()
Dim val1
Call WalkDownTree()
val1 = ParamTable(PartNumber, Name, Material, Texture, Color, Quantity, k)
For i = 1 To UBound(val1, 1)
For j = 1 To k-1
MsgBox val1(i,j)
Next
Next
End Sub
Sub WalkDownTree()
For k = 1 To 3
PartNumber = "PartNumber" & k
Name = "Name" & k
Material = "Material" & k
Texture = "Texture" & k
Color = "Color" & k
Quantity = 1
Call ParamTable(PartNumber, Name, Material, Texture, Color, Quantity, k)
Next
End Sub
Function ParamTable(PartNumber, Name, Material, Texture, Color, Quantity, k)
BOMTable(1,k) = PartNumber
BOMTable(2,k) = Name
BOMTable(3,k) = Material
BOMTable(4,k) = Texture
BOMTable(5,k) = Color
BOMTable(6,k) = Quantity
ParamTable = BOMTable
End Function
I would suggest not to be slacking in declaration of variables and even if it's not necessary for functioning. It is necessary for understanding.
The main global variable which holds all data should be declared on top
Option Explicit
Dim BOMData() As Variant
Then write the CATMain()
Sub CATMain()
Dim ItemCount As Integer 'This would be how many rows i will have in BOM or how many parts i will read i have to get this info from CATIA
ReDim BOMData(0 To ItemCount - 1, 0 To 5) As Variant 'This is making the collection
Dim Row As Integer
Dim Col As Integer
For Row = 0 To ItemCount - 1 'populate the BOM collection
Call WalkDownTree(Row)
Next
Dim TempStr As String
For Row = 0 To ItemCount - 1 'just write each row to msgbox
For Col = 0 To 5
TempStr = TempStr & BOMData(Row, Col) & " "
Next
Call MsgBox(TempStr)
TempStr=""
Next
End Sub
This is how could look the sub which populates the collection ... you are iterating through row or that could be items (products, parts etc)
Sub WalkDownTree(Row As Integer)
BOMData(Row, 0) = "PartNumber"
BOMData(Row, 1) = "Name"
BOMData(Row, 2) = "Material"
BOMData(Row, 3) = "Texture"
BOMData(Row, 4) = "Color"
BOMData(Row, 5) = 1
End Sub
The advantage of this solution could bring you simple excel export like this
Sub WriteToExcel()
Dim ExlApp As Excel.Application
Set ExlApp = GetObject(, "EXCEL.Application")
Dim ExlWorkBook As Workbook
Set ExlWorkBook = ExlApp.Workbooks.Open("C:\Test.xls")
Dim ExlSheet As Worksheet
Set ExlSheet = ExlWorkBook.Worksheets.Item(1)
ExlSheet.Range("A1").Resize((UBound(BOMData, 1) - LBound(BOMData, 1) + 1), (UBound(BOMData, 2) - LBound(BOMData, 2) + 1)).Value = BOMData
End Sub
EDIT
This is VBScript version. However i would suggest using VBA or VB .Net language for Catia if you want to seriously develop something. Using VBScript if not necessary is just torturing yourself
Dim BOMData()
Sub CATMain()
Dim ItemCount
ItemCount = 10 'how many items you have
ReDim BOMData (ItemCount - 1, 5)
Dim Row
Dim Col
For Row = 0 To ItemCount - 1 'populate the BOM collection
Call WalkDownTree(Row)
Next
Dim TempStr
For Row = 0 To ItemCount - 1 'just write each row to msgbox
For Col = 0 To 5
TempStr = TempStr & BOMData(Row, Col) & " "
Next
Call MsgBox(TempStr)
TempStr=""
Next
End Sub
Sub WalkDownTree(Row)
BOMData(Row, 0) = "PartNumber"
BOMData(Row, 1) = "Name"
BOMData(Row, 2) = "Material"
BOMData(Row, 3) = "Texture"
BOMData(Row, 4) = "Color"
BOMData(Row, 5) = 1
End Sub
I'd like to use excel 2010 to realize a function to first compare values from 2 different Excel sheets and then sort them based on another column value.
For example:
In sheet 1, I've got:
Name Value
Test 1 100.5
Test 1 200.6
Test 1 300.3
Test 2 100.8
Test 2 200.6
Test 3 200.5
In sheet 2, I've got :
Name
Test 1
Test 1
Test 1
Test 3
what I want to achieve is if the name from sheet 1 is not in sheet 2, delete the whole line in sheet 1 and sort by descending the name based on the column value.
Desired:
Name Value
Test 1 300.3
Test 1 200.6
Test 1 100.5
Test 3 200.5
Here is what I get so far:
Sub test()
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim i As Integer, j As Integer
Dim lastRow1 As Integer, lastRow2 As Integer
On Error GoTo 0
Set wb = ActiveWorkbook
Set ws1 = wb.Worksheets("Sheet1")
Set ws2 = wb.Worksheets("Sheet2")
lastRow1 = ws1.UsedRange.Rows.Count
lastRow2 = ws2.UsedRange.Rows.Count
For i = 2 To lastRow1
For j = 2 To lastRow2
If ws1.Cells(i, 1).Value <> "" Then 'This will omit blank cells at the end (in the event that the column lengths are not equal.
If InStr(1, ws2.Cells(j, 1).Value, ws1.Cells(i, 1).Value, vbTextCompare) < 1 Then
Rows(i).EntireRow.delete
Exit For
End If
End If
Next j
Next i
End Sub
Please suggest and help. thank you very much in advance.
I changed your code so it is working:
Sub test()
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim i As Integer, j As Integer
Dim lastRow1 As Integer, lastRow2 As Integer
On Error GoTo 0
Set wb = ActiveWorkbook
Set ws1 = wb.Worksheets("Sheet1")
Set ws2 = wb.Worksheets("Sheet2")
lastRow1 = ws1.Cells(Rows.Count, 1).End(xlUp).Row 'last used cell in column A
lastRow2 = ws2.Cells(Rows.Count, 1).End(xlUp).Row 'last used cell in column A
Dim same As Boolean
same = False
For i = lastRow1 To 2 Step -1 'bottom to top
For j = 2 To lastRow2
Debug.Print ws1.Cells(i, 1).Value
Debug.Print ws2.Cells(j, 1).Value
If ws1.Cells(i, 1).Value <> "" Then 'This will omit blank cells at the end (in the event that the column lengths are not equal.
If ws1.Cells(i, 1).Value = ws2.Cells(j, 1).Value Then
same = True 'set True if match
End If
End If
Next j
If same = False Then 'if no match
Rows(i).EntireRow.Delete
End If
same = False
Next i
'sort
lastRow1 = ws1.Cells(Rows.Count, 1).End(xlUp).Row
Range("A2:B" & lastRow1).Sort key1:=Range("A2:A" & lastRow1), order1:=xlAscending, Header:=xlNo, key2:=Range("B2:B" & lastRow1), order2:=xlAscending, Header:=xlNo
End Sub
Still thinking about the rest of the answer, but in advance I would advise you to start at the bottom of the list (so from lastrow to the second row) The reason for this is that you are removing rows which your counter does not take into account. You may also want to look into the MATCH function in Excel to see if a certain value is used in a list instead of going through the whole list.
Ok so I've searched and searched and can't quite find what I'm looking for.
I have a workbook and what I'm basically trying to do is take the entries from certain ranges (Sheet1 - E4:E12, E14:E20, I4:I7, I9:I12, I14:I17, & I19:I21) and put them in a separate list on Sheet2. I then want the new list on Sheet2 to be sorted by how many times an entry appeared on Sheet1 as well as display the amount.
example http://demonik.doomdns.com/images/excel.png
Obviously as can be seen by the ranges I listed above, this sample is much smaller lol, was just having trouble trying to figure out how to describe everything and figured an image would help.
Basically I am trying to use VBA (the update would be initialized by hitting a button) to copy data from Sheet1 and put all the ranges into one list in Sheet2 that is sorted by how many times it appeared on Sheet1, and then alphabetically.
If a better discription is needed just comment and let me know, I've always been horrible at trying to describe stuff like this lol.
Thanks in advance!
Another detail: I cant have it search for specific things as the data in the ranges on Sheet1 may change. Everything must be dynamic.
I started out with this data
and used the following code to read it into an array, sort the array, and count the duplicate values, then output the result to sheet2
Sub Example()
Dim vCell As Range
Dim vRng() As Variant
Dim i As Integer
ReDim vRng(0 To 0) As Variant
Sheets("Sheet2").Cells.Delete
Sheets("Sheet1").Select
For Each vCell In ActiveSheet.UsedRange
If vCell.Value <> "" Then
ReDim Preserve vRng(0 To i) As Variant
vRng(i) = vCell.Value
i = i + 1
End If
Next
vRng = CountDuplicates(vRng)
Sheets("Sheet2").Select
Range(Cells(1, 1), Cells(UBound(vRng), UBound(vRng, 2))) = vRng
Rows(1).Insert
Range("A1:B1") = Array("Entry", "Times Entered")
ActiveSheet.UsedRange.Sort Range("B1"), xlDescending
End Sub
Function CountDuplicates(List() As Variant) As Variant()
Dim CurVal As String
Dim NxtVal As String
Dim DupCnt As Integer
Dim Result() As Variant
Dim i As Integer
Dim x As Integer
ReDim Result(1 To 2, 0 To 0) As Variant
List = SortAZ(List)
For i = 0 To UBound(List)
CurVal = List(i)
If i = UBound(List) Then
NxtVal = ""
Else
NxtVal = List(i + 1)
End If
If CurVal = NxtVal Then
DupCnt = DupCnt + 1
Else
DupCnt = DupCnt + 1
ReDim Preserve Result(1 To 2, 0 To x) As Variant
Result(1, x) = CurVal
Result(2, x) = DupCnt
x = x + 1
DupCnt = 0
End If
Next
Result = WorksheetFunction.Transpose(Result)
CountDuplicates = Result
End Function
Function SortAZ(MyArray() As Variant) As Variant()
Dim First As Integer
Dim Last As Integer
Dim i As Integer
Dim x As Integer
Dim Temp As String
First = LBound(MyArray)
Last = UBound(MyArray)
For i = First To Last - 1
For x = i + 1 To Last
If MyArray(i) > MyArray(x) Then
Temp = MyArray(x)
MyArray(x) = MyArray(i)
MyArray(i) = Temp
End If
Next
Next
SortAZ = MyArray
End Function
End Result:
Here is a possible solution that I have started for you. What you are asking to be done gets rather complicated. Here is what I have so far:
Option Explicit
Sub test()
Dim items() As String
Dim itemCount() As String
Dim currCell As Range
Dim currString As String
Dim inArr As Boolean
Dim arrLength As Integer
Dim iterator As Integer
Dim x As Integer
Dim fullRange As Range
Set fullRange = Range("E1:E15")
iterator = 0
For Each cell In fullRange 'cycle through the range that has the values
inArr = False
For Each currString In items 'cycle through all values in array, if
'values is found in array, then inArr is set to true
If currCell.Value = currString Then 'if the value in the cell we
'are currently checking is in the array, then set inArr to true
inArr = True
End If
Next
If inArr = False Then 'if we did not find the value in the array
arrLength = arrLength + 1
ReDim Preserve items(arrLength) 'resize the array to fit the new values
items(iterator) = currCell.Value 'add the value to the array
iterator = iterator + 1
End If
Next
'This where it gets tricky. Now that you have all unique values in the array,
'you will need to count how many times each value is in the range.
'You can either make another array to hold those values or you can
'put those counts on the sheet somewhere to store them and access them later.
'This is tough stuff! It is not easy what you need to be done.
For x = 1 To UBound(items)
Next
End Sub
All that this does so far is get unique values into the array so that you can count how many times each one is in the range.
I have an Excel table in which multiple rows are given different coloured backgrounds by VBA macros. These background colours should be locked to the rows. My problem is that when the table is sorted by one column or another the background colours move as the data is reordered.
Can I format in another way to stop this happening so that the cells remain locked?
The code I use to format is:
For Each Row In rng.Rows
If Condition Then
Row.Select
cIndex = ColourIndex(colour)
With Selection.Interior
.ColorIndex = cIndex
End With
End If
Next
An example of my table is like this:
EDIT: Extra Code
Sub Quota(ByVal Type As String)
Dim records As Long
Dim sht1 As Worksheet
Set sht1 = Worksheets("Sheet1")
Dim sht2 As Worksheet
Set sht2 = Worksheets("Sheet2")
records = sht1.Range("A1048576").End(xlUp).Row - 5
Dim rng As Range
Dim rngRowCount As Long
Dim rLastCell As Range
Dim i As Long
sht2.Activate
'Last used cell
Set rLastCell = sht2.Cells.Find(What:="*", After:=Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
'All used columns except 1st
Set rng = sht2.Range(Cells(2, 1), rLastCell)
rng.Select
rngRowCount = rng.Rows.CountLarge
For i = 1 To rngRowCount
Dim valueAs String
Dim colour As String
Dim VarX As Long
Dim maxValue As Long
value= sht2.Cells(i + 1, 1).Value
colour = sht2.Cells(i + 1, 2).Value
If Type = "A" Then
VarX = sht2.Cells(i + 1, 3).Value
ElseIf Type = "B" Then
VarX = sht2.Cells(i + 1, 5).Value
End If
maxValue = (records / 100) * VarX
ColourRows value, colour, maxValue
Next i
End Sub
Sub ColourRows(value As String, colour As String, maxValue As Long)
Dim sht1 As Worksheet
Set sht1 = Worksheets("Sheet1")
sht1.Activate
Dim rng As Range
Dim firstSixRowsOnwards As Range
Dim lastColumn As Long
Dim usedColumns As Range
Dim usedColumnsString As String
Dim highlightedColumns As Range
Dim rngDataRowCount As Long
Dim performancevalueAs String
Dim cIndex As Integer
Dim count As Long
count = 0
Dim rLastCell As Range
'End row
rngDataRowCount = sht1.Range("A1048576").End(xlUp).Row
'First 6 rows
Set firstSixRowsOnwards = sht1.Range("A6:XFD1048576")
'Last column
lastColumn = Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
'Used Range
Set rng = sht1.Range(Cells(1, 1), Cells(rngDataRowCount, lastColumn))
'Used Columns
Set usedColumns = sht1.Range(Cells(1, 1), Cells(1048576, lastColumn))
Set rng = Intersect(rng, firstSixRowsOnwards, usedColumns)
For Each Row In rng.Rows
compareValue= Cells(Row.Row, 5)).Value
If (InStr(1, value, compareValue, 1) Then
Dim rowNumber As Long
Row.Select
If count < maxValue Then
cIndex = ColourIndex(colour)
With Selection.Interior
.ColorIndex = cIndex
End With
count = count + 1
Else
cIndex = 3 'red
With Selection.Interior
.ColorIndex = cIndex
End With
End If
End If
Next
End Sub
I believe that if you select your data by column and then sort (instead of a row limited range) then formatting will follow.
EDIT:
If you want to lock the formatting then use conditional formatting that is based on row number, e.g. ROW() = x or ROW() = range of values...
Tested: Use conditional formatting by formula set rule such as =ROW()=3 make sure excel does not double quote it for you, apply this to the entire data range. Row 3 will then always be formatted as you set here.
Setting in vba
Sub test()
Range("A3").Select
With Range("A3")
.FormatConditions.Add Type:=xlExpression, Formula1:="=ROW()=3"
.FormatConditions(1).Interior.ColorIndex = 46
End With
End Sub
Can be done with CF, for example (top rule is >11):
Edit - I inadvertently left out one rule
the second down below uses =ROW($A1)=11:
Here we go:
In this case, what I would do it one of the two things:
Conditional formatting. Needs lot of logics and manual steps so let us leave it.
A macro: Whenever you sort the data, please fire the following function
Sub Option1()
Dim row As Range
Dim rowNum As Integer
Dim tRange As Range
'set range here: in your example, it is A2:D11
Set tRange = ActiveSheet.Range("A2:D11")
'clear colors
tRange.ClearFormats ' clears the previous format
rowNum = 1
For Each row In tRange.Rows
Select Case rowNum
Case 1, 2
row.Interior.Color = RGB(255, 255, 0) ' 1 and 2nd will be yellow
Case 3, 4
row.Interior.Color = 255 ' 3rd and 4th row will be red
Case 5, 6
row.Interior.Color = RGB(0, 0, 255) ' 5 and 6th row will be blue
Case Else
row.Interior.Color = RGB(0, 255, 0) '' all the bottom row would be a Green row
End Select
rowNum = rowNum + 1
Next row
End Sub
Does it help?
I have a list of items in an Excel worksheet, A1-B115. At the moment I can enter 10 variables which retrieves the correct data from the list.
Code now:
C1=1 - run through A1-A115 and check for the value to be between 1000-2000; if so, copy the B value somewhere.
C2=1 - run through A1-A115 and check for the value to be between 2001-3000; if so, copy the B value somewhere.
....
What I would like to do is that I can enter a value (example: 25 or 30) and that my macro randomly selects the right amount of values.
Code I would like to do: C1: 30 -> randomly selects 30 values from B1-B115
This will do the trick.
Sub PickRandomItemsFromList()
Const nItemsToPick As Long = 10
Const nItemsTotal As Long = 115
Dim rngList As Range
Dim varRandomItems() As Variant
Dim i As Long
Set rngList = Range("B1").Resize(nItemsTotal, 1)
ReDim varRandomItems(1 To nItemsToPick)
For i = 1 To nItemsToPick
varRandomItems(i) = rngList.Cells(Int(nItemsTotal * Rnd + 1), 1)
Next i
' varRandomItems now contains nItemsToPick random items from range rngList.
End Sub
As discussed in the comments, this will allow individual items to be picked more than once within the nItemsToPick picked, if for example number 63 happens to be randomly picked twice. If you don't want this to happen, then an additional loop will have to be added to check whether the item about to be picked is already in the list, for example like so:
Sub PickRandomItemsFromList()
Const nItemsToPick As Long = 10
Const nItemsTotal As Long = 115
Dim rngList As Range
Dim idx() As Long
Dim varRandomItems() As Variant
Dim i As Long
Dim j As Long
Dim booIndexIsUnique As Boolean
Set rngList = Range("B1").Resize(nItemsTotal, 1)
ReDim idx(1 To nItemsToPick)
ReDim varRandomItems(1 To nItemsToPick)
For i = 1 To nItemsToPick
Do
booIndexIsUnique = True ' Innoncent until proven guilty
idx(i) = Int(nItemsTotal * Rnd + 1)
For j = 1 To i - 1
If idx(i) = idx(j) Then
' It's already there.
booIndexIsUnique = False
Exit For
End If
Next j
If booIndexIsUnique = True Then
Exit Do
End If
Loop
varRandomItems(i) = rngList.Cells(idx(i), 1)
Next i
' varRandomItems now contains nItemsToPick unique random
' items from range rngList.
End Sub
Note that this will loop forever if nItemsToPick > nItemsTotal !
I would use a collection to make sure you don't get any duplicates.
Function cItemsToPick(NrOfItems As Long, NrToPick As Long) As Collection
Dim cItemsTotal As New Collection
Dim K As Long
Dim I As Long
Set cItemsToPick = New Collection
If NrToPick > NrOfItems Then Exit Function
For I = 1 To NrOfItems
cItemsTotal.Add I
Next I
For I = 1 To NrToPick
K = Int(cItemsTotal.Count * Rnd + 1)
cItemsToPick.Add cItemsTotal(K)
cItemsTotal.Remove (K)
Next I
Set cItemsTotal = Nothing
End Function
You can test this function with the following code:
Sub test()
Dim c As New Collection
Dim I As Long
Set c = cItemsToPick(240, 10)
For I = 1 To c.Count
Debug.Print c(I)
Next I
End Sub