Filling VBA userform's combobox with table column plus an additional option - vba

I am developing an application, in excel with VBA forms. in one form I have a combobox to that let user select customer name, the rowsource of this combobox is a named range (name column of customers table). Everything working fine but I need to add 1 or more additional items in the combobox that not exist in the table column. For example I need to add "All" item in the cobmobox so user can select a particular customer name or All. at other place I wan't to add "Other" item in combobox with same rowsource so if the customer is new user can select Other and then type name in textbox.
I tried following code to add an item
Private Sub UserForm_Activate()
With Me.testCombo
.AddItem "All"
End With
End Sub
but i got error
Run-time error '70'
permission denied
if i remove rowsource property from the combobox then the above code work but only one item "All" display.
Note: I don't want to add "All" and "Other" in customer table, this could be easy solution but will cause other problem.

Try like this:
Private Sub UserForm_Activate()
Dim rowValue As Variant
Dim lngCount As Long
Dim myCell As Range
Dim varCombo() As Variant
With Me.ComboBox1
ReDim varCombo(Me.ComboBox1.ListCount)
For Each myCell In Range(.RowSource)
varCombo(lngCount) = myCell.value
lngCount = lngCount + 1
Next myCell
.RowSource = ""
For lngCount = LBound(varCombo) To UBound(varCombo) - 1
.AddItem CStr(varCombo(lngCount))
Next lngCount
.AddItem "All"
.AddItem "Nothing"
End With
End Sub
As mentioned in the comments, by A.S.H., you should unset the .RowSource property. However, you do not lose it, if you run the code twice, it would be the same. In my code I use UBound(varCombo) - 1, because I use lngCount=lngCount+1 on the last looping over the cell.

Something like this could do what you need
Dim a() As Variant
Dim b() As String
Dim s As String
a = Application.Transpose(Range("a1:a5").Value)
s = "Please select;" & Join(a, ";")
Erase a
b = Split(s, ";")
Me.ComboBox1.List = b

Thank you everyone for helping, the main problem was permission as A.S.H said if Rowsource is set then cannot add any item in the ComboBox. So I delete the RowSource from the properties in form. and wrote following code and it seems everything working fine. I hope my codes are good enough and simple.
Private Sub fillComboBox()
Dim comboData As Range
With Me.CWR_CustName
' first option of comobobox will be All
.AddItem "All"
For RW_Cust = 1 To Range("tblCust").Rows.Count
' add each customer name from customer table name column
.AddItem (Range("tblCust[Name]")(RW_Cust))
Next RW_Cust
End With
End Sub

Related

VBA excel - adding combo box item to list box

guys I hope someone can help me with this one.
I have a combo box that has data from a named range and I would like to select a value from the combo box and add it to the list box.
Currently I can add an item into the list box with a button but once I add another it overwrites the current item.
Also It needs to be able to add an item at the bottom if the list box already has some values in it.
I think it has something to do with finding the last row but I'm not sure, any help would be highly appreciated :)
image of the issue
Dim i As Integer
With Me.lb_lease
.ColumnCount = 3
.ColumnWidths = "200;50;50"
.AddItem
.List(i, 0) = cbox_hardware.Column(0)
.List(i, 1) = cbox_hardware.Column(1)
.List(i, 2) = cbox_hardware.Column(2)
i = i + 1
End With
I suggest to separate the actions of setting up the listbox and adding items to it. The procedure below will set up the box and clear all existing content. Change the names of the worksheet and the Listbox to match your circumstances. The code will also work if the listbox is in a userform.
Private Sub ResetListBox()
With Worksheets("LibraryAccount").ListBox1
.ColumnCount = 3
.ColumnWidths = "80;50;50"
.Clear ' delete current list
End With
End Sub
The next procedure adds an item to it. It requires a semi-colon separated string, like "One;Two;Three". You might concatenate it from your combobox result using ListIndex to identify the row. The procedure will disassemble the string and add it at the bottom of the list. Worksheet and ListBox names must be changed.
Private Sub AddToListBox(AddArray As String)
Dim Arr() As String
Dim i As Integer
Dim C As Long
Arr = Split(AddArray, ";")
With Worksheets("LibraryAccount").ListBox1
i = .ListCount
.AddItem
For C = 0 To 2
.List(i, C) = Arr(C)
Next C
End With
End Sub
The procedure below is for testing the above procedure. You can run ResetListbox and then call TestAdd several times.
Private Sub TestAdd()
AddToListBox "One;Two;Three"
End Sub

Excel VBA: Accessing the individual fields in a selected ListBox row

