Changing the Name of an Excel ActiveX ListBox - vba

I have a set of ActiveX controls and subs that fit together like this:
User types into an ActiveX TextBox,
TextBox_Click triggers execution of 3 subs.
The first sub updates the value of a named range on a sheet; based on that updated value a table is created in excel using an offset function
The second sub copies the table range updated in 3 and paste.values into a range on the sheet (to eliminate formulas)
Here's where it is breaking down.
When I set the sheet up I create one ListBox (ListBox1). The third of the three subs mentioned in #2 above tests to see if ActiveX 'ListBox1' exists in the sheet. If not, the intention is the code will determine what the ListBox is called (LB1 or LB2 or LB2 etc), changes the name to 'ListBox1', and pastes the table from #4 above into ListBox1. Then a ListBox1_Click command could trigger a unique set of code to execute.
Right now I'm just testing switching between the names ListBox1 and ListBox2.
The idea is that as a user types into TextBox1 for example, ListBox1 updates at every keystroke. So type "g" and the list shows 20 names starting with the first "g" in the database sheet. Then type "ge" and the list shows 20 names starting with the first "ge" in the database sheet etc etc. The user clicks on a name and ListBox1_click does something unique. If the user was typing in TextBox2 they would see different data in the ListBox (which I would like to rename as ListBox2) and if they click a unique set of code is executed by ListBox2_Click.
The problem in #5 is the I get error 'Object doesn't support this property or method' the FIRST time I try to execute. The second time it is ok. If I do something else on the sheet and come back to it i get the error again.
Here is the code for #5 which is in a Module:
Sub PutListInListBox()
Dim OBJ As Object
On Error Resume Next
Set OBJ = ActiveSheet.OLEObjects("ListBox1")
On Error GoTo 0
If OBJ Is Nothing Then
ActiveSheet.ListBox2.Name = "ListBox1"
End If
ActiveSheet.ListBox1.Clear
ActiveSheet.ListBox1.List = Sheets("Search Criteria Control").Range("G1:G21").Value
End Sub
I have no idea what I'm doing wrong and any help is appreciated.
I hope I'm making this clear.
UPATED CODE
I have a bunch of ActiveX Lables and Text boxes so I used the first form you suggested to search for specific name Cases. I've been reading about it and can't see what I have wrong here. After typing in TB5, the LB doesn't update. I click back to Design Mode and can see that the name is still ListBox2.
Any ideas?
Private Sub TextBox5_Change()
Call UpdateValues(TextBox5.Value)
Call CopyTable
Dim OLEOBJ As OLEObject
For Each OLEOBJ In ActiveSheet.OLEObjects
Select Case OLEOBJ.Name
Case "ListBox1", "ListBox2", "ListBox3"
OLEOBJ.Name = "ListBox1"
OLEOBJ.ListFillRange = Sheets("Search Criteria Control").Range("G1:G21").Address(external:=True)
End Select
Exit For
Next
End Sub

I'll concentrate on your Code#5.
First, if you are changing the name of the ListBox Object, it is better to iterate the Object Collection it belongs to since you are not sure of it's name. Something like this:
Dim oleobj As OLEObject
Dim sh As Worksheet: Set sh = ActiveSheet
For Each oleobj In sh.OLEObjects
Select Case oleobj.Name
Case "LB1", "LB2", "ListBox1", "ListBox2" 'put the possible names here
oleobj.Name = "ListBox1" 'change it to the name you want
End Select
Exit For 'if you have more than 1 ListBox
Next
If you just want to change the name of an existing ListBox, then skip the checking.
For Each oleobj In sh.OLEObjects
oleobj.Name = "ListBox1"
Exit For 'if you have more than 1 ListBox
Next
Now, to assign values or list to it, you can directly assign the source Range, using ListFillRange Property after you've change its name.
oleobj.ListFillRange = Sheets("Search Criteria Control") _
.Range("G1:G21").Address(, , , True) 'add this line within the loop
Take note that you need not clear the previous list. It will automatically update. Since I'm not sure what you want to achieve entirely, I'll stop here. HTH though.

Related

How to make the Combobox item list dynamic?

