combobox change event is firing every time in excel VBA - excel

I am getting an XML that contains data to be bound to combobox. While binding this data each time when an item is added to the combobox, its change event is fired. I want to fire change event only after data is bound and user selects any item.
Any help, code that can solve this problem?

Use a flag to indicate whether or not you want to handle the event;
private mblIsUpdating as boolean
...
sub addDataFromXml
mblIsUpdating = true
combo.additem ...
mblIsUpdating = false
end sub
sub combo_change
if (mblIsUpdating) then exit function
//handle change
end sub

In my experience, the combobox change event only fires when changing the combobox list of items if the combobox's value is not null. If this problem is happening when you first initialize the combobox, don't assign a default value until after you fill the combobox.
If you need to change the combobox list at other times, like Alex K says, create a boolean flag to indicate if you want to ignore the change event.
I'm not clear from your question if the change event is firing once as you populate the combobox or once for each .AddItem. If it is the latter issue, then you can cut down on the number of change events by creating an array of values for your combobox and assigning it to the combobox's .List.
Here is an example with a 2-d array that is populating the combobox with the names and paths of all the open workbooks. (A 1-d array also works.)
Private Sub InitializeComboBox()
Dim aList() As String
Dim i As Integer, iMax As Integer
' build combobox list with zero-based array
iMax = Application.Workbooks.Count - 1
ReDim aList(iMax, 2)
For i = 0 To iMax
With Application.Workbooks(i + 1)
aList(i, 0) = i
aList(i, 1) = .Name
aList(i, 2) = .Path
End With
Next i
With Me.ComboBox1
.ColumnCount = 3
.ColumnWidths = "0 pt;80 pt;220 pt"
.ListWidth = "300 pt"
.List = aList
End With
End Sub

Related

How to loop through listboxes in a vba user form

I have a VBA user form with 6 list boxes. Each list box contains related data in another list box on the same row e.g. list box 1 has an account code and list box 2 has an account name, etc. When a user selects an item within a listbox I want all other listboxes to select a corresponding row. How can I achieve this using a loop?
I know I can explicitly reference the list items as per
excelcise example
but I feel there must be a way to loop through available listboxes instead of listing them by name.
Private Sub CheckControls()
Dim contr As control
For Each contr In Controls
If TypeName(contr) = "ListBox" Then
Select Case contr.Name
Case "ListBox1":
Case "ListBox2":
Case "ListBox3":
'and so on....
End Select
End If
Next contr
End Sub
After a bit of troubleshooting I think I found the answer in the Controls collection. Within each list box I call a procedure which takes existing listbox index, topIndex (useful when using scrolbars) and its own name.
Private Sub lbox_gl_account_Change()
Call arrangeIndexOfLabels(Me.lbox_gl_account.listIndex,
Me.lbox_gl_account.topIndex, Me.ActiveControl.Name)
End Sub
The arrangeIndexOfLabels procedure loops through all controls in the collection and only affects those that are of type ListBox. It updates listIndex and topIndex for all ListBoxes except for the active one.
'Change index location of other listbox items according to the selected one
Private Sub arrangeIndexOfLabels(lngListIndex As Long, lngTopIndex As Long, strActiveControl As String)
Dim ctrlItem As Control
For Each ctrlItem In Me.Controls
If TypeName(ctrlItem) = "ListBox" Then
'Only changing index position of other list boxes than selected
If ctrlItem.Name <> strActiveControl Then
ctrlItem.listIndex = lngListIndex
ctrlItem.topIndex = lngTopIndex
End If
End If
Next ctrlItem
End Sub

How do I get the ListIndex of an Item in a Combobox when I have the Value, so I can remove the Item from a ListBox with the same list?