I am trying to access the individual cells in a selected/highlighted ListBox "lstData" row so I can reference their values elsewhere.
When I set a watch for Me.lstData.SelectedItem, I get Expression not defined in context. Same with Me.lstData.SelectedIndex and Me.lstData.Rows(1). The only thing that kind of works for me is Me.lstData.Value, but it ONLY returns the leftmost cell. When I try to plug it into the =OFFSET function
=Offset(Me.lstData.Value, ,1,1)
to access the cell immediately to the right, I get Expression not defined in context again.
How can I reference the other selected cells?
I don't think you can use Offset on a ListBox form control. The way to reference a 'cell' in a multi-column ListBox is by indexing the List property.
Here, i returns the row of the selected item, and 1 represents the second column (base 0) of the listbox:
Option Explicit
Private Sub CommandButton1_Click()
Dim i As Long
With Me.ListBox1
i = .ListIndex
MsgBox .List(i, 1)
End With
End Sub
Private Sub UserForm_Initialize()
With Me.ListBox1
.AddItem "A"
.List(0, 1) = "Alpha"
.AddItem "B"
.List(1, 1) = "Beta"
End With
End Sub

use a button on userform to get a variable and continue with sub

I have a userform in excel where a combobox compiles a dropdown using a range from another sheet. I've defined the dropdown using a dictionary from the range and forced the combobox to match (this is done to ensure the user tries to find the company prior to adding a new one). I do however, want them to be able to add new companies to the list if absolutely needed, thus have a button labeled "add company," and now need it to add the company they input into the list/dictionary, any ideas?
I would like to avoid having to launch a whole new userform, optimally I thought of an input box on_click of the button, but I am not sure how to force that variable back into the original userform.
My current code is:
Private Sub UserForm_Initialize()
Dim Acctsht As Worksheet
Dim ValSet
Dim FinanInst
Dim objFinanInst As Object
Dim objAcctType As Object
Dim objNickname As Object
Dim objFourDig As Object
Dim objAcctClass As Object
Dim objDescript As Object
Dim CompanyDict As New Scripting.Dictionary
Dim Tempsht As Worksheet
Dim NewCompTemp As String
Set Acctsht = ActiveWorkbook.Sheets("Accounts")
With Acctsht.Range("b2:b" & Range("b:b").SpecialCells(xlLastCell).Row)
ValSet = .Value
End With
With CompanyDict
.comparemode = 1
For Each FinanInst In ValSet
If Not .exists(FinanInst) Then .Add FinanInst, Nothing
Next
If .Count Then CBoxFinanInst.List = Application.Transpose(.keys)
End With
With CboxAcctType
.AddItem "Checking Account"
.AddItem "Fixed Loan"
.AddItem "Investment Account"
.AddItem "Money Market Account"
.AddItem "Revolving Credit"
.AddItem "Savings Account"
End With
With CBoxAcctClass
.AddItem "Asset"
.AddItem "Liability"
End With
End Sub
Private Sub CButtonAddCompany_Click()
Dim NewCompTemp As String
Unload FrmCreateAccount
NewCompTemp = InputBox("Please enter new company exactly as you wish it to appear", Title:="Create New Company")
FrmCreateAccount.Show (NewCompTemp)
Exit Sub
End Sub
In response to Jean-Pierre's comment below, I've tried the following code, but it's still not working:
Private Sub CButtonAddCompany_Click()
Dim NewCompTemp As String
Dim Acctsht As Worksheet
Dim CompanyDict As New Scripting.Dictionary
Set Acctsht = ActiveWorkbook.Sheets("Accounts")
NewCompTemp = InputBox("Please enter new company exactly as you wish it to appear", Title:="Create New Company")
With Acctsht.Range("b2:b" & Range("b:b").SpecialCells(xlLastCell).Row)
ValSet = .Value
End With
With CompanyDict
.comparemode = 1
For Each FinanInst In ValSet
If Not .exists(FinanInst) Then .Add FinanInst, Nothing
Next
If .Count Then CBoxFinanInst.List = Application.Transpose(.keys)
End With
With CompanyDict
.Add CompanyDict.Count + 1, NewCompTemp
End With
Exit Sub
End Sub
Only the original dropdown list in the combobox appears, regardless of what is entered and stored as NewCompTemp.
I got it, thanks to Jean-Pierre for sending me in the right direction! I didn't realize I could run the subroutine and have it reset the dictionary right on the form.
Essentially, the dictionary was set from the initialize action, however, I didn't realize I could retrigger a set-up of the same dictionary on a button_click action. Once I did that and ended that sub it returned to the original userform sub and voila. Thank you for all that helped and thank you for your patience. (older biologist here learning new skills).

Sortable List in VBA?

