I saw a great tutorial from this gentleman:
https://www.businessprogrammer.com/how-to-use-listbox-in-excel-vba-userform/
But if I only make 1 data row, I get an error: Type missmatch.
Can you help me why I get this error, even if I have x Rows but the same City name, I also get this error.... strange
Its about this code part here (ex. listbox1 gives according to what is selected listbox2 listing. But if only 1 kina data is found I get this error):
Option Explicit
Private Sub UserForm_Initialize()
Dim Hauptkategorie() As Variant
Me.Caption = "Artikelsuche"
ClearFilter
' Get array of cities and apply to listbox
Hauptkategorie = GetHauptkategorieList()
ListBox1.List = Hauptkategorie
'LoadAllDataToDataList
End Sub
' Return list of Hauptkategorie
Private Function GetHauptkategorieList() As Variant
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim vReturn As Variant
Dim i As Integer
Set rngData = ArtikelDatasource.Range("A1").CurrentRegion
Set rngCrit = CategoryCriteria.Range("B1:B2")
Set rngExt = CategoryCriteria.Range("B6")
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt, True
Set rngExt = rngExt.CurrentRegion
' Sort the cities ascending
rngExt.Sort Key1:=rngExt.Resize(1, 1), Header:=xlYes, Order1:=xlAscending
If rngExt.Rows.Count > 1 Then
vReturn = rngExt.Resize(rngExt.Rows.Count - 1).Offset(1)
Else
'Use this to return "no data" message
vReturn = noDataArray()
End If
GetHauptkategorieList = vReturn
For i = 2 To 8
With ArtikelSuche
.Controls("Listbox" & i).Clear
End With
Next i
End Function
Private Sub ListBox1_Change()
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim Ebene1kategorie() As Variant
CategoryCriteria.Range("C2").ClearContents
CategoryCriteria.Range("E2").ClearContents
CategoryCriteria.Range("G2").ClearContents
CategoryCriteria.Range("I2").ClearContents
CategoryCriteria.Range("K2").ClearContents
CategoryCriteria.Range("M2").ClearContents
CategoryCriteria.Range("O2").ClearContents
If ListBox1.ListIndex = -1 Then Exit Sub ' nothing is selected, so quit
Debug.Print ListBox1.List(ListBox1.ListIndex)
CategoryCriteria.Range("A2").Value = ListBox1.List(ListBox1.ListIndex)
Set rngData = ArtikelDatasource.Range("A1").CurrentRegion
Set rngCrit = CategoryCriteria.Range("A1").CurrentRegion
Set rngExt = ArticleCriteria.Range("A6").CurrentRegion.Resize(1)
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt
Set rngData = rngExt.CurrentRegion
If rngData.Rows.Count > 1 Then
Set rngData = rngData.Resize(rngData.Rows.Count - 1).Offset(1)
'ListBox2.RowSource = "'" & rngData.Parent.Name & "'!" & rngData.Address
Else
Debug.Print "Error, No data for given list item, which is kinda strange...."
Exit Sub
End If
'ListBox2.Clear
Ebene1kategorie = GetEbene1List()
ListBox2.List = Ebene1kategorie
ListBox2.ListIndex = -1
End Sub
Private Function GetEbene1List() As Variant
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim vReturn As Variant
Dim i As Integer
Set rngData = ArticleCriteria.Range("A6").CurrentRegion
Set rngCrit = CategoryCriteria.Range("d1:d2")
Set rngExt = CategoryCriteria.Range("d6")
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt, True
Set rngExt = rngExt.CurrentRegion
' Sort the cities ascending
rngExt.Sort Key1:=rngExt.Resize(1, 1), Header:=xlYes, Order1:=xlAscending
If rngExt.Rows.Count > 1 Then
vReturn = rngExt.Resize(rngExt.Rows.Count - 1).Offset(1)
Else
' Use this to return "no data" message
vReturn = noDataArray()
End If
GetEbene1List = vReturn
For i = 3 To 8
With ArtikelSuche
.Controls("Listbox" & i).Clear
End With
Next i
End Function
Private Sub ListBox2_Change()
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim Ebene2kategorie() As Variant
CategoryCriteria.Range("E2").ClearContents
CategoryCriteria.Range("G2").ClearContents
CategoryCriteria.Range("I2").ClearContents
CategoryCriteria.Range("K2").ClearContents
CategoryCriteria.Range("M2").ClearContents
CategoryCriteria.Range("O2").ClearContents
If ListBox2.ListIndex = -1 Then Exit Sub ' nothing is selected, so quit
Debug.Print ListBox2.List(ListBox2.ListIndex)
CategoryCriteria.Range("c2").Value = ListBox2.List(ListBox2.ListIndex)
Set rngData = ArtikelDatasource.Range("A1").CurrentRegion
Set rngCrit = CategoryCriteria.Range("A1").CurrentRegion
Set rngExt = ArticleCriteria.Range("A6").CurrentRegion.Resize(1)
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt
Set rngData = rngExt.CurrentRegion
If rngData.Rows.Count > 1 Then
'If rngExt.Rows.Count < 3 Then
'Set rngData = rngData.Resize(rngData.Rows.Count - 0).Offset(1)
'ListBox2.RowSource = "'" & rngData.Parent.Name & "'!" & rngData.Address
'Else
Set rngData = rngData.Resize(rngData.Rows.Count - 1).Offset(1)
'End If
Else
Debug.Print "Error, No data for given list item, which is kinda strange...."
Exit Sub
End If
'ListBox2.Clear
Ebene2kategorie = GetEbene2List()
ListBox3.List = Ebene2kategorie
ListBox3.ListIndex = -1
End Sub
Private Function GetEbene2List() As Variant
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim vReturn As Variant
Dim i As Integer
Set rngData = ArticleCriteria.Range("A6").CurrentRegion
Set rngCrit = CategoryCriteria.Range("f1:f2")
Set rngExt = CategoryCriteria.Range("f6")
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt, True
Set rngExt = rngExt.CurrentRegion
' Sort the cities ascending
rngExt.Sort Key1:=rngExt.Resize(1, 1), Header:=xlYes, Order1:=xlAscending
If rngExt.Rows.Count > 1 Then
'If rngExt.Rows.Count < 3 Then
' vReturn = rngExt.Resize(rngExt.Rows.Count - 0).Offset(1)
' Else
vReturn = rngExt.Resize(rngExt.Rows.Count - 1).Offset(1)
' End If
Else
' Use this to return "no data" message
vReturn = noDataArray()
End If
GetEbene2List = vReturn
For i = 4 To 8
With ArtikelSuche
.Controls("Listbox" & i).Clear
End With
Next i
End Function
(and the code goes further like this: the listboxes are all done in this way)
When you assign the value of a range to a variant Excel will create a string or numeric value if the range comprises a single cell, or an array if there are more than one cell in the range. Try this test:-
Private Sub TestArray()
' 271
Dim Arr1 As Variant
Dim Arr2 As Variant
With ActiveSheet
Arr1 = .Range(.Cells(1, 1), .Cells(1, 1)).Value
Arr2 = .Range(.Cells(1, 1), .Cells(2, 1)).Value
End With
Debug.Print VarType(Arr1), VarType(Arr2)
End Sub
VarType(Arr1) will return 5 or 8 (numeric or string), depending upon what cell A1 contains, and 8204 for Arr2. Any number below 8200 indicates that the variant is not an object. Debug.Print Arr1(1, 1) will return an error because Arr1 isn't an array.
In the procedure below the above test is incorporated. If the filter returned a single item and vReturn therefore is not an array the code converts the value to an array and assigns the single value to it. In consequence, vReturn(1, 1) will not throw an error as it did while this treatment was omitted.
Private Function GetEbeneList(ByVal Clm As Long) As Variant
' 271
' Clm = 4 (column D) or 6 (column F)
Dim vReturn As Variant
Dim Tmp As Variant
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim i As Integer
Set rngData = ArticleCriteria.Range("A6").CurrentRegion
With CategoryCriteria
Set rngCrit = .Range(.Cells(1, Clm), .Cells(2, Clm))
Set rngExt = .Cells(6, Clm)
End With
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt, True
With rngExt.CurrentRegion
If .Rows.Count > 1 Then
' Sort the cities ascending
.Sort Key1:=.Resize(1, 1), Header:=xlYes, Order1:=xlAscending
vReturn = .Resize(.Rows.Count - 1).Offset(1).Value
Else
' Use this to return "no data" message
vReturn = noDataArray()
End If
End With
If VarType(vReturn) < 8200 Then
Tmp = vReturn
ReDim vReturn(1 To 1)
vReturn(1, 1) = Tmp
End If
GetEbeneList = vReturn
For i = 3 To 8
ArtikelSuche.Controls("Listbox" & i).Clear
Next i
End Function
The code is untested (last, not least, because I don't have your function NoDataArra()) and may therefore contain bugs for which I apologize. To compensate, I have made some changes.
Basically, your functions GetEbene1List and GetEbene2List are identical except for the column they refer to. Instead of creating 2 functions, one would create one and supply the column variable as an argument. This idea is incorporated above.
So, instead of your existing function call ...
Ebene1kategorie = GetEbene1List()
ListBox2.List = Ebene1kategorie
ListBox2.ListIndex = -1
You should now call ...
With ListBox2
.List = EbeneKategorie(4)
.ListIndex = -1
End With
There are more syntax changes in the code that don't need explanation. They just offer more opportunity for typos and logical errors to have crept in :-)
Thank you sooo much for investing your time into my question. I really had to come to this group and ask professionals, because I was soo stucked, and I will be very honest: i have really really basic idea of programming. I do also Arduino, joomla etc, but all hobby stuff. My aim was actually to have a bunch of Data from Columne A:X (as an example) and have a Userform with X listboxes.
What the first listbox does, it actually checks all the Values in Column A and only display those who are diffrent from eachother, lets say you have 400 rows, only 3 different Values, so Listbox 1 has 3 Rows in this case.
If you click a row in the Listbox1, then the Columne B will be Checked according to what was selected in Listbox1, so in this case Columne A and Listbox 2 only shows the next value so on...
This way you can have a cool Search system. I found this gentlemans Idea cool regarding the cities, so I came home today after work and solved it.
I solved it on a nooby way, but it works. And I will try your solution as well.
This is how I did it :( (just showing you 1 Listbox and the function). Yes I used errorhandle. Let me know your thinking about this solution :)
Kind regards
Private Sub ListBox2_Change()
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim Ebene2kategorie() As Variant
Dim Ebene2kategorie2(1 To 1, 1 To 1) As Variant
CategoryCriteria.Range("E2").ClearContents
CategoryCriteria.Range("G2").ClearContents
CategoryCriteria.Range("I2").ClearContents
CategoryCriteria.Range("K2").ClearContents
CategoryCriteria.Range("M2").ClearContents
CategoryCriteria.Range("O2").ClearContents
If ListBox2.ListIndex = -1 Then Exit Sub ' nothing is selected, so quit
Debug.Print ListBox2.List(ListBox2.ListIndex)
CategoryCriteria.Range("c2").Value = ListBox2.List(ListBox2.ListIndex)
Set rngData = ArtikelDatasource.Range("A1").CurrentRegion
Set rngCrit = CategoryCriteria.Range("A1").CurrentRegion
Set rngExt = ArticleCriteria.Range("A6").CurrentRegion.Resize(1)
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt
Set rngData = rngExt.CurrentRegion
If rngData.Rows.Count > 1 Then
Set rngData = rngData.Resize(rngData.Rows.Count - 1).Offset(1)
Else
Debug.Print "Error, No data for given list item, which is kinda strange...."
Exit Sub
End If
On Error GoTo zero
Ebene2kategorie() = GetEbene2List()
ListBox3.List = Ebene2kategorie
ListBox3.ListIndex = -1
Exit Sub
zero:
Ebene2kategorie2(1, 1) = GetEbene2List()
ListBox3.List = Ebene2kategorie2
On Error GoTo 0
ListBox3.ListIndex = -1
End Sub
…
Private Function GetEbene2List() As Variant
Dim rngData As Range, rngCrit As Range, rngExt As Range
Dim vReturn2(1 To 1, 1 To 1) As Variant
Dim vReturn As Variant
Dim i As Integer
Set rngData = ArticleCriteria.Range("A6").CurrentRegion
Set rngCrit = CategoryCriteria.Range("f1:f2")
Set rngExt = CategoryCriteria.Range("f6")
rngData.AdvancedFilter xlFilterCopy, rngCrit, rngExt, True
Set rngExt = rngExt.CurrentRegion
' Sort the cities ascending
rngExt.Sort Key1:=rngExt.Resize(1, 1), Header:=xlYes, Order1:=xlAscending
If rngExt.Rows.Count > 1 And rngExt.Rows.Count < 3 Then
vReturn2(1, 1) = rngExt.Resize(rngExt.Rows.Count - 1).Offset(1)
GetEbene2List = vReturn2(1, 1)
ElseIf rngExt.Rows.Count > 1 Then
vReturn = rngExt.Resize(rngExt.Rows.Count - 1).Offset(1)
GetEbene2List = vReturn
Else
' Use this to return "no data" message
vReturn2(1, 1) = noDataArray()
End If
For i = 4 To 8
With ArtikelSuche
.Controls("Listbox" & i).Clear
End With
Next i
End Function
I have a macro that loops through cells of one sheet, looks for that value in another sheet, and then highlights the row if they match. I'd like to add a message box that would pop up if a matching value is not found. I know this is a simple problem, but I'm having trouble figuring out in which loop to put my booleans.
Sub MarkXfer_noX()
Dim rng As Range
Dim rng2 As Range
Set rng = Worksheets("Transferred Routings").UsedRange
Dim i As Integer
Dim j As Integer
Dim ProdCI As String
Dim found As Boolean
Dim intRowCount As Integer
intRowCount = Sheets("Transferred Routings").UsedRange.Rows.count
For i = 2 To intRowCount
If rng.Cells(i, 1) <> "" Then ProdCI = rng.Cells(i, 1) 'get the ProdCI number from column A if not blank
Worksheets("All_ProCI").Activate 'activate main page
Set rng2 = Worksheets("All_ProCI").UsedRange 'select a range on the main page
For j = 2 To rng2.Rows.count 'from row 2 to the end
If rng2.Cells(j, 2) = ProdCI Then 'if the ProdCI in column B matches the one we picked,
Call FillCell(j) 'call a sub in a different module and give it our current row
found = True
Else
found = False
End If
Next
Next
If found = False Then
MsgBox (ProdCI & " not found") 'Display a message if one of the items wasn't found on the main page. Currently has an error where the last one in the list always pops up.
Else
End If
End Sub
Right now it always shows a msgbox with the last value in the range no matter what.
Thanks all, here is the updated working code using the Find function
Sub MarkXfer_Find()
'Re-tooled to use the .Find function instead of looping through each
Dim rng As Range
Dim rng2 As Range
Set rng = Worksheets("Transferred Routings").UsedRange
Dim i As Integer
Dim ProdCI As String
Dim intRowCount As Integer
Dim intRowCount2 As Integer
Dim aCell As Range
intRowCount = Sheets("Transferred Routings").UsedRange.Rows.count
For i = 2 To intRowCount
If rng.Cells(i, 1) <> "" Then ProdCI = rng.Cells(i, 1) 'get the ProdCI number from column A if not blank
Worksheets("All_ProCI").Activate 'activate main page
Set rng2 = Worksheets("All_ProCI").UsedRange 'select a range on the main page
intRowCount2 = Worksheets("All_ProCI").UsedRange.Rows.count
'use the Find function to put a value in aCell
Set aCell = rng2.Range("B1:B" & intRowCount2).Find(What:=ProdCI, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'MsgBox ProdCI & " found"
Call FillCell(aCell.row)
Else 'If aCell is blank display msgbox
MsgBox "ProdCI """ & ProdCI & """ not found"
End If
Next
End Sub
I'm interested in a macro that will add a value in column P (Pass, At Risk or Failed) if column A has a certain condition - see below example.
I wonder if below macro can be used as inspiration. It was created to color a row if certain condition is met.
I'd also like the new macro to assign certain cell color in column P for value: Green for Pass, Yellow for At Risk and Red for Failed (same colors as in below macro)
Option Explicit
Sub Stackoverflow()
Dim ws As Worksheet
Dim rows As Long, i As Long
Dim rngSearch As Range, rngColor As Range
Application.ScreenUpdating = False
Application.EnableEvents = False
Set ws = ActiveSheet
rows = ws.UsedRange.rows.Count
For i = 1 To rows
Set rngSearch = ws.Cells(i, 1)
Set rngColor = ws.Range("A" & i, "O" & i)
If rngSearch = "Unexpected Status" Then
rngColor.Interior.Color = 13434828
End If
If rngSearch = "At Risk" Then
rngColor.Interior.Color = 8420607
End If
If rngSearch = "Requirements Definition" Then
rngColor.Interior.Color = 10092543
End If
Next i
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
This would make column P yellow, if rngSearch is "At Risk":
For i = 1 To rows
Set rngSearch = ws.Cells(i, 1)
Set rngColor = ws.Range("A" & i, "O" & i)
If rngSearch = "Unexpected Status" Then
rngColor.Interior.Color = 13434828
End If
If rngSearch = "At Risk" Then
Cells(rows, "P").Interior.Color = vbYellow
End If
If rngSearch = "Requirements Definition" Then
rngColor.Interior.Color = 10092543
End If
Next i
The others are to be made correspondingly.
Yes you can, simplified
Dim i As Long, lngColor as Long 'It is inadvisable to declare variables which could also be the name of built in functions and objects, in your case I would not declare "rows" as a variable as it is also a property of an object
Dim varVal as Variant
Dim ws As Worksheet
Set ws = Thisworkbook.Worksheets("Sheet1") 'As general advice, avoid active and select but used fixed values, this way no confusion can exist as to which sheet is used In my example it is Sheet1, but you have to set it to the actual name of your sheet
with ws
For i = 1 To .UsedRange.Rows.Count
Select Case .Cells(i, 1) 'Looks at the value of row i column A, and then below if it matches a case.
Case "Unexpected Status"
varVal = "Pass"
lngColor = 13434828
Case "At Risk"
varVal = "At Risk"
lngColor = 8420607
Case "Requirements Definition"
varVal = "Failed"
lngColor = 10092543
Case else
varVal = Empty
lngColor = 0
End Select
.Cells(i, 16) = varVal 'row i in column P is set to the value determined by the condition in the select case part
If Not lngColor = 0 Then 'This value of lngColor is only present if the select case did not match and if so, the color should not be changed
.Range(.Cells(i, 1), .Cells(i, 16)).Interior.Color = lngColor 'Set the range of row i column A to column P to the color specified by the case select.
End If
Next i
End With
I have tried to make a macro to color excel rows if certain conditions apply, however, when I run it I get a syntax error in this line:
If (Not item1 (Cells(matchline, 1)) Then GoTo continue
Also, I'd like for a certain range to be colored, not the entire row. I have this from another macro, but don't know how to apply it correctly in ColorRows:
Range(Cells(Rng.row, "A"), Cells(Rng.row, "M")).Interior.Color = xlNone
Current code:
Option Explicit
Sub ColorRows()
Dim matchline As Integer, lastmatchline As Integer, lastbinline As Integer
Dim item1 As String, line As Integer, endline As Integer
'For line = 3 To endline
For matchline = 6 To lastmatchline
item1 = Cells(matchline, 1).Value
If (Not item1 (Cells(matchline, 1)) Then GoTo continue
If Not item1(Cells(matchline, 1)) Then GoTo continue
If (item1 = "Unexpected Status") Then _
Cells(matchline, 1).EntireRow.Font.Interior.Color = 13434828
If (item1 = "At Risk") Then _
Cells(matchlineline, 1).EntireRow.Font.Interior.Color = 8420607
If (item1 = "Requirements Definition") Then _
Cells(matchlineline, 1).EntireRow.Font.Interior.Color = 10092543
continue:
Next line
End Sub
Try something like:
Dim ws As Worksheet
Dim rows As Long, i As Long
Dim rngSearch As Range, rngColor As Range
Application.ScreenUpdating = False
Application.EnableEvents = False
Set ws = ActiveSheet
rows = ws.UsedRange.rows.Count
For i = 1 To rows
Set rngSearch = ws.Cells(i, 1)
Set rngColor = ws.Range("A" & i, "M" & i)
If rngSearch = "Unexpected Status" Then
rngColor.Interior.Color = 13434828
End If
If rngSearch = "At Risk" Then
rngColor.Interior.Color = 8420607
End If
If rngSearch = "Requirements Definition" Then
rngColor.Interior.Color = 10092543
End If
Next i
Application.ScreenUpdating = True
Application.EnableEvents = True
I am getting a run time error on the below code , can you please assist.
The part and getting the error on is rngRange.Select. Can you advise in any way in which i can amend the below code? Thank you in advance
Sub NameRangeTop(Optional ByRef rngRange As Range)
If rngRange Is Nothing Then
Set rngRange = Application.Selection
Else
rngRange.Select
End If
Dim ActiveRange As Range
Dim NumRows, NumColumns, iCount As Long
Dim CurSheetName As String
CurSheetName = ActiveSheet.Name
Set ActiveRange = Selection.CurrentRegion
ActiveRange.Select
NumRows = ActiveRange.Rows.Count
NumColumns = ActiveRange.Columns.Count
If NumRows = 1 And NumColumns = 1 Then
MsgBox "No active cells in the surrounding area. Try running the macro from a different location", vbCritical, "Local Range Naming"
Exit Sub
End If
If NumRows = 1 Then
Set ActiveRange = ActiveRange.Resize(2)
NumRows = 2
End If
For iCount = 1 To NumColumns
ActiveRange.Resize(NumRows - 1).Offset(1, 0).Columns(iCount).Name = CurSheetName & "!" & ActiveRange.Rows(1).Columns(iCount).Value
Next
ActiveRange.Resize(NumRows - 1).Offset(1, 0).Select
End Sub
it's because the passed rngRangerange doesn't belong to currently active worksheet
code like this
If rngRange Is Nothing Then
Set rngRange = Application.Selection
Else
rngRange.Parent.Activate
rngRange.Select
End If