Excel VBA Userform Entering Data into Multiple rows using checkboxes - excel

Hi I need to enter multiple rows of data at once based on the checkboxes that are selected. Currently this only adds 1 row. I think I have to use a loop but I'm not sure how I should implement it. Can anyone help please ?
The sample output should look something like this:
TC37 | 1
TC37 | 2
TC37 | 4
Current Code:
Dim LastRow As Long, ws As Worksheet
Private Sub CommandButton1_Click()
Set ws = Sheets("sheet1")
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row + 1
ws.Range("A" & LastRow).Value = ComboBox1.Text
If CheckBox1.Value = True Then
ws.Range("B" & LastRow).Value = "1"
End If
If CheckBox2.Value = True Then
ws.Range("B" & LastRow).Value = "2"
End If
If CheckBox3.Value = True Then
ws.Range("B" & LastRow).Value = "3"
End If
If CheckBox4.Value = True Then
ws.Range("B" & LastRow).Value = "4"
End If
End Sub
Private Sub UserForm_Initialize()
ComboBox1.List = Array("TC37", "TC38", "TC39", "TC40")
End Sub

Since you are getting the last row 1 time, you should dump the data with reference to that one time. Try something like:
Dim chkCnt As Integer
Dim ctl As MSForms.Control, i As Integer, lr As Long
Dim cb As MSForms.CheckBox
With Me
'/* check if something is checked */
chkCnt = .CheckBox1.Value + .CheckBox2.Value + .CheckBox3.Value + .CheckBox4.Value
chkCnt = Abs(chkCnt)
'/* check if something is checked and selected */
If chkCnt <> 0 And .ComboBox1 <> "" Then
ReDim mval(1 To chkCnt, 1 To 2)
i = 1
'/* dump values to array */
For Each ctl In .Controls
If TypeOf ctl Is MSForms.CheckBox Then
Set cb = ctl
If cb Then
mval(i, 1) = .ComboBox1.Value
mval(i, 2) = cb.Caption
i = i + 1
End If
End If
Next
End If
End With
'/* dump array to sheet */
With Sheets("Sheet1") 'Sheet1
lr = .Range("A" & .Rows.Count).End(xlUp).Row + 1
.Range("A" & lr).Resize(UBound(mval, 1), 2) = mval
End With

Problem is that your variable LastRow does not change. It is set only once at the beginning. So when you try to write the value, it will always write it to the same cell.
If CheckBox1.Value = True Then
LastRow = ws.Range("B100").end(xlup).Row + 1
ws.Range("B" & LastRow).Value = "1"
End If
If CheckBox2.Value = True Then
LastRow = ws.Range("B100").end(xlup).Row + 1
ws.Range("B" & LastRow).Value = "2"
End If
If CheckBox3.Value = True Then
LastRow = ws.Range("B100").end(xlup).Row + 1
ws.Range("B" & LastRow).Value = "3"
End If
If CheckBox4.Value = True Then
LastRow = ws.Range("B100").end(xlup).Row + 1
ws.Range("B" & LastRow).Value = "4"
End If
You could also use and array to store the values and then paste the result of the array in the range.
there are many ways to do this but this one should work. You should always clean the range prior to paste the values.
hope this helps,

Related

Convert date list into date ranges [duplicate]

