I've got three combo boxes in a workbook that I want to daisy chain together. Item lists for each combo box refresh when you hit the down arrow on the keyboard after clicking the drop down button on the combo box. The second combo box list is dependent on the selection made in the first combo box. I've built these using scripting dictionaries.
strCustComboBox is the value in the previous combo box that the current combo box should be dependent on.
rngProject is looking at a range with lots of quote IDs in it. I offset from this column to the column where the values for the previous combo box are held and if this value is equal to strCustComboBox then add rngCompany value to the scripting dictionary
I'm running into a problem in the loop where I am trying to de-duplicate the rngCompany values written into the scripting dictionary that is used to build the list to be shown in the combo box. My code is below.
Sub UpdateComboBox1FromDashData()
Dim strCustComboBox As MSForms.ComboBox
Dim strComboBox As MSForms.ComboBox
Dim rngCompany As Range
Dim rngProject As Range
Dim d As Object, c As Variant, i As Long
Worksheets("QuoteEditor").Unprotect "xxxx"
Application.ScreenUpdating = False
Set strCustComboBox = ThisWorkbook.Worksheets("QuoteEditor").ComboBox4
Set strComboBox = ThisWorkbook.Worksheets("QuoteEditor").ComboBox1
If strCustComboBox = "" Then
MsgBox "Please select a project first", vbOKCancel
Else
End If
ThisWorkbook.Worksheets("DashboardData").Select
Call FindLastRow("A", "10")
Set d = CreateObject("Scripting.Dictionary")
c = Range("A10:A" & strLastRow)
Set rngProject = ThisWorkbook.Worksheets("DashboardData").Range("A10:A" & strLastRow)
i = 1
For Each rngCompany In rngProject
If UCase(rngCompany.Offset(, 7).Value) = UCase(strCustComboBox) Then
If d.exists(rngCompany) = True Then
Else
d.Add rngCompany, i
i = i + 1
End If
Else
End If
Next rngCompany
For Each Item In d
strComboBox.AddItem (Item)
Next Item
I think where I am using d.exists(rngCompany) is wrong but I'm not sure. When the subroutine finishes I still get duplicate data return to the combo box list.
I've also tried the code below as per the suggested duplicate thread:
With d
For Each rngCompany In rngProject
If UCase(rngCompany.Offset(, 7).Value) = UCase(strCustComboBox) Then
If Not .exists(rngCompany) Then
d.Add rngCompany, Nothing
Else
End If
End If
Next rngCompany
End With
Can anyone see where either of these are going wrong?
You hid the answer to this in your own question (emphasis mine):
where I am trying to de-duplicate the rngCompany values
There is no way for d.Exists(rngCompany) to return true the way that you have this written, because you are keying the Dictionary on the range, not its contents. Since the items you are testing are part of the iteration For Each rngCompany In rngProject, you are guaranteed to have only distinct ranges.
The solution is trivial - you need to explicitly call the default member of rngCompany:
If Not d.Exists(rngCompany.Value) Then
d.Add rngCompany.Value, i
i = i + 1
End If
Related
I come to you because VBA literature online does not show many results for when dealing with Tables and list objects.
With the following code, I add the list object items to a list box in a user form. I iterate through the list object's rows. But I need to validate wether the row is hidden as sometimes there will be filters on the table in the spreadsheet:
With Main
.Clear
Dim i As Long
For i = 1 To tblDataMaster.ListRows.Count
If tblDataMaster.Row(i).Hidden = False Then
.AddItem
Dim j As Integer
For j = 0 To 9
.List(.ListCount - 1, j) = tblDataMaster.DataBodyRange(i, (j + 5))
Next j
End If
Next i
End With
As written of course, the code won't work since .Row is not a property of the list object. But just to illustrate, the If statement needs to validate if that row is hidden or not. If it is not, then it will populate the list box with it.
Something like .DataBodyRange(i,1) is not working either.
Any help, greatly appreciated.
The key is to use ListRow.Range.
Dim tblRow As ListRow
For Each tblRow In tblDataMaster.ListRows
If Not tblRow.Range.EntireRow.Hidden Then
...
End If
Next
Or if iterating by index:
For i = 1 To tblDataMaster.ListRows.Count
If Not tblDataMaster.ListRows(i).Range.EntireRow.Hidden Then
...
End If
Next
I have a sub, which is called during an initialize event in a userform. What this does is add in job ID #'s - job titles in a combo box (cmbReqFunding). Right now, it loads all jobs, but I was wondering how i can make this dependent upon the leader (txtELT) the jobs fall under. i.e. if Leader 1 is populated in txtELT then only populate cmbReqFunding drop down list with their jobs, and exclude all others.
Sub LoadReqs_Cmb()
Dim rWS As Worksheet: Set rWS = ThisWorkbook.Worksheets("Reqs")
If UserForm1.cmbFundingCategory.Value = "Req Reduction" Then
If rWS.Cells(x, 7) = txtELT.Value Then 'see if column 7 in sheet is ELT value
For x = 2 To rWS.Cells(Rows.Count, 1).End(xlUp).Row
UserForm1.cmbReqFunding.AddItem rWS.Cells(x, 2) & " - " & rWS.Cells(x, 5)
Next x
Else
End If
End If
End Sub
Is there a way to do this? Everything I've found online deals with hard-coded values within the module window instead of how I'm loading in these values.
I'm writing some VBA code for a user form. The values are selected in a listbox on the left (LB_Participants). Then "select" is pressed and the values are copied to a listbox on the right (LB_Output). I then want VBA to go through all these items seperatly in the LB_Output and look up other associated data from another worksheet. Problem I'm having is that somethimes the values are not selected. I check it with a messagebox and from time to time its blank. Then no associated data can be retrieved ofcourse.
Before starting to fill in the userform, if I just click once on LB_Output (even without selecting any value) I don't have this problem. Many people will be using the userform so I don't want to explain tot them that they have to click first on the listbox before continuing... Is there something I'm not doing right?
Blank Msgbox
Dim ListCount As Integer
Dim z As Integer
ListCount = UserForm2.LB_Output.ListCount
For z = 0 To ListCount - 1
UserForm2.LB_Output.Selected(z) = True
TextString = UserForm2.LB_Output.Value
MsgBox (TextString)
'Split Participants into seperate names and copy them to data sheet
WArray() = Split(TextString, ";")
For Counter = LBound(WArray) To UBound(WArray)
Dim LRNames As Integer
If IsEmpty(Sheets("Data").Range("A1")) = True Then
LRNames = 0
Else
LRNames = Sheets("Data").Range("A" & Application.Rows.Count).End(xlUp).Row
End If
Strg = WArray(Counter)
Sheets("Data").Cells(LRNames + 1, 1) = Trim(Strg)
Next Counter
Next z
Not sure I understand, but think you want to loop through all the items in LB_Output and process them regardless if selected or not - all the selection was done in the other listbox and those items moved to LB_Output.
This does not explicitly select each item, simply gets data from it.
For z = 0 to UserForm2.LB_Output.Listcount -1
' If you want to select the item to show 'progress' through the list,
' uncomment ...
' LB_Output.listindex = z
' The next line will still work as is
TextString = UserForm2.LB_Output.List(z)
'// Do processing with this item
Next
I apologise now as I am an absolute beginner (also my pictures and code haven't been generalised).
I have a drop down list box in Excel, populated by a range I selected whilst inside excel (ie right click the ActiveX Control after it has been placed and alter the properties). I would like it so that if certain items in the list are selected, other items are removed from the list so that they cannot be selected. Eg. there is a list A, B, and C, but upon a user selecting A, B disappears from the list.
My code is as follows. This first part codes for the drop down list
Sub Rectangle1_Click()
Dim SelShp As Shape, ListShp As Shape, SelList As Variant, i As Integer
Set SelShp = Sheet8.Shapes(Application.Caller)
Set ListBx = Sheet8.ListBox1
If SelShp.TextFrame2.TextRange.Characters.Text = "Select Buffers" Then
ListBx.Visible = True
SelShp.TextFrame2.TextRange.Characters.Text = "Set Buffers"
Else
ListBx.Visible = False
SelShp.TextFrame2.TextRange.Characters.Text = "Select Buffers"
For i = 0 To Sheet8.ListBox1.ListCount - 1
If Sheet8.ListBox1.Selected(i) = True Then
SelList = SelList & "; " & Sheet8.ListBox1.List(i)
End If
Next i
If SelList <> "" Then
Range("ListBox1Output") = Right(SelList, Len(SelList) - 1)
Else
Range("ListBox1Output") = ""
End If
End If
End Sub
This second code is what is supposed to remove items from the list
Private Sub ListBox1_Change()
If Sheet8.ListBox1.Selected(0) Then
Sheet8.ListBox1.RemoveItem 1
End If
End Sub
The problem is, when I try it out I get a run-time error '-2147467259 (80004005)': Unspecified error., and if I try and debug it highlights the 'Sheet8.ListBox1.RemoveItem 1', but I just don't know enough to know what I'm doing wrong. Any help would be much appreciated, and I'm sorry if I'm missing something really simple.
Edit: I've been working on this since I posted, and have found some solutions, but run into other roadblocks.
My first problem was that the .RemoveItem method wasn't doing anything. Turns out if a ListBox is populated by using the .ListFillRange method, .RemoveItem won't work – a ListBox has to be populated by using .AddItem if I later want to .RemoveItem.
After I worked that out, I decided to try and do what I want with simpler data:
I have 2 Listboxes and I populate one of them with data. Upon selecting an item in ListBox1, that item is copied into ListBox2, and it is removed from ListBox1. Also, if certain items in ListBox1 are selected, other items are removed from the listbox so that they cannot be selected. Eg. there is a list A, B, and C, but upon a user selecting A, B disappears from the list.
I have got my code to the point where it works in certain situations. Unfortunately, the sequence of the items is important, and for some reason, for certain sequences of items, the code does not work as expected – eg my generalised items happen to be: Germany, India, France, USA, England. Upon selecting 'Germany', this item appears in ListBox2, it is removed from ListBox1, and also, 'France' is removed from ListBox1. This works fine, until the items are put in alphabetical order, at which point upon selecting 'Germany', this item appears in ListBox2, it is removed from ListBox1, 'France' is removed from ListBox1, AND India and USA are moved into ListBox2...?? It's as if once 'France' has been deleted, whatever was below it is selected and runs through the first 2 loops of the ListBox1_Change() sub for some reason. Interrupting it with a messagebox works for some reason, but I can't work out how to interrupt it without using the messagebox...
My code is as follows, with some comments on what I tried included in it.
Populate ListBox1 with items in random positions
Sub Populate_ListBox1()
'Clear LB1 before populating it
Sheet1.ListBox1.Clear
Sheet1.ListBox2.Clear
Sheet1.ListBox1.AddItem "Germany"
Sheet1.ListBox1.AddItem "India"
Sheet1.ListBox1.AddItem "France"
Sheet1.ListBox1.AddItem "USA"
Sheet1.ListBox1.AddItem "England"
End Sub
Try to move selected ListBox1 items while changing what items are in ListBox1
Private Sub ListBox1_Change()
'Variable Declaration
Dim iCnt As Integer
Dim jCnt As Integer
Dim kCnt As Integer
'Move Selected Item from Listbox1 to Listbox2
For iCnt = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Selected(iCnt) = True Then
Me.ListBox2.AddItem Me.ListBox1.List(iCnt)
End If
Next
'Clear Selected Item from Listbox1
For iCnt = Me.ListBox1.ListCount - 1 To 0 Step -1
If Me.ListBox1.Selected(iCnt) = True Then
Me.ListBox1.RemoveItem iCnt
'Me.ListBox1.Selected(iCnt) = False 'Nope
'Exit For
End If
Next
'If Germany is in Listbox2, then remove France from LB1
For kCnt = 0 To Me.ListBox2.ListCount - 1
If Me.ListBox2.Column(0, kCnt) = "Germany" Then
For jCnt = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Column(0, jCnt) = "France" Then
Me.ListBox1.RemoveItem jCnt
'Me.ListBox1.Locked = True 'Nope
'Me.ListBox1.Enabled = False 'Nope
'Me.ListBox1.ListIndex = -1 'This crashes excel...
'MsgBox "blah" 'For some reason this works >.<
Exit Sub
End If
Next jCnt
End If
Next
End Sub
I'd really appreciate help with this, and would even take advice on using a different program that would work with excel (trying to alter items in a listbox based upon their index, which changes, rather than on their values is a nightmare)
I have a listbox named ListBox1 on Sheet1 of an Excel workbook.
Every time the user selects one of the items in the list, I need to copy its name to a variable named strLB.
So, if I have Value1, Value2, Value3, Value4 and the user selects Value1 and Value3, I need my strLB to come out as Value1,Value3.
I tried doing that post hoc with:
For i = 1 To ActiveSheet.ListBoxes("ListBox1").ListCount
If ActiveSheet.ListBoxes("ListBox1").Selected(i) Then strLB = strLB & etc.etc.
Next i
But this is very slow (I have 15k values in my listbox). This is why I need to record the selection in real time and not in a cycle, after the user is done inputting.
I'm going to also need a way to check if the user removed any of the previous selection.
Unfortunately for MSForms list box looping through the list items and checking their Selected property is the only way. However, here is an alternative. I am storing/removing the selected item in a variable, you can do this in some remote cell and keep track of it :)
Dim StrSelection As String
Private Sub ListBox1_Change()
If ListBox1.Selected(ListBox1.ListIndex) Then
If StrSelection = "" Then
StrSelection = ListBox1.List(ListBox1.ListIndex)
Else
StrSelection = StrSelection & "," & ListBox1.List(ListBox1.ListIndex)
End If
Else
StrSelection = Replace(StrSelection, "," & ListBox1.List(ListBox1.ListIndex), "")
End If
End Sub
The accepted answer doesn't cut it because if a user de-selects a row the list is not updated accordingly.
Here is what I suggest instead:
Private Sub CommandButton2_Click()
Dim lItem As Long
For lItem = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(lItem) = True Then
MsgBox(ListBox1.List(lItem))
End If
Next
End Sub
Courtesy of http://www.ozgrid.com/VBA/multi-select-listbox.htm
To get the value of the selected item of a listbox then use the following.
For Single Column ListBox:
ListBox1.List(ListBox1.ListIndex)
For Multi Column ListBox:
ListBox1.Column(column_number, ListBox1.ListIndex)
This avoids looping and is extremely more efficient.
Take selected value:
worksheet name = ordls
form control list box name = DEPDB1
selectvalue = ordls.Shapes("DEPDB1").ControlFormat.List(ordls.Shapes("DEPDB1").ControlFormat.Value)