Multiple selections in Listbox userform and storing multiple listbox values as one array into the excel sheet - excel

I have the following code on a command button that initializes in a Listbox on a Userform and pastes the value into "ThisWorkbook.Worksheets("Sub")".
This only works with one selection, and if you select multiple selections in the Listbox it will only add the first value to cell A8 in column 5.
I want user to be able to pick several options from a listbox. Then, when they save the form, I want the options they selected to populate in the next available row as an Array in the Excel sheet:
Private Sub cmdadd_Click()
On Error Resume Next
Set wks = ThisWorkbook.Worksheets("Sub")
wks.Activate
Dim i As Integer
ActiveSheet.Range("A8").Select
i = 1
Do Until ActiveCell.Value = Empty
ActiveCell.Offset(1, 0).Select 'move down 1 row
i = i + 1 'keep a count of the ID for later use
Loop
'Populate the new data values into the 'Sub' worksheet.
ActiveCell.Value = i 'Next ID number
'Populate the new data values into the 'Sub' worksheet.
ActiveCell.Offset(0, 1).Value = Me.txtls.Text 'set col B
ActiveCell.Offset(0, 2).Value = Me.txtPr.Text
ActiveCell.Offset(0, 3).Value = Me.cbolo.Text
Dim intOffset As Integer
Dim strVal As String
Dim selRange As Range
Set selRange = Selection
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) = True Then
If strApps = "" Then
strApps = ListBox1.List(i)
intOffset = i
strVal = ActiveCell.Offset(0, 4).Value 'set col E
Else
strApps = strApps & ";" & ListBox1.List(i)
intOffset = i
strVal = strVal & ";" & ActiveCell.Offset(0, 4).Value 'set col E
End If
End If
Next
End Sub
Private Sub UserForm_Initialize()
Me.ListBox1.AddItem "A"
Me.ListBox1.AddItem "3"
Me.ListBox1.AddItem "S"
Me.ListBox1.AddItem "2"
Me.ListBox1.AddItem "S"
End Sub

Avoid Select/Active/Selection/ActiveXXX coding pattern and rely on fully qualified (uop to worksheet, at least) range references
as follows
Option Explicit
Private Sub cmdadd_Click()
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets("Sub")
Dim i As Long
With wks.Range("A8") ' reference "sub" worksheet cell A8
i = 1
Do Until .Offset(i - 1).Value = Empty ' check for referenced cell current row offset empty value
i = i + 1 'keep a count of the ID for later use
Loop
'Populate the new data values into the 'Sub' worksheet.
With .Offset(i - 1) ' reference referenced cell row offset to first empty cell
'Populate the new data values into the 'Sub' worksheet.
.Value = i ' set col A with next ID number
.Offset(0, 1).Value = Me.txtls.Text 'set col B
.Offset(0, 2).Value = Me.txtPr.Text 'set col C
.Offset(0, 3).Value = Me.cbolo.Text 'set col D
Dim strApps As String
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then strApps = strApps & ListBox1.List(i) & ", " ' update 'strApps' string with listbox selected items separated by a comma and a space
Next
If strApps <> "" Then .Offset(0, 4).Value = Left(strApps, Len(strApps) - 2) ' if any listbox selected values, write 'strApps' in col E
End With
End With
End Sub

Related

Update the same names on different row using loop

I have a userform with combobox 9 when you select combobox9 value it will show all the values into the each boxes and you can updated the textbox 19 value into sheet against the raw of the selected value in combobox9 however problem is if there's the same name e.g. twice same name in combobox9 it will only update the its 1st name on the raw and not the 2nd or even if there is 3 entry in sheet with same name.
Names are in column C and textvalue is updated its name on column H however I need to loop the column H if it is already updated against its name then same name needs to updated which is in new raw.
Below is the vba code I have but it is so far not working
Dim lCol As Variant
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Attendance")
If Me.ComboBox9.Value <> "" Then
If VBA.CVar(Application.Match(VBA.CVar(Me.ComboBox9.Value), sh.Range("C:C"), 0)) = True Then
MsgBox "Record Not found", vbCritical
Exit Sub
Else
i = Application.Match(VBA.Cvar(Me.ComboBox9.Value), sh.Range("C:C"), 0)
End If
lCol = Me.ComboBox9.Value
Set findvalue = sh.Range("C:C").Find(What:=lCol, LookIn:=xlValues)
If Not findvalue Is Nothing Then
adr = findvalue.Address
Do
If findvalue.Offset(0, 6).Value = Me.TextBox19 Then
sh.Unprotect "1234"
findvalue.Offset(0, 6).Value = Me.TextBox19.Value = ""
Exit Do
End If
Set findvalue = sh.Range("C:C").FindNext(findvalue)
Loop While findvalue.Address <> adr
Set findvalue = Nothing
End If