I have a Listbox SkuList whose list is equal to the list of a seperate Combobox SkuBox. What I am trying to do, is remove the value chosen for the Combobox SkuBox from the Listbox SkuList.
Private Sub UserForm_Activate()
Dim Esh As Worksheet
Set Esh = ThisWorkbook.Sheets("Result")
Dim r_sku As Range
If Esh.Range("A2") <> "" Then
For Each r_sku In Esh.Range("A2", Esh.Range("A2").End(xlDown))
Me.SkuBox.AddItem r_sku.Value
Next r_sku
End If
Me.SkuList.List = Me.SkuBox.List
End Sub
Private Sub SkuBox_Change()
Me.SkuList.List = Me.SkuBox.List
Me.SkuList.RemoveItem (SkuBox.Value)
End Sub
This last section about removing the item doesn't work, because .RemoveItem requires a ListIndex. My question is, how do I get the ListIndex of the SkuBox.Value?
You can use ListIndex, but that will not be accurate across controls. As soon as you start removing items, the indexes will be different for items in SkuList vs SkuBox.
I'm not up on my VBA, but I don't see any ID properties, so you'll need to do as stated. Loop thru and find the item by text.
The following should work, but my advice would be to get in there and play with this. If you debug and step through the code, the intellisense will give you a lot of information that you can use to discover properties and figure out how to do things.
Private Sub SkuBox_Change()
Dim selectedSkuBoxValue As String
selectedSkuBoxValue = SkuBox.Value
SkuList.ListIndex = -1
Dim listItem
For Each listItem In SkuList.List
If listItem = selectedSkuBoxValue Then
SkuList.Value = selectedSkuBoxValue
Exit For
End If
Next listItem
If SkuList.ListIndex > -1 Then
SkuList.RemoveItem SkuList.ListIndex
End If
End Sub

How to populate combobox values from textbox text in excel vba form

I have a problem in my VBA form in Excel and I'm trying to filter the value of a combobox using VLOOKUP from whatever I type in the textbox. How do I achieve this?
My code is:
Private Sub btnTemplateSearch_Click()
Dim filterInfo As Range
Set filterInfo = Worksheets("InfoDump").Range("E2:F46")
txtTemplateFilter.Text = filterInfo.Columns(2).Value
Me.cboTemplateType.List = Application.WorksheetFunction.VLookup(Me.txtTemplateFilter.Text, filterInfo,2,True)
Below is an example of a block of code that can be used to filter the list of ComboBox entries. I decided to Dim an array variable ListForComboBox at the module level such that all procedures in the module can access it. It gets populated at the form's init event by calling LoadListForComboboxArray. You can make changes to this procedure to update the range of input values or any other changes. The combobox's list property is set to this array.
Here's the caveat: you may want to consider tuning the below for performance. I included a textbox, and in the change event, I make a call to set the global array to a filtered version of the original array, based on textbox value. That means that the code will filter the array everytime you type a letter (so if you type "ABC", it will filter three times, creating a new array each time). You may want to assign that function to a different event (textbox exit, maybe) such that the code only fires once you leave the text box, and only once.
Let me know if you have trouble adapting the code:
Dim ListForCombobox() As String
Private Sub TextBox1_Change()
Me.ComboBox1.List = Filter(ListForCombobox, Me.TextBox1.Value)
Debug.Print "CALLED"
End Sub
Private Sub UserForm_Initialize()
LoadListForComboboxArray
Me.ComboBox1.List = ListForCombobox
End Sub
Private Sub LoadListForComboboxArray()
Dim rng As Range
Set rng = Sheets("Sheet1").Range("A1:A11")
ReDim ListForCombobox(1 To rng.Rows.Count)
For i = 1 To rng.Rows.Count
ListForCombobox(i) = rng(i).Value
Next i
Debug.Print ListForCombobox(1)
End Sub

Excel Combo Box Refresh Dropdown?