I am using a 'Generate' button on my worksheet. When I click on the button, a popup (form) come, which contains two comboboxes. Basis the selection in the first combobox, the second combobox option list is populated.
For the first combobox, when I hardcode the item values it works fine. The form code is as follows:
Private Sub UserForm_Initialize()
With ComboBox_DL
.AddItem "DL1"
.AddItem "DL2"
End With
End Sub
I tried to make this item list dynamic by fetching the combobox item values from a column the in the excel worksheet using the following form code:
Private Sub UserForm_Initialize()
With ComboBox_DL
For Each c In ActiveSheet.Range(Range("AE"), Range("AE").End(xlDown))
.AddItem c.Value
Next
End With
End Sub
But the above code throws error: Run time error '1004': Method 'Range' of object '_Global' failed
I modified the code adding sheet details:
With ComboBox_DL
For Each c In ThisWorkbook.Worksheets("Business_Input_Data").Range(Range("AE"), Range("AE").End(xlDown))
.AddItem c.Value
Next
It still throws the same error.
Can someone help please? Also, I want to know how to look up the values corresponding to the selection in combobox1 and populate the list in combobox2?
If your combobox entries are a list on a worksheet, you don't need to use VBA to fill them at all. Instead, you can create a Dynamic Named Range, and use that as the Rowsource for the combobox.
Say your list starts on Sheet3, cell A1. Go to Formulas | Name Manager to create a named range. Give it a useful name like "Combo", then put the following formula into RefersTo: =OFFSET(Sheet3!$A$1,0,0,COUNTA(Sheet3!$A:$A),1) Save and close the Named Ranges dialogue.
In the properties of your combobox, look for the line "RowSource". Set it to =Combo, or whatever name you used for your named range.
Any changes to the list, including lengthening or shortening it, will now be reflected immediately and automatically in the combo box.
EDITED TO ADD:
To use the value selected in the first combobox to determine what list is used in a second combobox, we'll need to do two things.
The first is to create named ranges for all the possible selections in the first list:
In the image, column A is the source for our first combo box; the other columns contain the possible sources for the second combo box.
We then just need to put a little bit of code in the Change event for the first combobox:
Private Sub ComboBox1_Change()
Me.ComboBox2.Value = ""
Me.ComboBox2.RowSource = "=" & Me.ComboBox1.Value
End Sub
This code will trigger whenever ComboBox1 is changed. First it clears any existing value in ComboBox2, then it will set the row source property of ComboBox2 to a combination of the = symbol and whatever value was selected in the first box. Since those values are also named ranges, the second box will now use the selected named range as its list source.
If you needed to, you could add more levels of cascading options, with different named ranges for each one. More than a couple of levels may become unmanageable, though - at which point we may want to look at another method.
Havent tested this as i have not created the userform to test under same conditions, but should work subject to minor alterations.
Dim n As Long
n = Sheets("Business_Input_Data").Cells(Rows.Count, "AE").End(xlUp).Row
With ComboBox_DL
For Each c In ThisWorkbook.Worksheets("Business_Input_Data").Range("AE" & n)
.AddItem c.Value
Next
you're missing the row index in "AE"
furthermore use always explicit worksheet qualification in any Range reference
Private Sub UserForm_Initialize()
Dim c As Range
With ComboBox_DL
For Each c In For Each c In ThisWorkbook.Worksheets("Business_Input_Data").Range(ThisWorkbook.Worksheets("Business_Input_Data").Range("AE1"), ThisWorkbook.Worksheets("Business_Input_Data").Range("AE1").End(xlDown))
.AddItem c.Value
Next
End With
End Sub
but more elegant solutions are:
Private Sub UserForm_Initialize()
With ThisWorkbook.Worksheets("Business_Input_Data")
ComboBox_DL.RowSource = .Range("AE1", .Range("AE1").End(xlDown)).Address
End With
End Sub
Private Sub UserForm_Initialize()
With ThisWorkbook.Worksheets("Business_Input_Data")
ComboBox_DL.List = .Range("AE1", .Range("AE1").End(xlDown)).Value
End With
End Sub
where:
the former binds your ComboBox list to the range values whose address is given as ComboBox RowSource property
the latter takes the values of the given range as Combobox values
This is a solution to dynamically update the comboBox with emails in one column range.
Dim c As Range
ComboBox1.Value = ""
ComboBox1.Clear
For Each c In Sheets("emails").Range("F5:F5000")
If c Like "*#*" Then
ComboBox1.AddItem c
End If
Next
The 'ComboBox.Value' Set the initial value.
The 'ComboBox.Clear' Clears the previous rows in the comboBox.

Not Understanding why I am receiving 'Subscript Out Of Range'

