Scripting.Dictionary keys to Listbox VBA Excel - vba

I have been working with VBA in excel and recently began working with the Scripting.Dictionary object. I hadn't run across any major problems until today.
Basically I am trying to populate a listbox with the Key values of a dictionary, then add one more value to the listbox. This results in the value not only being added to the listbox, but also to the dictionary as a key. I have attempted to copy the values from the dict.keys() array to a completely separate array, but still have the same issue. I assume this is a byref problem but have yet to figure out a solution. If anyone has any ideas that would be awesome.
Private Sub Setup_settingLst()
'Set Settings listbox items
'On Error GoTo ErrorExit
Dim list_ary() As Variant
Dim tmp As Variant
Dim i As Integer
settingLst.Clear
settingLst.Value = "-Select Setting-"
i = 0
tmp = tmp_dict.Keys()
If tmp_dict.Count > 1 Then
ReDim list_ary(0 To tmp_dict.Count)
For i = 0 To UBound(tmp)
list_ary(i) = tmp(i)
Next i
list_ary(tmp_dict.Count) = "Back"
Else
ReDim list_ary(0 To tmp_dict.Count - 1)
For i = 0 To UBound(tmp)
list_ary(i) = tmp(i)
Next i
End If
settingLst.List = list_ary
Erase list_ary
Exit Sub
ErrorExit:
End Sub

This seems to work
Private Sub UserForm_Click()
Dim dcValues As Scripting.Dictionary
Me.ListBox1.Clear
Set dcValues = FillDictionary
Me.ListBox1.List = dcValues.Keys
Me.ListBox1.AddItem "Back"
End Sub

Related

Remove Listbox item if match not found in VBA

I am writing vba code that will search all listbox items against a entire column in a sheet.
If listbox item not found in Excel sheet column, i want to delete the item from list. I tried few codes, its showing some error as "Could not get list property, Invalid property array index". Below is my code i am using currently.
Private Sub CommandButton1_Click()
Dim itemExistResults As Boolean
Dim myarray()
Dim intItem As Long
myarray = Application.Transpose(Sheet1.Range("a2:a1000"))
For intItem = 0 To ListBox1.ListCount - 1
If IsInArray(ListBox1.List(intItem), myarray) Then
Else
ListBox1.RemoveItem intItem
End If
Next
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = UBound(Filter(arr, stringToBeFound)) > -1
End Function
Any idea where i am wrong in this code.
You should iterate from the last item of list to the first, because removing items changes their indexation.
Try to change your loop like that:
For intItem = ListBox1.ListCount - 1 To 0 Step -1
If IsInArray(ListBox1.List(intItem), myarray) Then
Else
ListBox1.RemoveItem intItem
End If
Next
I have a tip for you connected with your task, but not exactly with the error described in question.
For this type of task you should use object of Dictionary type instead of iterating through array - it would be much more effective.
I have modified your code to use dictionary. Check it and compare the time each of those solutions need to complete this task - the one with dictionary should be much faster. If you have any questions regarding this code, let me know in comments.
Private Sub CommandButton1_Click()
Dim myArray As Variant
Dim intItem As Long
Dim dict As Object
Dim i As Long
Dim value As Variant
'--- [Loading data into dictionary] ------------------------------------
Set dict = VBA.CreateObject("Scripting.Dictionary")
myArray = Sheet1.Range("A2:A1000")
'Iterate through all the items in array and load them into dictionary.
For i = LBound(myArray) To UBound(myArray)
value = myArray(i, 1)
If Not IsEmpty(value) Then
If Not dict.exists(value) Then
Call dict.Add(value, 0)
End If
End If
Next i
'-----------------------------------------------------------------------
'--- [Comparing ListBox with dictionary] -------------------------------
With ListBox1
For intItem = .ListCount - 1 To 0 Step -1
value = .List(intItem)
If Not dict.exists(value) Then
.RemoveItem intItem
End If
Next
End With
'-----------------------------------------------------------------------
End Sub

Type mismatch error in VBA when adding data to textbox