Filling all the empty cells between two equal cells in same column in excel sheet (with the same value of the equal cells )

I have the following excel
I am trying the following code
> Sub fill_blanks()
Dim i As Long
i = 2 '
Do Until Range("B" & i) = ""
Range("B" & i).Select
If ActiveCell.FormulaR1C1 <> "" Then
Range("A" & i).Select
If ActiveCell.FormulaR1C1 = "" Then
Range("A" & i - 1).Copy
Range("A" & i).PasteSpecial Paste:=xlPasteValues
Else
i = i + 1
End If
Else
i = i + 1
End If
Loop
End Sub >
What I need to check is if the cell is not empty, then to keep its value, and if it was empty to check the first next not empty cell and the previous non empty cell in the same column, and if they have the same value, then to fill all the empty cells between with the same value, and if the two cells are not matching, then to return X.
So the result will be as following
But using the code , I am getting something different.
This what I get with this code
Find the last used row LastRow so we know where to stop.
Loop through your rows, when you come accross an epmty cell remember it FirstEmptyRow
Keep looping until you find data again, the row before is then LastEpmtyRow. Now we know the beginning and the end of the empty space.
Check if above the epmty space and below the empty space is the same date. If so fill it into the empty space otherwise fill in x.
So you end up with something like
Option Explicit
Public Sub FillData()
Const START_ROW As Long = 2 'define first data row
Const COL As String = "A" 'define the column
Dim ws As Worksheet 'define your worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long 'find last used row in column A
LastRow = ws.Cells(ws.Rows.Count, COL).End(xlUp).Row
Dim FirstEmptyRow As Long, LastEpmtyRow As Long 'first and last empty row of a empty range
Dim iRow As Long
For iRow = START_ROW To LastRow
If ws.Cells(iRow, COL).Value = vbNullString And FirstEmptyRow = 0 Then
'found first row of an empty range
FirstEmptyRow = iRow
ElseIf ws.Cells(iRow, COL).Value <> vbNullString And FirstEmptyRow <> 0 Then
'found last row of an empty range
LastEpmtyRow = iRow - 1
'check if same date to fill either the date or x
If ws.Cells(FirstEmptyRow - 1, COL).Value = ws.Cells(LastEpmtyRow + 1, COL).Value Then
'fill date
ws.Range(ws.Cells(FirstEmptyRow, COL), ws.Cells(LastEpmtyRow, COL)).Value = ws.Cells(FirstEmptyRow - 1, COL).Value
Else
'fill x
ws.Range(ws.Cells(FirstEmptyRow, COL), ws.Cells(LastEpmtyRow, COL)).Value = "x"
End If
'reset variables
FirstEmptyRow = 0
LastEpmtyRow = 0
End If
Next iRow
End Sub
Image 1: Illustration of the process.

Combo box drop down method in vba calling change method again and again

Part 1: A combo box in sheet1 to dynamically list unique values from a column in sheet2 put it in the drop down list
Part 2: Display the related entries of sheet2 in sheet1 based on the combo box selection.
I have done the part 1 in a method call fillCombo and have called it under ComboBox1_DropButtonClick() and part 2 under the method ComboBox1_Change()
First time when i click dropdown arrow of combo box it lists the unique entries and on making the selection in it, the related entries are displayed in sheet1 and everything is fine.
During the next selection of dropdown arrow it goes to ComboBox1_DropButtonclick() method then ComboBox1_change() method, ComboBox1_change() method without the dropdown list appearing and me selecting
So it works correctly only in the first instance.
Can you please correct the error.
Private Sub ComboBox1_Change()
Dim sht2, sht1, a As Long, X As Long, i As Long
Dim Lastrow As Long
Set sht1 = Worksheets("Sheet1")
Set sht2 = Worksheets("Sheet2")
a = sht2.Cells(Rows.Count, 1).End(xlUp).Row
X = 8
Lastrow = sht1.Range("D" & Rows.Count).End(xlUp).Row
sht1.Range("G8:J" & Lastrow).Clear
For i = 2 To a
If sht2.Cells(i, 3).Value = "Payments" Then
sht2.Cells(i, "C").Resize(1, 4).Copy sht1.Cells(X, "G")
X = X + 1
End If
Next
sht1.Select
sht1.Cells(1, 1).Select
End Sub
Private Sub ComboBox1_DropButtonClick()
Call fillCombo
End Sub
Sub fillCombo()
Dim ws2 As Worksheet
Set ws2 = ThisWorkbook.Sheets("Sheet2")
Group = 3
firstTime = True
strValue = Sheet1.ComboBox1.Value
'last row
wsLR = ws2.Cells(Rows.Count, 1).End(xlUp).Row
'loop thru rows
For l = 2 To wsLR
If ws2.Cells(l, Group) <> "" And (InStr(uE, "|" & ws2.Cells(l, Group) & "|") = 0) Then
If firstTime = True Then
firstTime = False
uE = "|" & uE & ws2.Cells(l, Group) & "|"
Else
uE = uE & ws2.Cells(l, Group) & "|"
End If
End If
Next l
dropValues = Split(uE, "|")
Sheet1.ComboBox1.Clear
For Each cell In dropValues
If cell <> "" Then
Sheet1.ComboBox1.AddItem cell
End If
Next cell
Sheet1.ComboBox1.Value = strValue
End Sub