Is there a way to create a VBA user interface that will allow user to order items? See example image taken from a pdf editor.
I want my users to be able to order data in a popout window or list and output their order to a different location. Data is a list of buildings.
Thanks!
For this solution I used a UserForm with a ListBox and a SpinButton control.
I put a list of cells I wanted in my listbox in Column A of Sheet1. I have a generic Building 1, Building 2, etc. through Building 19 so that my data is contained in the range A1:A19 of Sheet1. This is arbitrary and you should change to suit your needs.
This code basically stores the original RowSource that contains the items in the ListBox, deletes the RowSource from the ListBox, rearranges the underlying source data and then re-applies the RowSource to the ListBox in the new order after the user clicks either up or down on the SpinButton
I did not change the default control names (UserForm1, SpinButton1, ListBox1).
Open the VB Editor (either Developer tab --> Visual Basic or press ALT+F11
Right click Microsoft Excel Objects --> Insert --> UserForm
Add a SpinButton and a ListBox so the UserForm looks like so
In the VB Editor, right click UserForm1 under Forms --> View Code
Paste the following code in
Private Sub UserForm_Initialize()
'Populate the UserForm with data from range A1:A19 (arbitrary, change to suit your needs
ListBox1.RowSource = Sheet1.Range(Sheet1.Range("A1"), Sheet1.Range("A1").End(xlDown)).Address
End Sub
Private Sub SpinButton1_SpinDown()
With ListBox1
If .ListIndex = .ListCount - 1 Then Exit Sub 'No item selected or we are in the last position
lCurrentListIndex = .ListIndex + 1 'Get the current position of the item
strRowSource = .RowSource 'Get the current row source
strAddress = Range(strRowSource).Address 'Address of the row source range
strSheetName = Range(strRowSource).Parent.Name 'Grab the parent sheet name
.RowSource = vbNullString 'Empty the listbox
'Re-arrange the underlying data
With Range(strRowSource)
.Rows(lCurrentListIndex).Cut
.Rows(lCurrentListIndex + 2).Insert Shift:=xlDown
End With
'Re-apply the row source
.RowSource = strRowSource
'For continuity, select the previously selected element in its new position
.Selected(lCurrentListIndex) = True
End With
End Sub
Private Sub SpinButton1_SpinUp()
Dim lCurrentListIndex As Long
Dim strRowSource As String
Dim strAddress As String
Dim strSheetName As String
With ListBox1
If .ListIndex < 1 Then Exit Sub 'No item selected or we are in the first position
lCurrentListIndex = .ListIndex + 1
strRowSource = .RowSource
strAddress = Range(strRowSource).Address
strSheetName = Range(strRowSource).Parent.Name
.RowSource = vbNullString
With Range(strRowSource)
.Rows(lCurrentListIndex).Cut
.Rows(lCurrentListIndex - 1).Insert Shift:=xlDown
End With
.RowSource = strRowSource
.Selected(lCurrentListIndex - 2) = True
End With
End Sub
I tried to add comments to clarify what I am doing. It is a slightly cumbersome method, and was adapted from code available here. If you click the Debug (looks like play) button the form should display and populate with the values of cells A1:A19 of Sheet1. You can then select an item in the ListBox and press the up or down buttons of the SpinButton in order to move items up or down the list. An important assumption is that MultiSelect is disabled on this ListBox.
Ordinarily I would not post such an in-depth solution without seeing what you tried, but this problem piqued my curiosity.

VBA - Add Class as Item in ComboBox

I have a text file containing CSV information.
I want a single field from each entry to populate a combobox.
But I want to preserve the relationship with the other data when the user picks an item from the combobox.
For example:
Dim c as Collection
c = ReadFile() 'returns a Collection of variant arrays to c
Dim info As Variant
For Each info In c
'Let's say, for example, info(3) contains the human-friendly name of the item
'(which may or may not be unique)
'and info(0) contains the unique ID of the item (which I need to reference later)
'I'd like to put:
'combobox.AddItem(info)
'but I'm getting errors unless I do something more specific, like:
combobox.AddItem (info(3))
'Can I preserve each info() object as a part of the combobox?
'I know this can be done in .NET but I'm not so sure about VBA.
Next info
Is it possible to store my collection of "info" in a combobox?
Later in the code I'd like the convenience of using something like:
combobox.SelectedItem(0)
or
combobox.Value(0)
to retrieve my unique ID.
I don't have SolidWorks, so I can't test this in that context, but here's an example built in Excel. I'm betting that the Combobox class is similar enough.
Option Explicit
Dim colTemp As Collection
Public Sub Populate_Combobox()
Dim arrThings() As Variant
Dim varItem As Variant
'This section constructs a data structure like you describe: a Collection of Variant Arrays
Set colTemp = New Collection
arrThings = Array(123, "fhdg", "Umbrella")
colTemp.Add arrThings
arrThings = Array(156, "afibewsrbeld", "Car")
colTemp.Add arrThings
arrThings = Array(34, "afifelbxcfbd", "Car")
colTemp.Add arrThings
arrThings = Array(247, "afisbdfheldd", "Shoe")
colTemp.Add arrThings
For Each varItem In colTemp
'This adds the "human readable" name to the dropdown
ComboBox1.AddItem varItem(2)
Next
End Sub
Private Sub ComboBox1_Change()
'This handles the event that a user has changed their selection in the dropdown
Dim i As Integer
Dim arrThings As Variant
'The index of the ComboBox selection is used to get the correct array out of the Collection
arrThings = colTemp.Item(ComboBox1.ListIndex + 1)
'Just to show it's the correct item...
Dim strOutput As String
For i = 0 To UBound(arrThings)
strOutput = strOutput & " " & arrThings(i)
Next
MsgBox "The chosen item contains these: " & strOutput
End Sub
EDIT: Fixed an issue where, because I had failed to use Option Explicit, I accidentally created an undeclared variable. Thankfully it had no effect on the functioning of the code, but it easily could have. Don't make my mistake - ALWAYS use Option Explicit ;)