I have been working on this code in which I have a userform that has a mashup of listboxes and comboboxes. So far I have populated the listboxes but for some reason I am having trouble with the comboboxes (combobox1 and combobox2).
I have managed to populate the drop-down list for combobox1, and from that list I want to 'filter' through a named range that is already called out through the 'name manager'. The named range is called Range_Books.
Range_Books references two columns and a variable number of rows in table48 on sheet BOOKS or in VBA code Sheet7. The code below is my latest iteration of attempting to accomplish what I have explained but it still has failed.
I originally was attempting to call out the range directly without the Worksheets("Sheet7"). since the named range is not on a specific sheet, but I am still not sure which is the best way to call out the range and if that is the root of my problem. I have called out the range directly without the worksheets(" ") before which is why I am so perplexed by this.
It may be important to note that when the userform is initialized, it opens a secondary workbook in order to populate the listboxes. After initialization, various actions may be done before a value is chosen for combobox1, and thus activating the function I am trying to create. This secondary workbook stays open until the userform is closed. I mention this because I am unsure if the secondary workbook is causing issues with the range object. I have been receiving trouble from VBA since adding the opening of a secondary workbook functionality to the userform.
Private Sub ComboBox1_Change()
Dim count As Integer
Dim i As Integer
count = Worksheets("Sheet7").Range("Range_Books").Rows.count
For i = 0 To count
If Worksheets("Sheet7").Range("Range_Books").Cells(i, 1) = ComboBox1.Value Then
ComboBox2.AddItem (Worksheets("Sheet7").Range("Range_Books").Cells(i, 2))
End If
Next i
End Sub
You need to either start with For i = 1 to count, or change the ranges to .Cells(i+1,1)...
Also, make sure you're referring to the correct sheet. I think this is where the crux of your issue is.
If your named range is in a worksheet with the tab name "Books", then you need to instead use count = Worksheets("Books").Range("Range_Books").Rows.count
If you want to use the "Sheet7" reference instead, you could use count = Sheet7.Range("Range_Books").Rows.count
For i = 0 To count
...
Cells(i, 1)
at this point, i = 0. Row 0 Doesn't exist.
Change i = 0 to i = 1
Use this
Private Sub ComboBox1_Change()
Dim count As Integer
Dim i As Integer
Dim ws As WorkSheet
Set ws = Sheets("Sheet7")
count = ws.Range("Range_Books").Rows.count
For i = 1 To count
If Worksheets("Sheet7").Range("Range_Books").Cells(i, 1) = ComboBox1.Value Then
ComboBox2.AddItem (Worksheets("Sheet7").Range("Range_Books").Cells(i, 2))
End If
Next i
End Sub
Thank you everyone for the help, it is very much appreciated! My final working code is below. I changed all instances of Worksheets("Sheet7") to just Sheet7. I attached a picture of the Excel Objects folder tree, as you can see I have Sheet7 which I named "Books". My confusion was that Worksheets(" ") calls out the name I assign rather than the VBA assigned name for the sheet. I also added ComboBox2.Clear that way whenever ComboBox1 changes it resets the values rather then stacking them. I hope this helps somebody in the future and thanks again to the commentors who helped me!
enter image description here
Private Sub ComboBox1_Change()
ComboBox2.Clear
Dim count As Integer
Dim i As Integer
count = Sheet7.Range("Range_Books").Rows.count
For i = 1 To count
If Sheet7.Range("Range_Books").Cells(i, 1) = ComboBox1.Value Then
ComboBox2.AddItem (Sheet7.Range("Range_Books").Cells(i, 2))
End If
Next i
End Sub

VBA listbox select worksheet by index

I have a form with listbox which dynamically provides a list of the worksheets in the current workbook (code below). I wish to take the selected Sheet and refer to it in a formula later in the process. From hours of playing around I cannot seem to accomplish this. I believe I read somewhere that you cannot take the string back to the sub and use it to refer to to an object. So I thought maybe I can create two listboxes
for sheet name
for sheet index
that I could pass the index number to and maybe use that in my formula to lookup items from the correct sheet.
For the life of my I cannot seem to find a way to connect the two since the items will always be changing; the code will be ran on multiple workbooks by multiple operators so the layout will most likely change between users. I can easily add the second list box with index #'s but I have a block on how to associate the name which will have meaning to the user and the index which I can pass back to the sub. I realize the "On click" procedure for the list box to associate the two but with the dynamic nature of the fields I cannot come up with the logic to put that into code.
For N = 1 To ActiveWorkbook.Sheets.Count
With ListBox1
.AddItem ActiveWorkbook.Sheets(N).Name
End With
Next N
Try this out.
Declare a public variable above the code for the UserForm, making it available throughout your workbook from any module or code.
Public listChoice As String
Using your code to get the sheet names for the ListBox rowsource.
Private Sub UserForm_Activate()
For n = 1 To ActiveWorkbook.Sheets.count
With ListBox1
.AddItem ActiveWorkbook.Sheets(n).name
End With
Next n
End Sub
Including an update event for the ListBox
Private Sub ListBox1_AfterUpdate()
listChoice = ListBox1.Text
End Sub
I included a test just to demonstrate that the result is still retained. You don't need this, it demonstrates the results on the screenshot.
Private Sub cmdTestChoice_Click()
MsgBox ("The choice made on the ListBox was: " & listChoice)
End Sub
edit: To access that sheet later, you can call it using something like this:
Some examples of different ways to access a cell, using .Range, or .Cells, with numbers or letters.
Using lRow & lCol as Long to set row and column numbers.
Sheets(listChoice).Cells(lRow, lCol).Value = TextBox1.Value 'Set cell on sheet from TextBox
TextBox2.Value = Sheets(listChoice).Range("A2").Value 'Set TextBox From Cell on Sheet
'Set a cell on another sheet using the selected sheet as a source.
Sheets("AnotherSheet").Cells(lRow, "D") = Sheets(listChoice).Range("D2")

