I have a problem with displaying multiple columns in a ListBox in my UserForm.
Everything is working until my numbers of column is max 10.
My code:
Private Sub FindButton_Click()
ListBoxResult.Clear
ListBoxResult.ColumnCount = 14
Dim RowNum As Long
RowNum = 1
Do Until Sheets("db").Cells(RowNum, 1).Value = ""
If InStr(1, Sheets("db").Cells(RowNum, 2).Value, FindDMC.Value, vbTextCompare) > 0 Then
On Error GoTo next1
ListBoxResult.AddItem Sheets("db").Cells(RowNum, 1).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 2) = Sheets("db").Cells(RowNum, 2).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 3) = Sheets("db").Cells(RowNum, 3).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 4) = Sheets("db").Cells(RowNum, 4).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 5) = Sheets("db").Cells(RowNum, 5).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 6) = Sheets("db").Cells(RowNum, 6).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 7) = Sheets("db").Cells(RowNum, 7).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 8) = Sheets("db").Cells(RowNum, 8).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 9) = Sheets("db").Cells(RowNum, 9).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 10) = Sheets("db").Cells(RowNum, 10).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 11) = Sheets("db").Cells(RowNum, 11).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 12) = Sheets("db").Cells(RowNum, 12).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 13) = Sheets("db").Cells(RowNum, 13).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 14) = Sheets("db").Cells(RowNum, 14).Value
ListBoxResult.List(ListBoxResult.ListCount - 1, 15) = Sheets("db").Cells(RowNum, 15).Value
End If
next1:
RowNum = RowNum + 1
Loop
End Sub
ListBoxResult.ColumnCount and properties is 14, also Column widths is ok.
After runing my code the failure code is Run-time error '380': Could not set the List property. Invalid property value. At first, I was thinking that maybe ListBoxes have limits for columns, but I found ListBoxes with 60 columns on the Internet.
I am trying also this, but still doesn't work:
Private Sub Browser_RMA_Initialize()
ListBoxResult.RowSource = "db!a1:z1"
ListBoxResult.ColumnCount = 14
ListBoxResult.ColumnWidths = "50;50;50;50;50;50;50;50;50;50;50;50;50;50;"
ListBoxResult.ColumnHeads = True
End Sub
Could you support me, please?
Assigning to .Columnproperty avoids transposing
As late addition to #Dy.Lee 's valid and already accepted array approach (see my comment), I demonstrate a way how to avoid both repeated redimming [4] and transposing [5]:
Option Explicit ' declaration head of UserForm code module
Private Sub FindButton_Click()
'[0] where to search
Const SearchCol As Long = 2 ' get search items from 2nd column
'[1] define data set
Dim data As Variant
data = Tabelle1.Range("A1").CurrentRegion ' << change to your project's sheet Code(Name)
Dim ii As Long: ii = UBound(data, 1) ' row count
Dim jj As Long: jj = UBound(data, 2) ' column count
'[2] provide for sufficient result rows (array with converted row : columns order)
Dim results() As Variant
ReDim Preserve results(1 To jj, 1 To ii) ' redim up to maximum row count ii
'[3] assign filtered data
Dim i As Long, j As Integer, n As Long
For i = 1 To ii
If InStr(1, data(i, SearchCol), FindDMC.Value, vbTextCompare) > 0 Then
'' If data(i, SearchCol) = FindDMC.Value Then ' exact findings
n = n + 1
For j = 1 To jj
results(j, n) = data(i, j)
Next
End If
Next i
'[4] fill listbox with results
With ListBoxResult
.Clear
.ColumnCount = 14
.ColumnWidths = "50;50;50;50;50;50;50;50;50;50;50;50;50;50;"
If n Then
'[4] redimension only a 2nd time (& last time)
ReDim Preserve results(1 To jj, 1 To n)
'[5] assign results to listbox'es .Column property
.Column = results ' << .Column property avoids unnecessary transposing
End If
End With
End Sub
The column index of the listbox also starts at 0. The index number of additem should be 0, and you specified 15 at the end, then the number of columns becomes 16, so an error occurs because column 14 is exceeded.
It would be convenient to use an array.
Private Sub FindButton_Click()
Dim Ws As Worksheet
Dim vDB As Variant, vResult()
Dim i As Long, j As Integer, n As Long
Set Ws = Sheets("db")
vDB = Ws.Range("a1").CurrentRegion
For i = 1 To UBound(vDB, 1)
If InStr(1, vDB(i, 2), FindDMC.Value, vbTextCompare) > 0 Then
n = n + 1
ReDim Preserve vResult(1 To 14, 1 To n)
For j = 1 To 14
vResult(j, n) = vDB(i, j)
Next
End If
Next i
With ListBoxResult
.Clear
.ColumnCount = 14
.ColumnWidths = "50;50;50;50;50;50;50;50;50;50;50;50;50;50;"
If n Then
If n = 1 Then
.Column = vResult
Else
.List = WorksheetFunction.Transpose(vResult)
End If
End If
End With
End Sub
Related
I am trying to fill a series from a higher number in cell G2 (e.g "512") down to a lower number in Cell H2 (e.g "500"). I need the VBA code to run in Column J, producing the following this series as an example 512, 511, 510, 509, 508 ... down the column.
Here's a screenshot that describes what I need
Most examples I've found seems to be built for an increasing series (512, 513, 514....)
Any help to get this right will be helpful
For a VBA general solution, try this
Sub CreateSequence(StartValue As Long, EndValue As Long, OutputStart As Range, Optional ByVal StepBy As Long = 1)
Dim NumValues As Long
Dim dat As Variant
Dim i As Long
StepBy = Abs(StepBy)
If StepBy <= 0 Then Exit Sub
NumValues = Abs(StartValue - EndValue) \ StepBy + 1
ReDim dat(1 To NumValues, 1 To 1)
For i = 0 To NumValues - 1
dat(i + 1, 1) = StartValue + i * IIf(StartValue > EndValue, -StepBy, StepBy)
Next
OutputStart.Resize(UBound(dat, 1), 1).Value = dat
End Sub
Use it like this
Sub Demo()
CreateSequence Range("G2").Value, Range("H2").Value, Range("K2")
End Sub
A formula solution (Excel version 365)
=SEQUENCE(G2-H2+1,1,G2,-1)
hlRange = Sheets(2).Cells(2, 7).Value - Sheets(2).Cells(2, 8).Value + 1
' Fill series from max to min value
For j = 1 To hlRange
Sheets(2).Cells(j + 1, 10).Value = Sheets(2).Cells(2, 7).Value - j + 1
Next j
You can use the following code, it lets you add a a values to specify the steps you want to have.
https://i.stack.imgur.com/vSan5.jpg
Sub createNumList()
Dim i As Integer
Dim count As Integer
Dim cellValue As Integer
count = (ActiveSheet.Cells(2, 1).Value - ActiveSheet.Cells(2, 2).Value) / ActiveSheet.Cells(2, 3).Value
For i = 1 To count + 1
If i = 1 Then
ActiveSheet.Cells(i + 2, 5).Value = ActiveSheet.Cells(2, 1).Value
Else
ActiveSheet.Cells(i + 2, 5).Value = ActiveSheet.Cells(i + 1, 5).Value - ActiveSheet.Cells(2, 3).Value
End If
Next i
End Sub
I'm new to VBA and was surprised that there isn't a function to insert elements in an array (my previous question). So I rethought my approach a bit.
On screen I have the following example table 'allActualWeights'. There are a lot of blanks (no weight value) that I want to get rid of (the table is different everytime). So the end result should be 'actualWeights'.
In my code I tried the following:
Option Base 1
Dim allActualWeights
allActualWeights = Range("A6:E29").Value
Dim actualWeights
actualWeights = allActualWeights
For Index = 1 To 24
If allActualWeights(Index, 2) <> 0 Then
ReDim actualWeights(Index, 5)
actualWeights(Index, 1) = allActualWeights(Index, 1)
actualWeights(Index, 2) = allActualWeights(Index, 2)
actualWeights(Index, 3) = allActualWeights(Index, 3)
actualWeights(Index, 4) = allActualWeights(Index, 4)
actualWeights(Index, 5) = allActualWeights(Index, 5)
End If
Next Index
Range("G6:K29") = actualWeights
But I'm not getting the results I hoped for.
What am I doing wrong, or is there a better approach?
Here's one approach:
Sub Tester()
Dim allActualWeights, actualweights(), i As Long, n As Long, c As Long
Dim rngSource As Range
Set rngSource = ActiveSheet.Range("A6:E29")
With rngSource
allActualWeights = .Value
'size the output array # of rows to count of values in ColB
ReDim actualweights(1 To Application.CountA(.Columns(1)), _
1 To .Columns.Count)
End With
n = 1
For i = LBound(allActualWeights, 1) To UBound(allActualWeights, 1)
If Len(allActualWeights(i, 2)) > 0 Then
For c = LBound(allActualWeights, 2) To UBound(allActualWeights, 2)
actualweights(n, c) = allActualWeights(i, c)
Next c
n = n + 1 'next output row
End If
Next i
'put the array on the sheet
Range("G6").Resize(UBound(actualweights, 1), UBound(actualweights, 2)) = actualweights
End Sub
This should do it and is easily maintainable...
Sub ActualWeights()
Dim c&, i&, j&, n&, a, b
With [a6:e29] '<-- allActualWeights
a = .Value2
n = UBound(a) - Application.CountBlank(.Offset(, 1).Resize(, 1))
ReDim b(1 To n, 1 To UBound(a, 2))
For i = 1 To UBound(a)
If a(i, 2) Then
c = c + 1
For j = 1 To UBound(a, 2)
b(c, j) = a(i, j)
Next
End If
Next
.Offset(, 6).Resize(n) = b
End With
End Sub
I am adding more than 10 columns to my listbox in Excel VBA. I keep getting run-time error '380'-Invalid property value. It works properly until column 9 in listbox. I couldn`t find any proper solution for this anywhere else. Does anyone know a workaround for this issue?
Private Sub txtSearch_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal
Shift As Integer)
Dim rng As Range
Set rng = Range("Lookup")
Dim rw
Dim strText As String
strText = LCase(txtSearch.Text)
With ListBox1
.RowSource = ""
.ColumnCount = 12
For Each rw In rng.Rows
If InStr(LCase(Cells(rw.Row, 4)), strText) Then
.AddItem Cells(rw.Row, 1).Value
.List(ListBox1.ListCount - 1, 1) = Cells(rw.Row, 2).Value
.List(ListBox1.ListCount - 1, 2) = Cells(rw.Row, 3).Value
.List(ListBox1.ListCount - 1, 3) = Cells(rw.Row, 4).Value
.List(ListBox1.ListCount - 1, 4) = Cells(rw.Row, 5).Value
.List(ListBox1.ListCount - 1, 5) = Cells(rw.Row, 6).Value
.List(ListBox1.ListCount - 1, 6) = Cells(rw.Row, 7).Value
.List(ListBox1.ListCount - 1, 7) = Cells(rw.Row, 8).Value
.List(ListBox1.ListCount - 1, 8) = Cells(rw.Row, 9).Value
.List(ListBox1.ListCount - 1, 9) = Cells(rw.Row, 10).Value
.List(ListBox1.ListCount - 1, 10) = Cells(rw.Row, 11).Value
.List(ListBox1.ListCount - 1, 11) = Cells(rw.Row, 12).Value
.List(ListBox1.ListCount - 1, 12) = Cells(rw.Row, 13).Value
End If
Next
End With
End Sub
I don't know if this will fix everything, but it will definitely clean it up a bit. Also, I am not sure what worksheet you are pulling Cells(rw.Row, 2).value from. But they may have something to do with why it stops part way through. Also, to clean it up a bit, try an additional For Statement.
Private Sub txtSearch_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim rng As Range: Set rng = Range("Lookup")
Dim rw
Dim strText As String: strText = LCase(txtSearch.Text)
With ListBox1
.RowSource = ""
.ColumnCount = 21
For Each rw In rng.Rows
If InStr(LCase(Cells(rw.Row, 4)), strText) Then
.AddItem Cells(rw.Row, 1).Value
For x = 1 To 12 '''Change Worksheet to your Worksheet name
.List(ListBox1.ListCount - 1, x) = Worksheets("Sample").Cells(rw.Row, x + 1).Value2
Next x
End If
Next
End With
End Sub
If this doesn't help, try what #Cyril said with the array.
Just came back to you... a bit long, but here's the general thoughts...
This all goes in the code for the ActiveX Control:
Option Explicit
Sub ListBox1_Click()
Dim rw As Range, strtext As String
Dim arr As Variant, ai As Long, aj As Long
Dim brr As Variant, bi As Long, bj As Long
strtext = "a" 'I used this when i did my testing
ReDim arr(11, 0)
For Each rw In Range("rng")
If InStr(LCase(rw.Value), strtext) Then
aj = findaj(arr)
If Not IsEmpty(arr(1, aj)) Then
aj = aj + 1
ReDim Preserve arr(11, aj)
End If
For ai = 1 To 11
arr(ai, aj) = Cells(rw.Row, ai + 1).Value
Next ai
End If
Next rw
ReDim brr(aj, 11)
For bi = 0 To aj
For bj = 1 To 11
brr(bi, bj) = arr(bj, bi)
Next bj
Next bi
ListBox1.ColumnCount = 11
ListBox1.List = brr
End Sub
Private Function findaj(ByVal brr As Variant)
Dim j As Long, meow As String
j = 0
Do While True
On Error GoTo toll
j = j + 1
meow = brr(1, j)
Loop
toll:
findaj = j - 1
End Function
So there's a lot going on here... I use two separate arrays, due to how redimming arrays works in VBA. You can only update the second element of the array, so arr(ai,aj) can only have aj updated when I redim preserve while adding a new row to my array.
So we make an array (arr) that captures the data based on VBA's limitations. Within that array, we use a function, findaj, which intentionally traps an error to determine the appropriate last column in arr (i italicized the use of column, as it's not truly the case, but it makes sense spatially when thinking about it).
You then convert the array arr to brr in the appropriate order of columns/rows.
Afterwards, you make your .list = brr.
As far as I know, Excel Average functions do not include cells that are blank. However, my this appears to be exactly what my code is doing:
Sub sumavg()
Dim rowCounter As Long
Dim colCounter As Long
Dim values() As Variant
Const START_COL As Long = 1
Const END_COL As Long = 6
Const OUTPUT_COL_START As Long = 20
With Worksheets("datasummary")
'Load the values into an array
values = .Range(.Cells(1, 1), .Cells(199, 18)).Value
For rowCounter = 1 To 40
ReDim rowresults(1 To 1, START_COL To END_COL)
For colCounter = START_COL To END_COL
'find average of AOIentries values
rowresults(1, colCounter) = Application.WorksheetFunction.Average(values((5 * rowCounter - 2), colCounter), values((5 * rowCounter - 2), colCounter + 6), values((5 * rowCounter - 2), colCounter + 12))
Next colCounter
'print row of results
.Range(.Cells(5 * rowCounter - 2, OUTPUT_COL_START), .Cells(5 * rowCounter - 2, OUTPUT_COL_START + END_COL - START_COL)).Value = rowresults
For colCounter = START_COL To END_COL
'find average of RT values
rowresults(1, colCounter) = Application.WorksheetFunction.Average(values((5 * rowCounter - 1), colCounter), values((5 * rowCounter - 1), colCounter + 6), values((5 * rowCounter - 1), colCounter + 12))
Next colCounter
'print row of results
.Range(.Cells(5 * rowCounter - 1, OUTPUT_COL_START), .Cells(5 * rowCounter - 1, OUTPUT_COL_START + END_COL - START_COL)).Value = rowresults
Next rowCounter
End With
End Sub
Here is the code to print values including blank cells:
For r = 1 To UBound(d, 1)
k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
If d(r, 19) = 1 Then
dBT(k) = dBT(k) + IIf(d(r, COL_AOI) = "AOI Entry", 1, 0) 'get count
Else: dBT(k) = ""
End If
Next r
'populate array with appropriate counts for each row
For r = 1 To UBound(d, 1)
k = d(r, 1) & "|" & d(r, 2) 'create key
resBT(r, 1) = dBT(k) 'get the count
Next r
Call createsummarytable
Call PopSummaryAOI(dBT)
dBT.RemoveAll
For r = 1 To UBound(d, 1)
k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
dBT(k) = d(r, COL_RT)
Next r
As far as I can tell, the cell is entirely blank, so it shouldn't be included in the average, but (20 + 17)/2 =/= 12.33, whereas (20 + 17 + 0)/3 = 12.33.
When you call .Range(.Cells(1, 1), .Cells(199, 18)).Value, you end up with an array of Variant. WorksheetFunction.Average treats Ranges and Variant arrays differently than it treats Variants. If you give it individual Variant for arguments, it casts them to Doubles, and casting Empty to a Double results in 0. If you want it to ignore empty cells, you need to pass it a Range or a Variant():
Sub Example()
Dim test As Variant
test = Empty 'This is what you get from an EmptyCell.Value
Debug.Print CDbl(test) 'Prints 0.
Debug.Print WorksheetFunction.Average(test, 0, 10) 'Prints 3.33333333333333.
Range("A1").ClearContents 'Nothing in A1 now.
Debug.Print Range("A1").Value = Empty 'Prints True
Debug.Print WorksheetFunction.Average(Range("A1"), 0, 10) 'Prints 5
End Sub
Does anyone know how might I find the earliest MMMYY from an array of the following form (see column K).
Note: the date are not sorted in ascending order.
Code:
Sub outputfile()
'Capture the contract no. in ContractNo() array
Dim ContractNo() As String
'Capture the project title in ProjectTitle() array
Dim ProjectTitle() As String
'Capture the contract start in ContractStart() array
Dim ContractStart() As Date
'Capture the contract end in ContractEnd() array
Dim ContractEnd() As Date
'Capture ASPQ Cement in ASPQC() array
Dim ASPQC() As Double
'Capture ASP Sand in ASPQS() array
Dim ASPQS() As Double
'Capture ASP Aggregate in ASPQA() array
Dim ASPQA() As Double
i = 2
Do Until IsEmpty(Cells(i, 1).Value)
i = i + 1
Loop
ReDim ContractNo(1 To i - 2)
ReDim ProjectTitle(1 To i - 2)
ReDim ContractStart(1 To i - 2)
ReDim ContractEnd(1 To i - 2)
ReDim ASPQC(1 To i - 2)
ReDim ASPQS(1 To i - 2)
ReDim ASPQA(1 To i - 2)
For i = 1 To UBound(ContractNo, 1)
ContractNo(i) = Cells(i + 1, 1).Value
ProjectTitle(i) = Cells(i + 1, 2).Value
ContractStart(i) = Cells(i + 1, 11).Value
ContractEnd(i) = Cells(i + 1, 12).Value
ASPQC(i) = Cells(i + 1, 14).Value
ASPQS(i) = Cells(i + 1, 15).Value
ASPQA(i) = Cells(i + 1, 16).Value
Next i
End sub
I believe the best is a built in formula in a cell.
=TEXT(MIN(K:K), "MMMYY")