I have a TextBox and a ListBox with a list of various cities being populated from an Excel file
Now each city has one of two options: either within territory or outside. I want that option to be shown in textBox
I tried something like this :
Private Sub CommandButton1_Click()
TextBox2.Value = Application.VLookup(Me.ListBox1.Text,Sheets("Sheet1").Range("B:C"), 2, False)
End Sub
But am getting error stating that :
Run Time Error 2147352571 (80020005) . Could not set Value property. Type mismatch.
My excel file is something like this :
Let say your data are stored in Sheet1. You want to bind these data to ListBox1 on UserForm. I'd suggest to use custom function to load data instead of binding data via using RowSource property. In this case i'd suggest to use Dictionary to avoid duplicates.
See:
Private Sub UserForm_Initialize()
Dim d As Dictionary
Dim aKey As Variant
Set d = GetDistinctCitiesAndTerritories
For Each aKey In d.Keys
With Me.ListBox1
.AddItem ""
.Column(0, .ListCount - 1) = aKey
.Column(1, .ListCount - 1) = d.Item(aKey)
End With
Next
End Sub
'needs reference to Microsoft Scripting Runtime!
Function GetDistinctCitiesAndTerritories() As Dictionary
Dim wsh As Worksheet
Dim dict As Dictionary
Dim i As Integer
Set wsh = ThisWorkbook.Worksheets("Sheet1")
Set dict = New Dictionary
i = 2
Do While wsh.Range("A" & i) <> ""
If Not dict.Exists(wsh.Range("B" & i)) Then dict.Add wsh.Range("B" & i), wsh.Range("C" & i)
i = i + 1
Loop
Set GetDistinctCitiesAndTerritories = dict
End Function
After that, when user clicks on ListBox, city and territory are displayed in corresponding textboxes.
Private Sub ListBox1_Click()
Me.TextBoxCity = Me.ListBox1.List(Me.ListBox1.ListIndex, 0)
Me.TextBoxTerritory = Me.ListBox1.List(Me.ListBox1.ListIndex, 1)
End Sub
Note: code was written straight from the head, so it can contains errors!
The problem is likely that you aren't checking to see to see if the call to Application.VLookup succeeded. Most values returned can be successfully cast to a String - with one important exception: If the VLookup returns an error, for example it doesn't find Me.ListBox1.Text - it can't cast the Variant returned directly.
This should demonstrate:
Private Sub ReturnsOfVLookup()
Dim works As Variant, doesnt As String
works = Application.VLookup("Something not found", _
Sheets("Sheet1").Range("B:C"), 2, False)
Debug.Print works
On Error Resume Next
doesnt = Application.VLookup("Something not found", _
Sheets("Sheet1").Range("B:C"), 2, False)
If Err.Number <> 0 Then
Debug.Print Err.Description
Else
Debug.Print doesnt 'We won't be going here... ;-)
End If
End Sub

Why ListBox doesn't have a FindString method in Excel-VBA?

Trying to search on a ListBox. Specifically, I want to look at an array of items from the Cell, and for each one that matches an entry in the ListBox, I want it to select that List.
I copy-pasted some code that was supposed to let me find a string, but it keeps telling me:
Compile Error: Method or Data Member not found.
Any suggestions?
Relevant Code:
Public local_Target As Range
' local_Target is assigned in the sheet function to pass it here
Private Sub Network_ListBox_Enter()
' Get data in cell (if any)
Dim current_data As String
Dim entries() As String
current_data = local_Target.Value
If current_data = "" Then
Exit Sub
Else
entries = Split(current_data, vbNewLine)
End If
For Each Item In entries
FindMyString Item
Next Item
End Sub
Private Sub UserForm_Terminate()
Dim index As Integer
Dim result As String
' Iterate through the listbox and create the result, then assign to
' Target.value
For index = 0 To Network_ListBox.ListCount - 1
If Network_ListBox.Selected(index) Then
' stuff
If result = "" Then
result = Network_ListBox.List(index)
' ElseIf index = Network_ListBox.ListCount - 1 Then
' result = result + Network_ListBox.List(index)
Else
result = result + vbNewLine + Network_ListBox.List(index)
End If
End If
Next index
local_Target.Value = result
End Sub
Sub FindMyString(ByVal searchString As String)
' Ensure we have a proper string to search for.
If searchString <> "" Then
' Find the item in the list and store the index to the item.
Dim index As Integer
index = Me.Network_ListBox.FindString(searchString)
' Determine if a valid index is returned. Select the item if it is valid.
If index <> -1 Then
Network_ListBox.SetSelected index, True
'Else
' MessageBox.Show ("The search string did not match any items in the ListBox")
End If
End If
End Sub
I checked Intellisense and I don't think that Method is supported in VBA. Other documentations I've found refers to .Net Framework only as well. So maybe, it is not really supported in VBA, but regardless, you can create a function to do just that. Something like below.
Private Function SearchString(mysearch As String, mylist As Variant) As Long
Dim itm As Variant, idx As Long: idx = 0
If IsArray(mylist) Then
For Each itm In mylist
If mysearch = itm Then
SearchString = idx: Exit Function
End If
idx = idx + 1
Next
End If
SearchString = -1
End Function
And you can use it like this:
Private Sub CommandButton1_Click()
Dim i As Long
'do the search
i = SearchString("WhatImSearching", Me.ListBox1.List)
'select the item that match your search
If i <> -1 Then Me.ListBox1.Selected(i) = True
End Sub
I'm not saying that the function I created above is the most efficient way.
That is just an example to give you an idea for a workaround. HTH.
Important: This works in single column ListBox which have a 1D array list. If you need to work on multi-column ListBox, you'll have to tweak the function a little.

Sort Function (ascending) for Userform Listbox Excel