Excel macro select two ranges and compare

This is a question that was asked to me in an interview. I have a excel list. It is copied to another location and then by mistake a row in the new location gets deleted.
Now I need to write a macro to compare the old and new ranges and then provide the missing data as result.
I can perhaps perform the comparison part. But the problem is I don't know how to get the selected range as input in a macro.
For eg. as soon as I select a range, it should be sent as input to the macro, then the macro should wait for another selection. As soon as I select the new range, the macro should compare and find the missing lines in new range.
Regarding the selection per mouse click you could look at the link I sent in the comments of the other answer. Selection_Change is an event which gets triggered when you change the selection of a worksheet (not only mouseclick but move-by-keys as well). The target coming in is the cell which you have selected. You can pass this as a range on to a function.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
showMsg Target
End Sub
Private Function showMsg(r As Range)
MsgBox r.Address
End Function
You can just as well use another event like BeforeDoubleClick or BeforeRightClick. Check out the events of Excel and choose the one you feel fits best.
If you only want the function to be triggered for a certain range you can filter it.
If target.column <> 1 then exit function
If you don't want the event to trigger your function each time you change a selection you can choose one cell to be the switch which gets triggered by the same event.
If target.address = "$A$1" Then Call toggleSearch()
with toggleSearch being the switching function.
This is a classical diff (and a simple one at that), you shouldn't select by hand or anything. Just sort the two lists in an identical way, then run a Sub which loops over the number of rows in the source sheet comparing each row with the same row in the target sheet. The first mismatch you get is the missing line.
This example assumes both sheets are in the same workbook but you can easily adapt it
Public Sub diffThem()
Dim src as Worksheet, trg as Worksheet
Dim r as Range, i as Integer
Set src = ThisWorkbook.Sheets("Source")
Set trg = ThisWorkbook.Sheets("Destination")
Set r = src.Range("A1")
For i = 1 to ThisWorkbook.Sheets("Source").UsedRange.Rows.Count
If r.EntireRow <> trg.Range("A" & r.Row).EntireRow Then
MsgBox("The missing row is " & r.Row)
Exit Sub
End if
Set r = r.Offset(1,0)
Next i
End Sub
If EntireRow cannot be run due to different layouts or whatever then loop the columns at that point.

Find cell location based on value then do something- User Forms VBA Excel

i have experience in programing, however, I am new to VBA. I have a user form that i am working on. This form has a Combo Box that has a list initialized to it. What i am trying to do is:
*Get the ID Number value inputted by the user from the ComboBox
*Take the value inputted by the user and find its match using a range of values from a worksheet (i.e. Worksheet.Range("ID_Number_List"))
*Once it obtains it's match get the location of the cell that it matches
* Off set the location of the cell by one column to get the Name that relates to the ID Number(Same Row) to set it to textBoxName.Value
*Off set it two columns to get the telefone number that relates to the ID Number and set it to textboxTele.value
I want this to happen as soon as a value is selected from the Combobox, so my question is does my code go in the combo box or does it go to the next text box? so as soon as the person tabs over to the next text box the code is automatically execute. i would like the code to fully execute without tabing over to the next box.
This code is not complete but here is what i have (i didnt add the off set part i just did a test execution):
Dim ORIValue As String
'get value from combo_box Set
ORIValue = COMBO_ORILIST.Value
Dim cLoc As Range
Dim cORIVal As Range
'worksheet with the ID information Dim ORISheetList As Worksheet
Set ORISheetList = Worksheets("ORI_LIST")
'
For Each cLoc In ORISheetList.Range("ORI_LIST")
'compare the input string from list- considering using Match function for this
If StrComp(cLoc, ORIValue, vbTextCompare) Then TextBAgencyName.Value = "test"
Else: Next cLoc
End If
Let me know what you think. If i have to rewrite everything i will.
Your code doesn't compile.
If you have a userform with a single combobox called ComboBox1, you need to put your cell-finding code in the form code as follows:
Private Sub ComboBox1_Change()
MsgBox "yep, this is where the code should go"
End Sub
I suspect using the rowsource property of the combobox in combination with the index of the selected value you probably don't need to actually perform a search for the selected value. Something like this might work:
Private Sub ComboBox1_Change()
MsgBox Range(ComboBox1.RowSource).Cells(ComboBox1.ListIndex + 1)
End Sub
Hope that helps.