How to add Selected Value (one at a time) from Listbox to specific excel column

I am using a Listbox which contains the name of folders. I need to select the names from listbox (one at a time, to maintain the order of selection) and add it to the excel column A1, such that each time adding to the next empty cell of column A. I am very new to vb and need help. Below are the approaches i tried.
Approach 1)
Sub AddRecord_Click()
With Sheet1.ListBox1
For intIndex = 0 To .ListCount - 1
With ActiveSheet
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
End With
If .Selected(intIndex) Then
Sheet1.Cells(LastRow, "A") = Sheet1.ListBox1.Value
NextRow = LastRow + 1
End If
Next
End With
End Sub
Approach 2)
Sub AddRecord_Click()
intRecord = (CInt(Range("A1").End(xlDown).Row) + 1)
Sheet1.Cells(intRecord, "A") = Sheet1.ListBox1.Value
intRecord = intRecord + 1
End Sub
Try this may be helpful to u
Sub ListBox7_Change()
Dim i As Long
With ActiveSheet.ListBoxes("List Box 7")
For i = 1 To .ListCount
If .Selected(i) Then
Range("A" & Rows.count).End(xlUp).offset(1).Value = .List(i)
End If
Next i
End With
End Sub
First you get last used row from the excel sheet and finally increment that last row and insert next column value to the excel.
Dim last as Excel.Range = xlWorkSheet.Cells.SpecialCells
(Excel.XlCellType.xlcellTypeLastCell,Type.Missing)
dim lastUsedRow As Integer = last.Row
lastUsedRow += 1
xlWorksheet.RangeA("A"+ lastUserRow).value = ListBox1.Value

Normalizing Excel Grid Intersection data into a flat list