I have a data like this :
A049
A050
A051
A053
A054
A055
A056
A062
A064
A065
A066
And I want the output like :
As you can see, I want the ranges which are in consecutive order
I am trying some thing like this:
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
For i = 2 To lastRow
r = wb.Sheets("Sheet1").Range("A" & i).Value
If wb.Sheets("Sheet1").Range("A" & i).Value = wb.Sheets("Sheet1").Range("A" & i+1).Value
Next i
End Sub
But not helping me
Am feeling charitable so have tried some code which should work. It assumes your starting values are in A1 down and puts results in C1 down.
Sub x()
Dim v1, v2(), i As Long, j As Long
v1 = Range("A1", Range("A" & Rows.Count).End(xlUp)).Value
ReDim v2(1 To UBound(v1, 1), 1 To 2)
For i = LBound(v1, 1) To UBound(v1, 1)
j = j + 1
v2(j, 1) = v1(i, 1)
If i <> UBound(v1, 1) Then
Do While Val(Right(v1(i + 1, 1), 3)) = Val(Right(v1(i, 1), 3)) + 1
i = i + 1
If i = UBound(v1, 1) Then
v2(j, 2) = v1(i, 1)
Exit Do
End If
Loop
End If
If v1(i, 1) <> v2(j, 1) Then v2(j, 2) = v1(i, 1)
Next i
Range("C1").Resize(j, 2) = v2
End Sub
Try the below code
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
Dim lastNum, Binsert As Integer
Dim firstCell, lastCell, currentCell As String
Binsert = 1
lastNum = getNum(wb.Sheets("Sheet1").Range("A1").Value)
firstCell = wb.Sheets("Sheet1").Range("A1").Value
For i = 2 To lastRow
activeNum = getNum(wb.Sheets("Sheet1").Range("A" & i).Value)
currentCell = wb.Sheets("Sheet1").Range("A" & i).Value
If (activeNum - lastNum) = 1 Then
'nothing
Else
lastCell = wb.Sheets("Sheet1").Range("A" & (i - 1)).Value
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> lastCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = lastCell
End If
Binsert = Binsert + 1
firstCell = wb.Sheets("Sheet1").Range("A" & i).Value
End If
lastNum = activeNum
Next i
'last entry
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> currentCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = currentCell
End If
End Sub
Public Function getNum(ByVal num As String) As Integer
getNum = Val(Mid(num, 2))
End Function
Another solution. It loops backwards from last row to first row.
Option Explicit
Public Sub FindConsecutiveValues()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lRow As Long 'find last row
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Dim lVal As String 'remember last value (stop value)
lVal = ws.Range("A" & lRow).Value
Const fRow As Long = 2 'define first data row
Dim i As Long
For i = lRow To fRow Step -1 'loop from last row to first row backwards
Dim iVal As Long
iVal = Val(Right(ws.Range("A" & i).Value, Len(ws.Range("A" & i).Value) - 1)) 'get value of row i without A so we can calculate
Dim bVal As Long
bVal = 0 'reset value
If i <> fRow Then 'if we are on the first row there is no value before
bVal = Val(Right(ws.Range("A" & i - 1).Value, Len(ws.Range("A" & i - 1).Value) - 1)) 'get value of row i-1 without A
End If
If iVal - 1 = bVal Then
ws.Rows(i).Delete 'delete current row
Else
If lVal <> ws.Range("A" & i).Value Then 'if start and stop value are not the same …
ws.Range("B" & i).Value = lVal 'write stop value in column B
End If
lVal = ws.Range("A" & i - 1).Value 'remember now stop value
End If
Next i
End Sub

Using text values in Combobox

I would like to also use text values to populate textbox one to four right now only number values will fetch data in the textbox, I know I am overlooking a pretty simple thing but can't seem to find out what?
Private Sub ComboBox1_Change()
Dim i As Long, LastRow As Long, ws As Worksheet
Set ws = Sheets("Sheet1")
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
If Val(Me.ComboBox1.Value) = ws.Cells(i, "A") Then
MsgBox Me.ComboBox1.Value
Me.TextBox1 = ws.Cells(i, "B").Value
Me.TextBox2 = ws.Cells(i, "C").Value
Me.TextBox3 = ws.Cells(i, "D").Value
Me.TextBox4 = ws.Cells(i, "E").Value
End If
Next i
End Sub
I fixed it myself with the possibility to reverse it.
FYI: sheet is renamed to "Control"
Private Sub UserForm_Initialize()
With Sheets("Control")
Me.ComboBox1.List = .Range("a2", .Range("a" & Rows.Count).End(xlUp)).Value
End With
End Sub
Private Sub ComboBox1_Change()
Dim i As Long
For i = 1 To 4
Me("textbox" & i).Value = ""
Next
If Me.ComboBox1.ListIndex = -1 Then Exit Sub
With Sheets("control")
For i = 1 To 4
Me("textbox" & i).Value = .Cells(Me.ComboBox1.ListIndex + 2, i + 1).Value
Next
End With
End Sub
Private Sub CommandButton2_Click()
If Me.ComboBox1.ListIndex = -1 Then Exit Sub
Sheets("control").Cells(Me.ComboBox1.ListIndex + 2, "b").Resize(, 4).Value = _
Array(Me.TextBox1.Value, Me.TextBox2.Value, Me.TextBox3.Value, Me.TextBox4.Value)
End Sub