Is there a way to refresh a combobox?
I have the following VBA code. The dropdown is populated, until the If statement where the list is cleared and populated with the matched items.
At this point, the dropdown list only shows a single item with a scroll bar. But If I close the pulldown and reopen, it's fully populated correctly.
Private Sub ComboBox_SiteName_Change()
ComboBox_SiteName.DropDown
Dim v As Variant, i As Long
With Me.ComboBox_SiteName
.Value = UCase(.Value)
If .Value <> "" And .ListIndex = -1 Then
v = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
.Clear ' Clear all items
' Repopulate with matched items
For i = LBound(v, 1) To UBound(v, 1)
If LCase(v(i, 1)) Like "*" & LCase(.Value) & "*" Then
.AddItem v(i, 1)
End If
Next i
Else
' Repopulate with all items
.List = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
End If
End With
End Sub
The ComboBox_Change function gets called as the user types in the combo box.. the dropdown box turns from a list into a single line with Up/Down arrows after the Clear and Repopulate matched items..
but if I close the dropdown portion and reopen it lists all the items without Up/Down arrows.
The .ListRows value = 8 by the way.
I would like a way for the dropdown potion to either close and reopen.. or a VBA function to refresh the dropdown portion, Without external buttons or controls Please
Getting the list to ONLY show values that matched the text typed by the user so far, was a nightmare. Below is what I wrote which works (but took me a while!)
Note that the MacthEntry Property of the combo box MUST be set to "2 - frmMatchEntryNone" for the code to work. (Other values cause the combo box .value property store the text of the first value that matches what the user typed, and the code relies on it storing what they typed.)
Also note, the trick to get around the behaviour you observed, ie the combo boxes list of values not being sized correctly, was to use the code lines:
LastActiveCell.Activate
ComboBox_SiteName.Activate
Also, the code will pick up any items on the list that have the letters typed by the user ANYWHERE in their text.
Anyway, here's my code:
Private Sub ComboBox_SiteName_GotFocus()
' When it first gets the focus ALWAYS refresh the list
' taking into acocunt what has been typed so far by the user
RePopulateList FilterString:=Me.ComboBox_SiteName.Value
Me.ComboBox_SiteName.DropDown
End Sub
' #4 Private Sub ComboBox_SiteName_Change()
Private Sub ComboBox_SiteName_Enter()
Dim LastActiveCell As Range
On Error GoTo err_Handler
Set LastActiveCell = ActiveCell
Application.ScreenUpdating = False
With Me.ComboBox_SiteName
If .Value = "" Then
' Used cleared the combo
' Repopulate will all values
RePopulateList
.DropDown
Else
' #4 reducdant
' LastActiveCell.Select
' .Activate
' ===========================================
' #4 new code
' CheckBox1 is another control on the form
' which can receive the focus and loose it without event firing
CheckBox1.SetFocus
' This will trigger the GotFocus event handler
' which will do a refresnh of the list
.SetFocus
' ===========================================
End If
End With
Application.ScreenUpdating = True
Exit Sub
err_Handler:
Application.ScreenUpdating = True
Err.Raise Err.Number, "", Err.Description
Exit Sub
Resume
End Sub
Private Sub RePopulateList(Optional FilterString As String = "")
Dim i As Long
Dim ValidValues() As Variant
' #2 range now refers to just the data cells
ValidValues = Worksheets("Address").Range("Table5[SITE NAME]").Value
With Me.ComboBox_SiteName
If FilterString = "" Then
' All all values
.List = ValidValues
Else
' #2: .List cannot be set to have no items.
' so remove all but one
.List = Array("Dummy Value")
' Only add values that match the FilterString parameter
For i = LBound(ValidValues, 1) To UBound(ValidValues, 1)
If LCase(ValidValues(i, 1)) Like "*" & LCase(FilterString) & "*" Then
.AddItem ValidValues(i, 1)
End If
Next i
' #2 add this line to remove the dummy item
.RemoveItem (0)
End If
End With
End Sub
Private Sub ComboBox_SiteName_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Application.ScreenUpdating = False
End Sub
======================================================================
You could: Replace all your code with this which should give acceptable functionality (as long a the data source is in alpha order), and it's easy! However, it doesn't quite do what you wanted.
Private Sub ComboBox_SiteName_GotFocus()
With Me.ComboBox_SiteName
.List = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
End With
ComboBox_SiteName.DropDown
End Sub
Combo boxes can be set up to "filter as the user types" - so long as the data is in alphabetical order.
======================================================================
Note that in your code the following two lines cause the ComboBox_SiteName_Change event to start again. I suspect you need to add break points and debug you code more.
.Value = UCase(.Value)
.Clear ' Clear all items
Anyway, I hope this is job done.
this will be my first bounty if I get it, so please let me know if you need any more help. (I think it may be worth more than 50 points)
Harvey
================================================
PART 2:
To answer you comment issues:
(See the #2 tag in my code above)
To refer to a table column's data, excluding the header use:
=Table5[SITE NAME]
(This will be autogenerated when entering a formula if you click and drag over the data cells in a column).
The code has been altered accordlingly.
I used excel 2013 and 2010 and found that the .Activate event works in both.
See #3 for a minor change.
Please recopy all the code.
note that I introduced code to try and stop flickering using Application.ScreenUpdating, but it didn;t have any effect - I don't know why. I've left the code in so you can do further experiments should you need to.
NOTE the new procedure ComboBox_SiteName_KeyDown
================================================
PART 3:
To answer you comment issues:
It's a combo on a form ! - so make the change tagged with #4 above.
Harvey
Solved!
https://trumpexcel.com/excel-drop-down-list-with-search-suggestions/
You can do what is in the link with some modifications:
"ListFillRange" in combobox properties should be the last column (the one that is changing). If it is a userform the range will go under "RowSource".
And add this code:
Private Sub ComboBox1_Change()
Sheets("Where the data is").Range("B3") = Me.ComboBox1.Value
End Sub
Try changing the command from Change to DropButtonClick
This refreshes the list on a click of the drop down

Troble with updating the list box

I have Created a excel user form with three Combo box and list box with 3 columns.
When user selects a value from drop down list and click Add button it will be displayed in the list box - Done
When user selects a item in the list box it will again displays in drop down list - done
But when user selects the item in the list box and click update button its calling the ListBox
_click () function, I dont want it to call the listbox_click function
PLease help. updating the code
Code for adding value from drop down list to list box
Private Sub cmdAdd_Click()
Call lstValues.AddItem(AddPpayTierOption(cboPpayTier.Value))
lstValues.List(UBound(lstValues.List), COL_BRAND) = cboBrandTier.Value
lstValues.List(UBound(lstValues.List), COL_GEN) = cboGenTier.Value
End Sub
when clicks the item in the list box it will display the value in drop down list
Private Sub lstValues_Click()
Dim I As Long
cmdEdit.Enabled = True
cmdRemove.Enabled = True
If lstValues.ListIndex <> -1 Then
For I = 0 To lstValues.ColumnCount - 1
If I = 0 Then
cboPpayTier.Value = lstValues.Column(I)
Else
If I = 1 Then
cboBrandTier.Value = lstValues.Column(I)
Else
If I = 2 Then
cboGenTier.Value = lstValues.Column(I)
End If
End If
End If
Next I
End If
End Sub
when user click the update button code.
when it goes to lstValues.Column(j) = cboPpayTier.Value line its calling the lstValues_Click() function I don't want code to call that function. Please Help
Private Sub cmdEdit_Click()
Dim j As Long
Dim var As Variant
If lstValues.ListIndex <> -1 Then
For j = 0 To lstValues.ColumnCount - 1
If j = 0 Then
lstValues.Column(j) = cboPpayTier.Value
Else
If j = 1 Then
lstValues.Column(j) = cboBrandTier.Value
Else
If j = 2 Then
lstValues.Column(j) = cboGenTier.Value
End If
End If
End If
Next j
End If
End Sub
please let me for more clarification.
Two options:
Use Application.EnableEvents = False to disable event processing. And Application.EnableEvents = True to re-enable. Note, this disables all event handling, so place it either side of code that would otherwise trigger an event you don't want.
Declare a global flag. Set it just before code that will trigger an event you don't want. In the Event Sub itself, examine the flag, and exit if it's set. Reset the flag either on the other side of the event triggering code, or in the event Sub itself. Doesn't stop the event firng, but stops it executing code you don't want.
As requested, example of option 2
In a standard module, at the top (just after Option Explicit), add this code
Global InhibitEvent As Boolean
In your code
' Somewhere in your code,
' when you are about to execute some logic that will trigger an event
InhibitEvent = True
'... event triggering logic here
InhibitEvent = False
In the Event Sub that you don't want to execute (eg a listBox Change event)
Private Sub ListBox1_Change()
' Look for Event Inhibit
If InhibitEvent Then Exit Sub
' rest of event code here
End Sub
Try using a List as the data source of list box. When updating, first put datasource of listbox null then equal to List

Resources