I am trying to get Excel data, which was mapped using a grid/matrix mapping into a de-normalized for so that i can enter the data into a database.
How do you copy data in a grid from one excel sheet to the other as follow illustrated below.
I was trying something like this... but as you can see, i am far off!
Sub NormaliseList(mySelection As Range)
Dim cell As Range
Dim i As Long
i = 1
For Each cell In mySelection
If cell <> "" Then
Sheets(2).Range("A" & i).Value = cell(cell.Row, 1).Value
Sheets(2).Range("B" & i).Value = cell.Value
Sheets(2).Range("C" & i).Value = cell(1, cell.Column).Value
i = i + 1
Next cell
End Sub
For Reference. I Updated my code..
Simply add the code, assign macro shortcut to the function
Select the range that contains the intersection data (not the row and column data)
Run macro (Beware, sheet 2 will have data added in normalised form)
If there are multiple headings that are needed i figured i would consolidate into one column then perform a "text to columns" after processing.
Sub NormaliseList()
' to run - assign macro shortcut to sub - Select Intersection data (not row and column headings and run)
Dim Rowname, ColumnName, IntValue As String
Dim x, cntr As Integer
Dim test As Boolean
cntr = 0
For x = 1 To Selection.Count
If Selection(x).Value <> "" Then
cntr = cntr + 1
Rowname = ActiveSheet.Cells(Selection.Cells(x).Row, Selection.Column - 1)
ColumnName = ActiveSheet.Cells(Selection.Row - 1, Selection.Cells(x).Column)
IntValue = Selection(x).Value
test = addrecord(Rowname, ColumnName, IntValue, cntr)
End If
Next x
End Sub
Function addrecord(vA, vB, vC As String, rec As Integer) As Boolean
'Make sure that you have a worksheet called "Sheet2"
Sheets("Sheet2").Cells(rec, 1) = vA
Sheets("Sheet2").Cells(rec, 2) = vB
Sheets("Sheet2").Cells(rec, 3) = vC
End Function
I've got two posts, with usable code and downloadable workbook, on doing this in Excel/VBA on my blog:
http://yoursumbuddy.com/data-normalizer
http://yoursumbuddy.com/data-normalizer-the-sql/
Here's the code:
'Arguments
'List: The range to be normalized.
'RepeatingColsCount: The number of columns, starting with the leftmost,
' whose headings remain the same.
'NormalizedColHeader: The column header for the rolled-up category.
'DataColHeader: The column header for the normalized data.
'NewWorkbook: Put the sheet with the data in a new workbook?
'
'NOTE: The data must be in a contiguous range and the
'rows that will be repeated must be to the left,
'with the rows to be normalized to the right.
Sub NormalizeList(List As Excel.Range, RepeatingColsCount As Long, _
NormalizedColHeader As String, DataColHeader As String, _
Optional NewWorkbook As Boolean = False)
Dim FirstNormalizingCol As Long, NormalizingColsCount As Long
Dim ColsToRepeat As Excel.Range, ColsToNormalize As Excel.Range
Dim NormalizedRowsCount As Long
Dim RepeatingList() As String
Dim NormalizedList() As Variant
Dim ListIndex As Long, i As Long, j As Long
Dim wbSource As Excel.Workbook, wbTarget As Excel.Workbook
Dim wsTarget As Excel.Worksheet
With List
'If the normalized list won't fit, you must quit.
If .Rows.Count * (.Columns.Count - RepeatingColsCount) > .Parent.Rows.Count Then
MsgBox "The normalized list will be too many rows.", _
vbExclamation + vbOKOnly, "Sorry"
Exit Sub
End If
'You have the range to be normalized and the count of leftmost rows to be repeated.
'This section uses those arguments to set the two ranges to parse
'and the two corresponding arrays to fill
FirstNormalizingCol = RepeatingColsCount + 1
NormalizingColsCount = .Columns.Count - RepeatingColsCount
Set ColsToRepeat = .Cells(1).Resize(.Rows.Count, RepeatingColsCount)
Set ColsToNormalize = .Cells(1, FirstNormalizingCol).Resize(.Rows.Count, NormalizingColsCount)
NormalizedRowsCount = ColsToNormalize.Columns.Count * .Rows.Count
ReDim RepeatingList(1 To NormalizedRowsCount, 1 To RepeatingColsCount)
ReDim NormalizedList(1 To NormalizedRowsCount, 1 To 2)
End With
'Fill in every i elements of the repeating array with the repeating row labels.
For i = 1 To NormalizedRowsCount Step NormalizingColsCount
ListIndex = ListIndex + 1
For j = 1 To RepeatingColsCount
RepeatingList(i, j) = List.Cells(ListIndex, j).Value2
Next j
Next i
'We stepped over most rows above, so fill in other repeating array elements.
For i = 1 To NormalizedRowsCount
For j = 1 To RepeatingColsCount
If RepeatingList(i, j) = "" Then
RepeatingList(i, j) = RepeatingList(i - 1, j)
End If
Next j
Next i
'Fill in each element of the first dimension of the normalizing array
'with the former column header (which is now another row label) and the data.
With ColsToNormalize
For i = 1 To .Rows.Count
For j = 1 To .Columns.Count
NormalizedList(((i - 1) * NormalizingColsCount) + j, 1) = .Cells(1, j)
NormalizedList(((i - 1) * NormalizingColsCount) + j, 2) = .Cells(i, j)
Next j
Next i
End With
'Put the normal data in the same workbook, or a new one.
If NewWorkbook Then
Set wbTarget = Workbooks.Add
Set wsTarget = wbTarget.Worksheets(1)
Else
Set wbSource = List.Parent.Parent
With wbSource.Worksheets
Set wsTarget = .Add(after:=.Item(.Count))
End With
End If
With wsTarget
'Put the data from the two arrays in the new worksheet.
.Range("A1").Resize(NormalizedRowsCount, RepeatingColsCount) = RepeatingList
.Cells(1, FirstNormalizingCol).Resize(NormalizedRowsCount, 2) = NormalizedList
'At this point there will be repeated header rows, so delete all but one.
.Range("1:" & NormalizingColsCount - 1).EntireRow.Delete
'Add the headers for the new label column and the data column.
.Cells(1, FirstNormalizingCol).Value = NormalizedColHeader
.Cells(1, FirstNormalizingCol + 1).Value = DataColHeader
End With
End Sub
You’d call it like this:
Sub TestIt()
NormalizeList ActiveSheet.UsedRange, 1, "Name", "Count", False
End Sub

Resources