Listbox Modification in VBA - vba

I created a Userform in Word which imports 3 columns of data from an excel sheet, inserts it into bookmarks and in the name of the word document and saves it as a pdf.
Now I wanted to add a Listbox into the form to be able to add, modify and delete the inputs manually which are usually imported from the excel sheet .
I already figured out how to add data from 3 textboxes into a 3 Column Listbox but even after googling for hours I can't find a good way to modify selected data.
VB.net has the .selectedItem property, VBA does not. Can anybody give me an example how to modify a multi column listbox with the values of 3 textboxes?
Thanks in advance

You need to iterate through ListBox.Selected and check if it is True. Once you get a True one, you can process that item.
Sample code adds some items with columns and sets up a click event to run through the Selected items.
Private Sub ListBox1_Click()
Dim i As Integer
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
Debug.Print ListBox1.List(i, 0)
End If
Next i
End Sub
Private Sub UserForm_Initialize()
ListBox1.AddItem "test"
ListBox1.AddItem "test1"
ListBox1.AddItem "test2"
ListBox1.ColumnCount = 3
ListBox1.ColumnHeads = True
ListBox1.List(1, 0) = "change to 1,0"
ListBox1.List(1, 1) = "change to 1,1"
ListBox1.List(1, 2) = "change to 1,2"
End Sub
Picture of form with Immediate window after clicking each item in turn.

Related

Need help, VBA, need the combobox to avoid entering a specific values

I have a list of data in a sheet from A1:A8 and i have a combobox1 in a userform. What i want is to avoid a user to input an invalid value in the combobox1 based on the lists of data in the sheet
Go to combobox properties and change Style from 0 - fmStyleDropDownCombo to 2 - fmStyleDropDownList
i think this is what you are searching:
https://msdn.microsoft.com/en-us/vba/access-vba/articles/combobox-beforeupdate-event-access
There you have a way to check the values with that you want, there is a example where you can replace it with your range of cells.
Edited (Nice point, i'll put the example here):
Private Sub Combobox_BeforeUpdate(Cancel As Integer)
For i = 1 to 8
If(Cells(i, 1).Value == Me.Combobox.Value)
Cancel = True
Me.Combobox.Undo
End If
Next i
End Sub
Cya.

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

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.

Populating a dropdown box with already-existing options in VBA?

I'm making an add records form for a spreadsheet of mine, and let's say that I want one of the controls to be a dropdown that is populated by unique entries under a certain column "type". However, I want to also make it such that the dropbox always has a initial option to "add new type" and upon such selection, it becomes a regular text box. How would I do this in VBA?
You cannot change a control type at run time. The easiest thing to do is create a combo box and a text box. Set the text box visibility to false. Then in the onchange event of the combo box your code will unhide the text box and hide the combo box. You will also need a save button so that when it is clicked it will add the option to the drop down, clear the text box, hide the text box, hide the button and unhide the drop down.
Okay, so here's my idea of how to tackle this.
Create 2 hidden elements (Visibility = False), one a TextBox and one a CommandButton.
Populate your ComboBox with the values from the sheet under column "type"
Add one more entry AddItem with wording such as "Add new item..."
When the user selects "Add new item...", change the Visibility of the TextBox & CommandButtons to True
When the user clicks the CommandButton, add the phrase to the column and add a new element to the ComboBox
I have created a mockup UserForm and code that does a little more than just this; it also styles the user entry to sentence case (consistency purposes) and checks to make sure the value isn't already in the column.
Excel Sheet with "type" column
UserForm with name labels
UserForm Code
Private Sub bAdd_Click()
Dim str As String
Dim rng As Range
Dim ro As Integer
'Makes sure there is an entry, adds it to the Sheet and then updates the dropdown
If Len(Me.tbNew) > 0 Then
'Converts user entry to "Sentance Case" for better readability
str = StrConv(Me.tbNew, vbProperCase)
'Finds out if the entry already exists
Set rng = Sheets(1).Range(Sheets(1).Cells(2, 1), Sheets(1).Cells(Sheets(1).Cells(Sheets(1).Rows.Count, 1).End(xlUp).Row, 1))
On Error Resume Next
Err.Number = 0
'Searches for duplicate; if found, then ListIndex of cbColor is modified without inserting new value (prevents duplicates)
ro = rng.Find(str, LookIn:=xlValues, LookAt:=xlWhole).Row
Debug.Print Err.Number
'Ensures a user doesn't add the same value twice
If Err.Number > 0 Then
Sheets(1).Cells(Sheets(1).Cells(Sheets(1).Rows.Count, 1).End(xlUp).Row + 1, 1) = str
Me.cbColor.AddItem StrConv(Me.tbNew, vbProperCase), Me.cbColor.ListCount - 1
Me.cbColor.ListIndex = Me.cbColor.ListCount - 2
Else
Me.cbColor.ListIndex = ro - 2
End If
'Resets and hides user form entries
Me.tbNew = vbNullString
Me.tbNew.Visible = False
Me.bAdd.Visible = False
End If
End Sub
Private Sub bClose_Click()
Unload Me
End Sub
Private Sub cbColor_Change()
'Visibility is toggled based on if the user selected the last element in the dropdown
Me.bAdd.Visible = Me.cbColor.ListIndex = Me.cbColor.ListCount - 1
Me.tbNew.Visible = Me.cbColor.ListIndex = Me.cbColor.ListCount - 1
End Sub
Private Sub UserForm_Initialize()
'Populate from the sheet
For a = 2 To Sheets(1).Cells(Cells(Sheets(1).Rows.Count, 1).End(xlUp).Row, 1).Row
Me.cbColor.AddItem Sheets(1).Cells(a, 1)
Next
'Add option for new type
Me.cbColor.AddItem "Add new type..."
End Sub

lAdding files to a two column listbox

I am trying to add files to a list box in the same way as they are added when files are attached to an email, in two columns but able to address each file uniquely.
I am using Access VBA and do not know if it is possible.
Any help would be appreciated.
Thanks
Try mapping the indices of the items in the listBox to the files using a separate array/collection/dictionary. Then, when an item is selected, you can use the item's index to get the link
I just tried this below, works perfectly.
Userform Code:
Private d As Dictionary
Private Sub userform_initialize()
Set d = New Dictionary
'populate list box, and add items to dictionary
For i = 1 To 3
With ListBox1
d.Add .ListCount, "Link" & i
.AddItem 0
.List(.ListCount - 1) = "Hello World"
End With
Next
End Sub
'update label1's value based of listbox's selected item
Private Sub ListBox1_Change()
With ListBox1
If .ListIndex <> -1 Then
Label1.Caption = d.Item(.ListIndex)
End If
End With
End Sub
And the userform looked like this: (listbox named ListBox1, and label named Label1):
Example:
If you have problems using the dictionary object, you need to add a reference to "Microsoft Scripting Runtime". But really any collection-type can replace the dictionary in this case (an array/Collection)