I have written a piece of code that does reconciliation: The first part checks between columns:

I have written a piece of code that does reconciliation:
The first part checks between columns.
Works absolutely fine on upto 100k Rows, then simply freezes on anything bigger. Is the an optimal way to write this? Should I be using a scripting dictionary for the reconciliation too? Ive been off VBA for a while now and I am pretty rusty! Thanks for reading and helping.
Sub AutoRecon()
Worksheets("Main_Recon").Select
Dim i As Long, _
LRa As Long, _
LRb As Long, _
rowx As Long
LRa = Range("A" & Rows.Count).End(xlUp).Row
LRb = Range("G" & Rows.Count).End(xlUp).Row
rowx = 2
Application.ScreenUpdating = False
For i = 2 To LRa
If Range("A" & i).Errors.Item(xlNumberAsText).Value = True Then
Range("A" & i).Value = "N" & Range("A" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRb
If Range("G" & i).Errors.Item(xlNumberAsText).Value = True Then
Range("G" & i).Value = "N" & Range("G" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRa
If IsError(Application.Match(Range("A" & i).Value, Range("G2:G" & LRb), 0)) Then
Range("O" & rowx).Value = Range("A" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRb
If IsError(Application.Match(Range("G" & i).Value, Range("A2:A" & LRa), 0)) Then
Range("S" & rowx).Value = Range("G" & i).Value
rowx = rowx + 1
End If
Next i
Application.ScreenUpdating = True
End Sub
This takes too long.
The issue is that you run the loop 4 times, but you can combine 2 loops.
You can gain some speed in the process using arrays to read/write. Every read/write action to a cell needs a lot of time. So the idea is to read all data cells into an array DataA at once (only 1 read action) then process the data in the array and then write it back to the cells at once (only 1 write action). So if you have 100 rows you save 99 read/write actions.
So you would end up with something like below. Note this is untested, so backup before running this.
Option Explicit
Public Sub AutoRecon()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Main_Recon")
Application.ScreenUpdating = False
'find last rows of columns
Dim LastRowA As Long
LastRowA = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim LastRowG As Long
LastRowG = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row
'read data into array
Dim DataA() As Variant 'read data from column A into array
DataA = ws.Range("A1", "A" & LastRowA).Value
Dim DataG() As Variant 'read data from column G into array
DataG = ws.Range("G1", "G" & LastRowG).Value
Dim iRow As Long
For iRow = 2 To Application.Max(LastRowA, LastRowG) 'combine loop to the max of both columns
If iRow <= LastRowA Then 'run only until max of column A
If ws.Cells(iRow, "A").Errors.Item(xlNumberAsText).Value = True Then
DataA(iRow, 1) = "N" & DataA(iRow, 1)
End If
End If
If iRow <= LastRowG Then 'run only until max of column G
If ws.Cells(iRow, "G").Errors.Item(xlNumberAsText).Value = True Then
DataG(iRow, 1) = "N" & DataG(iRow, 1)
End If
End If
Next iRow
'write array back to sheet
ws.Range("A1", "A" & LastRowA).Value = DataA
ws.Range("G1", "G" & LastRowG).Value = DataG
'read data into array
Dim DataO() As Variant 'read data from column O into array (max size = column A)
DataO = ws.Range("O1", "O" & LastRowA).Value
Dim DataS() As Variant 'read data from column G into array (max size = column G)
DataS = ws.Range("S1", "S" & LastRowG).Value
Dim oRow As Long, sRow As Long
oRow = 2 'output row start
sRow = 2
For iRow = 2 To Application.Max(LastRowA, LastRowG) 'combine loop to the max of both columns
If iRow <= LastRowA Then
If IsError(Application.Match(DataA(iRow, 1), DataG, 0)) Then
DataO(oRow, 1) = DataA(iRow, 1)
oRow = oRow + 1
End If
End If
If iRow <= LastRowG Then
If IsError(Application.Match(DataG(iRow, 1), DataA, 0)) Then
DataS(sRow, 1) = DataG(iRow, 1)
sRow = sRow + 1
End If
End If
Next iRow
'write array back to sheet
ws.Range("O1", "O" & LastRowA).Value = DataO
ws.Range("S1", "S" & LastRowG).Value = DataS
Application.ScreenUpdating = True
End Sub

how to copy an entire row to sheet 2 if column H has a date in cell.?

I am trying to search (if column H in sheet mechanical Equip. has any date then copy entire row to sheet off rent next available row. It is coping the first row from mechanical equip. whether it has a date or not.
Sub CopyRowWithDates()
Dim lrowcompleted As String
Dim Rrange As Range
Set Rrange = Sheets("MECHANICAL EQUIP.").Range("H2:H6000")
On Error Resume Next
Application.EnableEvents = False
If Rrange = "mm/dd/yyy" Then
lrowcompleted = Sheets("OFF RENT").Cells(Rows.Count, "A").End(xlUp).ROW
Range("A" & Rrange.ROW & ":N" & Rrange.ROW).Copy Sheets("OFF RENT").Range("A" & lrowcompleted + 1)
Else
End If
Application.EnableEvents = True
End Sub
If you use For each myDate in range("H2:H6000") instead of set range?
Sub CopyRowWithDates()
Application.EnableEvents = False
Application.ScreenUpdating = False
Dim lrowcompleted As String
Dim myDate as String
For each myDate in range("H2:H6000")
On Error Resume Next
Application.EnableEvents = False
If myDate = "mm/dd/yyy" Then
lrowcompleted = Sheets("OFF RENT").Cells(Rows.Count, "A").End(xlUp).ROW
Range("A" & myDate.ROW & ":N" & myDate.ROW).Copy Sheets("OFF RENT").Range("A" & lrowcompleted + 1)
Else
End If
Application.EnableEvents = True
Application.Screenupdating = True
End Sub
I prefer to use Range("A1048576").End(xlUp).Rowinstead of Cells(Rows.Count,"A").End(xlUp).ROW
i modified a different code i had and this one works the way i need it to. thanks for help.
Private Sub CommandButton5_Click()
Dim id As String
Dim PO As String
Dim finalrow As Integer
Dim i As Integer
Dim lrowcompleted As String
id = TextBox19.Value
finalrow = Sheets("ALL P.O. INFO").Range("D6000").End(xlUp).row
For i = 2 To finalrow
If Sheets("ALL P.O. INFO").Cells(i, 4) = id Then
Sheets("ALL P.O. INFO").Cells(i, 8).Value = TextBox17.Value
End If
If Sheets("MECHANICAL EQUIP.").Cells(i, 4) = id Then
Sheets("MECHANICAL EQUIP.").Cells(i, 8).Value = TextBox17.Value
lrowcompleted = Sheets("OFF RENT").Range("A6000").End(xlUp).row
Sheets("MECHANICAL EQUIP.").Range("A" & i & ":N" & i).Copy Sheets("OFF RENT").Range("A" & lrowcompleted + 1)
End If

concatenate vba excel keep format

I am building on some code, partly cut and paste from other posts. I need to concatenate with a VBA code keeping the format and running through rows to output in last cell in each row. (Can't paste image) so hope description is clear:
In A1:D1 values are RED,BLUE,GREEN
In A2:D2 Values are YELLOW,PURPLE,ORANGE
OUTPUT IN E1 should concatenate these values, keeping font colour. Each value should have "ALT ENTR" to give line break.
Next row should be displayed in E2, and so on
'************************************************************************************
Sub test()
Dim rng As Range: Set rng = Application.Range("a1:c1") 'Not yet looping
Dim row As Range
For Each row In rng.Rows
'Debug.Print col.Column
Call concatenate_cells_formats(Cells(1, 4), rng) 'Not yet looping
Next row
End Sub
Sub concatenate_cells_formats(cell As Range, source As Range)
'Anon
Dim c As Range
Dim i As Integer
i = 1
With cell
.Value = vbNullString
.ClearFormats
For Each c In source
.Value = .Value & " " & Trim(c)
Next c
.Value = Trim(.Value)
For Each c In source
With .Characters(Start:=i, Length:=Len(Trim(c))).Font
.Name = c.Font.Name
.FontStyle = c.Font.FontStyle
.Size = c.Font.Size
.Strikethrough = c.Font.Strikethrough
.Superscript = c.Font.Superscript
.Subscript = c.Font.Subscript
.OutlineFont = c.Font.OutlineFont
.Shadow = c.Font.Shadow
.Underline = c.Font.Underline
.ColorIndex = c.Font.ColorIndex
End With
.Characters(Start:=i + Len(c), Length:=1).Font.Size = 1
i = i + Len(Trim(c)) + 1
Next c
End With
End Sub
'*****************************************************************************
Option Explicit
Sub concColour()
Dim i As Long, j As Long, s As Long, l As Long, clr As Long, vals As Variant
With Worksheets("sheet4")
For i = 1 To .Cells(.Rows.Count, "A").End(xlUp).Row
vals = Application.Transpose(Application.Transpose(Intersect(.Range("A:D"), .Rows(i)).Value2))
.Cells(i, "E") = Join(vals, vbLf)
s = 1
For j = LBound(vals) To UBound(vals)
l = Len(vals(j))
clr = .Cells(i, "A").Offset(0, j - 1).Font.Color
With .Cells(i, "E").Characters(Start:=s, Length:=l).Font
.Color = clr
End With
s = s + l + 1
Next j
.Cells(i, "E").Font.Size = 4
Next i
End With
End Sub
enter image description here
I think you require something like this. Change source font and formats as per your requirement.
Sub Adding_T()
Dim lena As Integer
Dim lenc As Integer
Dim lend As Integer
Dim lene As Integer
Dim LastRow As Long
Dim nrow As Long
With Worksheets("Sheet2") 'Change sheet as per your requirement
LastRow = .Cells(.Rows.Count, "A").End(xlUp).row
For nrow = 1 To LastRow
.Range("E" & nrow) = .Range("A" & nrow).Value2 & Chr(13) & Chr(10) & .Range("B" & nrow).Value2 & _
Chr(13) & Chr(10) & .Range("C" & nrow).Value2 & Chr(13) & Chr(10) & .Range("D" & nrow).Value2
lena = Len(.Range("A" & nrow).Value2)
lenc = lena + 2 + Len(.Range("B" & nrow).Value2)
lend = lenc + 2 + Len(.Range("C" & nrow).Value2)
lene = lend + 2 + Len(.Range("D" & nrow).Value2)
For i = 1 To lena
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("A" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lena + 2 To lenc
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("B" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lenc + 2 To lend
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("C" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lend + 2 To lene
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("D" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
Next
End With
End Sub
Snapshot of trial:
EDIT: OP Preferred code does not permit looping through the Range. Amended his Sub Test() to allow looping through the range.
Sub Test2()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = ThisWorkbook.ActiveSheet
Dim rng As Range
Dim row As Range
Dim rw As Long
LastRow = ws.Cells(Rows.Count, "A").End(xlUp).row
rw = 1
For rw = 1 To LastRow
Set rng = ws.Range("A" & rw & ":C" & rw)
Call concatenate_cells_formats(Cells(rw, 4), rng)
Next
End Sub
Results are as per snapshot appended here.

Resources