I am an IT enthusiast but I am not too good with programming or VBA. As a side project, I am compiling some data and would like to make it user friendly. I am new to forums so any advice would be welcome.
I have a Userform with a Listbox which has a large list of cities, but the list is unsorted. I understand i can go into the last page where I have the country capital list connected to the Listbox and sort the column there directly in the worksheet, but that would ruin my country list, so i would like to sort the list within the Userform Listbox, is there a way to do this?
I would also like to be able to add a Userform 'find' function within the Userform itself, as I have already done so, but I am unsure how to make it work despite trying some code, I failed, if you do know, then it would be great to hear whatever kind of advice, Thank you in advance.
Please find file in the link below with an image describing objectives and the code i currently have.
File:
https://www.sendspace.com/file/d4iaui
Sub Listb(target)
Location.ListBox1.List = Range("countrycapital").Value
For j = 0 To Location.ListBox1.ListCount - 1
Location.ListBox1.Selected(j) = False
Next j
currentrow = target.Row
'Location.Cells(19, 2) = Sheets("Practice List").Cells(target.Row, 3)
locval = target & ","
k = 0
For i = 1 To Len(locval)
Length = Abs(k - Application.WorksheetFunction.Search(",", locval, i))
Values = Mid(locval, i, Length - 1)
For j = 0 To Location.ListBox1.ListCount - 1
If Location.ListBox1.List(j) = Values Then
Location.ListBox1.Selected(j) = True
GoTo nxt
End If
Next j
nxt:
i = Application.WorksheetFunction.Search(",", locval, i)
k = i
Next i
Location.Show
End Sub
Sub newlocation()
Location.ListBox1.List = Range("countrycapital").Value
For j = 0 To Location.ListBox1.ListCount - 1
Location.ListBox1.Selected(j) = False
Next j
Location.Show
End Sub
Private Sub CommandButton1_Click()
Call ThisWorkbook.checkcriteria
End Sub
Private Sub CommandButton2_Click()
End Sub
Private Sub ListBox1_Click()
End Sub
Private Sub UserForm_Initialize()
Dim vaItems As Variant
Dim i As Long, j As Long
Dim vTemp As Variant
Me.ListBox1.AddItem "B" 'these new added values show on the userform
Me.ListBox1.AddItem "A" ' instead, I would like the original Listbox1...
Me.ListBox1.AddItem "D" ' ...incorporated within the sort function
Me.ListBox1.AddItem "C"
'Put the items in a variant array
vaItems = Me.ListBox1.List
'Steal code from John Walkenbach’s Excel Power Programming
'with VBA to sort the array
For i = LBound(vaItems, 1) To UBound(vaItems, 1) - 1
For j = i + 1 To UBound(vaItems, 1)
If vaItems(i, 0) > vaItems(j, 0) Then
vTemp = vaItems(i, 0)
vaItems(i, 0) = vaItems(j, 0)
vaItems(j, 0) = vTemp
End If
Next j
Next i
'Clear the listbox
Me.ListBox1.Clear
'Add the sorted array back to the listbox
For i = LBound(vaItems, 1) To UBound(vaItems, 1)
Me.ListBox1.AddItem vaItems(i, 0)
Next i
End Sub
Private Sub ListBox1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
HookListBoxScroll Location, Location.ListBox1
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
UnhookListBoxScroll
End Sub
My 2 cents :
- in order to sort things, I usually use the .Net Sort function. Some are accessible via Com Wrapper : CreateObject("System.Collections.ArrayList")
- this object has a .Contains function, that could be use by your Find function.
Hope this helps !

Loop through single column of Userform

I've worked with userforms in VBA a bit and know some of the tricks for looping through all controls. However, I'm running into issues with this one, and need a way to read the values of the line and reason columns into arrays based upon the values of "Area" and "Shift". The possible values for these two columns are in the picture.
Basically what I need is something like
For Each ctl In Me.Controls
If somectl.Value = "Kitting" And otherctl.Value = "1" Then
ReDim Preserve somearray(i)
somearray(i) = ctl.Value
End If
Next ctl
If you've manage to standardized your naming, you can do it like this:
Private Sub CommandButton1_Click()
Dim i As Integer
Dim areaCB As MSForms.ComboBox
Dim shiftCB As MSForms.ComboBox
Dim reasonCB As MSForms.ComboBox
Dim somearray
For i = 1 To 3 ' 3 or more depending on how may you have in your form
Set areaCB = Me.Controls("areadd" & i)
Set shiftCB = Me.Controls("shiftdd" & i)
Set reasonCB = Me.Controls("reasondd" & i)
If areaCB.Value = "Kitting" _
And shiftCB.Value = "1" Then
If IsArray(somearray) Then
ReDim Preserve somearray(UBound(somearray) + 1)
somearray(UBound(somearray)) = reasonCB.Value
Else
somearray = Array(reasonCB.Value)
End If
End If
Next
End Sub
So for example in areadd1, 1 is the row number.
Correspondingly, the ComboBox next to it to the right is shiftdd1 and so on.
This is just to give you idea. Modify it to suit your needs.