Numbering my cells and resetting based on year - vba

This is my first post to stack overflow and my first online question about programming.
I am developing a program to record requests for projects (Work Orders) in a manufacturing plant. The current system is being removed due to the switch from Windows XP.
I am having trouble developing my numbering code.
The format of the code is:
YY - ######. I'm currently using:
.Cells(iRow, 1).Value = Format(Date, "yy") & " - " & Format(iRow - 1, "000000")
So that would input the Year and the "iRow" - 1 into the first column. iRow is determined using:
iRow = 2 'starting index for next empty WONum cell
With WORecordSheet
'Find the next empty WONum cell
Do While .Cells(iRow, 1).Value <> ""
.Cells(iRow, 1).Activate
iRow = iRow + 1
Loop
End With
It loops through each until an empty row is found, then inputs the number using the year and that specified row minus one into that cell.
The problem I'm having is with the year. When a new year comes, it needs to switch back to the first work order.... Such as:
14 - 001111
14 - 001112
14 - 001113
15 - 000001
15 - 000002
But, the problem is that the number is made using the row, so it won't restart with a new year. I know that I will need another variable that either adds 1 to the previous number if the year is the same or loops through just the rows of the same year until a new row is found and that is the number put in for the work order number, but the empty row to input the number into should be decided the same way as before, with the iRow loop.
I do not know how I could determine the year of the previous entry... Could you somehow separate the value into the two parts of "YY" and "######"? And run an if statement that if the "YY" is the same as the current year then it adds 1 to the "######"?
Thanks for any suggestions!
UPDATE: I have created a block of code that works. It is based off of the response from #user1759942 . However, I did reference the other responses to dim variables and use the "Right" function properly. Here is the updated code:
Dim iRow As Long
Dim yr As Long
Dim lCodeNum As Long
WORecordSheet.Activate
iRow = 2 'starting index for next empty WONum cell
lCodeNum = 1 'starting index for last 6 digits of wonum
With WORecordSheet
'Find the next empty WONum cell
Do While .Cells(iRow, 1).Value <> ""
.Cells(iRow, 1).Activate
iRow = iRow + 1
Loop
yr = Left(.Cells(iRow - 1, 1).Value, 2)
If yr = Format(Date, "yy") Then
lCodeNum = Right(.Cells(iRow - 1, 1).Value, 6) + 1
Else
lCodeNum = 1
End If
End With
And later on:
.Cells(iRow, 1).Value = Format(Date, "yy") & " - " & Format(lCodeNum, "000000")

you can do exactly what you thought. Separate the YY from the rest and examine that.
have a variable - dim yr as string to save the year, and I'd use a separate variable for putting the number: dim lCodeNum as long and in the while loop set those variables too
dim yr as string
iRow = 2 'starting index for next empty WONum cell
lCodeNum = 1
With WORecordSheet
'Find the next empty WONum cell
yr = left(.cells(iRow,1).value, 2) 'gets the first 2 characters in the cell
Do While .Cells(iRow, 1).Value <> ""
.Cells(iRow, 1).Activate
iRow = iRow + 1
if not left(.cells(iRow, 1).value, 2) = yr then
lCodeNum = 1
else
lCodeNum = lCodeNum + 1
end if
yr = left(.cells(iRow,1).value, 2)
Loop
End With
then when you assign the value to the empty cell you can do:
.Cells(iRow, 1).Value = Format(Date, "yy") & " - " & Format(lCodeNum, "000000")
so the way above, you're using irow to loop over every row, and to reference the cells, but using lCodeNum as the number, thus it resets to 1 every time a new year is encountered.
you could use irow instead of lcodenum, but then you could only put 1 if a new year was encountered, and then the numbers would pick up where they left off, so you'd end up with like
14 - 000144
14 - 000145
15 - 000001
15 - 000147

This isn't a 100% complete answer, but hopefully it will give you everything you need to apply it to your own program. Also, this isn't the only way to address this, but it is one way. Hopefully it will give you a good enough nudge in the right direction...
It's simple enough to get the last two digits of the current year in VBA doing something like:
Dim yearDigits As Long
yearDigits = Right(Year(Now), 2)
now that you know the current year's last 2 digits, you can compare it to the some data string like YY - ###### by doing something close to:
Dim invoice As String
yearDigits = Right(year(Now), 2)
invoice = "13 - 001111"
invoiceYear = Left(invoice, 2)
tying it together may look something like:
Sub test()
Dim yearDigits As Long
Dim invoice As String
Dim invoiceYear As Long
Dim equalYear As Boolean
yearDigits = Right(year(Now), 2)
invoice = "13 - 001111"
invoiceYear = Left(invoice, 2)
equalYear = yearDigits = invoiceYear
MsgBox "Current Year = " & yearDigits & ". Invoice Year = " & invoiceYear & ". Are they equal? " & equalYear
End Sub
If this doesn't help, or you need some help applying it to your code, please post back and I'll give you some more nudges.
Good luck!

This should place a new number code in column A each time it is run. It should re-start the sequencing on change of year:
Sub FillId()
Dim N As Long, Prev As String, PrevYr As Long, PrevNum As Long
Dim Yr As Long, M As Long
If Range("A1").Value = "" Then
Range("A1").Value = Mid(Year(Date), 3) & " - " & "000001"
Exit Sub
End If
N = Cells(Rows.Count, "A").End(xlUp).Row
Prev = Cells(N, "A").Value
PrevYr = CLng(Mid(Prev, 1, 2))
PrevNum = CLng(Mid(Prev, 6))
Yr = CLng(Mid(Year(Date), 3))
If Yr <> PrevYr Then
M = 1
Else
M = PrevNum + 1
End If
Cells(N + 1, "A").Value = Mid(Year(Date), 3) & " - " & Format(M, "000000")
End Sub

Related

Auto scheduling

I am trying to make an auto scheduling program with an excel.
For example, each number is certain job assigned to the person given day.
1/2 1/3 1/4 1/5
Tom 1 2 2 ?
Justin 2 3 1 ?
Mary 3 3 ?
Sam 1 ?
Check O O X ? ## check is like =if(b2=c2,"O","X")
The things I want to make sure is every person is given a different job from yesterday.
My idea
while
randomly distribute jobs for 1/5
wend CheckCell = "O"
But I found that checking cell in the vba script doesn't work - the cell is not updated in each while loop.
Could you give me a little pointer for these kinds of program? Because I am new to vbaScript, any kinds of help would be appreciated.
Using VBA, I'm sure there are better ways to do this, but this will check the values from the penultimate column against values from last column and if they match it will write "O" to under the last column, else it will write "X":
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A
LastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
counter = 0 'set counter
For i = 2 To LastRow 'loop through penultimate column and add values to array
If ws.Cells(i, LastCol - 1).Value <> "" Then
Values = Values & ws.Cells(i, LastCol - 1) & ","
End If
Next i
Values = Left(Values, Len(Values) - 1)
Values = Split(Values, ",") 'split values into array
For i = 2 To LastRow 'loop through last column and add values to array
If ws.Cells(i, LastCol).Value <> "" Then
ValuesCheck = ValuesCheck & ws.Cells(i, LastCol) & ","
End If
Next i
ValuesCheck = Left(ValuesCheck, Len(ValuesCheck) - 1)
ValuesCheck = Split(ValuesCheck, ",")
For y = LBound(Values) To UBound(Values) 'loop through both arrays to find all values match
For x = LBound(ValuesCheck) To UBound(ValuesCheck)
If Values(y) = ValuesCheck(x) Then counter = counter + 1
Next x
Next y
If counter = UBound(Values) + 1 Then 'if values match
ws.Cells(LastRow + 1, LastCol).Value = "O"
Else 'else write X
ws.Cells(LastRow + 1, LastCol).Value = "X"
End If
End Sub
just to clarify are you looking to implement the random number in the vba or the check.
To do the check the best way would be to set the area as a range and then check each using the cells(r,c) code, like below
Sub checker()
Dim rng As Range
Dim r As Integer, c As Integer
Set rng = Selection
For r = 1 To rng.Rows.Count
For c = 1 To rng.Columns.Count
If rng.Cells(r, c) = rng.Cells(r, c + 1) Then
rng.Cells(r, c).Interior.Color = RGB(255, 0, 0)
End If
Next c
Next r
End Sub
this macro with check the text you have selected for the issue and change the cell red if it matches the value to the right.
To make it work for you change set rng = selection to your range and change the rng.Cells(r, c).Interior.Color = RGB(255, 0, 0) to the action you want
A sligthly different approach than the other answers.
Add this function:
Function PickJob(AvailableJobs As String, AvoidJob As String)
Dim MaxTries As Integer
Dim RandomJob As String
Dim Jobs() As String
Jobs = Split(AvailableJobs, ",")
MaxTries = 100
Do
MaxTries = MaxTries - 1
If MaxTries = 0 Then
MsgBox "Could find fitting job"
End
End If
RandomJob = Jobs(Int((1 + UBound(Jobs)) * Rnd()))
Loop Until RandomJob <> AvoidJob
PickJob = RandomJob
End Function
And put this formula in your sheet
=PickJob("1,2,3",D2)
where D2 points to is the previous job

VBA - Find first and last rows of repeating text

My question is similar to this one VBA - Find first and last row containing specific text but I need a little tweak. My Column A values are Delete, Delete end, and -(dash) only and I need to get the first rows where Delete is and last rows where Delete end is.
Rows Column A
1 Delete
2 Delete
3 Delete end
4 -
5 -
6 -
7 -
8 Delete
9 Delete end
Edit:
I would like to extract the rows 1 and 3, and 8 and 9, not the range like A1:A3. How should I do this approach?
Hope this is what you want.
Assuming your data starts with A2..
Sub test()
Dim lastrow As Long, i As Long
Dim startaddress As String, endaddress As String, alladdress As String
lastrow = Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, 1) = "Delete" Then
startaddress = Cells(i, 1).Address
Do While Cells(i, 1) <> "Delete end"
i = i + 1
Loop
endaddress = Cells(i, 1).Address
If alladdress <> "" Then
alladdress = alladdress & ", " & startaddress & ":" & endaddress
Else
alladdress = startaddress & ":" & endaddress
End If
End If
Next i
Cells(2, 2) = alladdress
End Sub

add the count of non-blank cells to the count of preceeding value VBA

I am new to excel vba and I would like help with the problem I am facing.
I have put across a small example in the above link.
What I would like is to count the number of characters in each column in a defined range.
However if there are blank cells, then the blank cell gets counted to the preceding non-blank value.
In example 1: cells 3,4 are empty and their preceding non-blank value is R. So count of R becomes 4.
Cell 6 is empty as well and therefore gets added to the count of Y which is the preceding non-blank value. So count of Y is 2.
In example 2: cells 1,2 are empty however they don't have any preceding non-blank value and hence they are not counted.
Also, cells 4,5,6 are empty. However they have a preceding non-blank value Y.
So count of Y is 4
Can someone help me to code this in VBA?
Assuming that you have row index on column A and Data in column B and the data in your sheet starts from row number 3 (as shown on your image), I would suggest the following code :
Sub test()
Dim rowNum As Integer
Dim prevRowData As String
Dim rCount, yCount
rowNum = 3
prevRowData = ""
rCount = 0
yCount = 0
Do While Trim(Range("A" & rowNum).Value) <> ""
Select Case (Trim(Range("B" & rowNum).Value))
Case "R"
rCount = rCount + 1
prevRowData = "R"
Case "Y"
yCount = yCount + 1
prevRowData = "Y"
Case ""
If prevRowData = "R" Then
rCount = rCount + 1
ElseIf prevRowData = "Y" Then
yCount = yCount + 1
End If
End Select
rowNum = rowNum + 1
Loop
Range("A" & (rowNum + 1)).Value = "Count of R:" & rCount
Range("A" & (rowNum + 2)).Value = "Count of y:" & yCount
End Sub
Something like this will do it. Something to note is that this will only go to the last row used, so your row six would not get counted because there is no data beyond row 5. You can replace lastRow with the row number to go to if you know that row but I'm not sure how you know the last blank row that should be counted.
In you VBA IDE go to the tools menu and select references. Select "Microstoft ActiveX data objects 2.8 Library.
We will use a ADODB Recordset to store the data as we find it.
This assumes your list is on Sheet1 and the data is in column A. It will write summary out below the data that is read up.
Private Sub CommandButton1_Click()
Dim rs As New ADODB.Recordset
Dim ws As Excel.Worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1")
Dim lastRow As Long
Dim lRow As Long
Dim szLastData As String
'Add fields to your recordset for storing data.
With rs
.Fields.Append "Value", adChar, 25
.Fields.Append "Count", adInteger
.Open
End With
'This is getting the last used row in column A
lastRow = ws.Cells(ws.Rows.count, "A").End(xlUp).Row
'Loop through the rows
lRow = 1
Do While lRow <= lastRow
'Update the value we will search for in out rs if there is data in the current row
If ws.Range("A" & lRow).Value <> "" Then
szLastData = ws.Range("A" & lRow).Value
End If
'Check if this is already data that we are counting
rs.Filter = ""
rs.Filter = "Value='" & szLastData & "'"
If rs.RecordCount = 0 Then
'If this is new data, add a new row for it
rs.AddNew
rs.Fields("Value").Value = ws.Range("A" & lRow).Value
rs.Fields("Count").Value = 1
rs.Update
Else
'If we get here, we already have this data.
'Increment the count by 1
rs.Fields("Count").Value = rs.Fields("Count").Value + 1
rs.Update
End If
lRow = lRow + 1
Loop
'Remove the filer and move to the first record in the rs
rs.Filter = ""
rs.MoveFirst
'Move down a row
lRow = lRow + 1
'Loop through the data we found and write a summary
Do While rs.EOF = False
ws.Range("A" & lRow).Value = rs.Fields("Value").Value
ws.Range("B" & lRow).Value = rs.Fields("Count").Value
lRow = lRow + 1
rs.MoveNext
Loop
End sub

Split rows that have multiline text and single line text

I'm trying to figure out how to split rows of data where columns B,C,D in the row contain multiple lines and others do not. I've figured out how to split the multi-line cells if I copy just those columns into a new sheet, manually insert rows, and then run the macro below (that's just for column A), but I'm lost at coding the rest.
Here's what the data looks like:
So for row 2, I need it split into 6 rows (one for each line in cell B2) with the text in cell A2 in A2:A8. I also need columns C and D split the same as B, and then columns E:CP the same as column A.
Here is the code I have for splitting the cells in columns B,C,D:
Dim iPtr As Integer
Dim iBreak As Integer
Dim myVar As Integer
Dim strTemp As String
Dim iRow As Integer
iRow = 0
For iPtr = 1 To Cells(Rows.Count, col).End(xlUp).Row
strTemp = Cells(iPtr1, 1)
iBreak = InStr(strTemp, vbLf)
Range("C1").Value = iBreak
Do Until iBreak = 0
If Len(Trim(Left(strTemp, iBreak - 1))) > 0 Then
iRow = iRow + 1
Cells(iRow, 2) = Left(strTemp, iBreak - 1)
End If
strTemp = Mid(strTemp, iBreak + 1)
iBreak = InStr(strTemp, vbLf)
Loop
If Len(Trim(strTemp)) > 0 Then
iRow = iRow + 1
Cells(iRow, 2) = strTemp
End If
Next iPtr
End Sub
Here is a link to an example file (note this file has 4 rows, the actual sheet has over 600): https://www.dropbox.com/s/46j9ks9q43gwzo4/Example%20Data.xlsx?dl=0
This is a fairly interesting question and something I have seen variations of before. I went ahead and wrote up a general solution for it since it seems like a useful bit of code to keep for myself.
There are pretty much only two assumptions I make about the data:
Returns are represented by Chr(10) or which is the vbLf constant.
Data that belongs with a lower row has enough returns in it to make it line up. This appears to be your case since there are return characters which appear to make things line up like you want.
Pictures of the output, zoomed out to show all the data for A:D. Note that the code below processes all of the columns by default and outputs to a new sheet. You can limit the columns if you want, but it was too tempting to make it general.
Code
Sub SplitByRowsAndFillBlanks()
'process the whole sheet, could be
'Intersect(Range("B:D"), ActiveSheet.UsedRange)
'if you just want those columns
Dim rng_all_data As Range
Set rng_all_data = Range("A1").CurrentRegion
Dim int_row As Integer
int_row = 0
'create new sheet for output
Dim sht_out As Worksheet
Set sht_out = Worksheets.Add
Dim rng_row As Range
For Each rng_row In rng_all_data.Rows
Dim int_col As Integer
int_col = 0
Dim int_max_splits As Integer
int_max_splits = 0
Dim rng_col As Range
For Each rng_col In rng_row.Columns
'splits for current column
Dim col_parts As Variant
col_parts = Split(rng_col, vbLf)
'check if new max row count
If UBound(col_parts) > int_max_splits Then
int_max_splits = UBound(col_parts)
End If
'fill the data into the new sheet, tranpose row array to columns
sht_out.Range("A1").Offset(int_row, int_col).Resize(UBound(col_parts) + 1) = Application.Transpose(col_parts)
int_col = int_col + 1
Next
'max sure new rows added for total length
int_row = int_row + int_max_splits + 1
Next
'go through all blank cells and fill with value from above
Dim rng_blank As Range
For Each rng_blank In sht_out.Cells.SpecialCells(xlCellTypeBlanks)
rng_blank = rng_blank.End(xlUp)
Next
End Sub
How it works
There are comments within the code to highlight what is going on. Here is a high level overview:
Overall, we iterate through each row of the data, processing all of the columns individually.
The text of the current cell is Split using the vbLf. This gives an array of all the individual lines.
A counter is tracking the maximum number of rows that were added (really this is rows-1 since these arrays are 0-indexed.
Now the data can be output to the new sheet. This is easy because we can just dump the array that Split created for us. The only tricky part is getting it to the right spot on the sheet. To that end, there is a counter for the current column offset and a global counter to determine how many total rows need to be offset. The Offset moves us to the right cell; the Resize ensures that all of the rows are output. Finally, Application.Transpose is needed because Split returns a row array and we're dumping a column.
Update the counters. Column offset is incremented every time. The row offset is updated to add enough rows to cover the last maximum (+1 since this is 0-indexed)
Finally, I get to use my waterfall fill (your previous question) on all of the blanks cells that were created to ensure no blanks. I forgo error checking because I assume blanks exist.
Thank you for providing a sample. This task was so interesting that I thought of writing the code for that. You are more than welcome to tweak it to your satisfaction, and I hope your team gets to use an RDBMS to manage this kind of data in the future.
Sub OrganizeSheet()
Dim LastRow As Integer
LastRow = GetLastRow()
Dim Barray() As String
Dim Carray() As String
Dim Darray() As String
Dim LongestArray As Integer
Dim TempInt As Integer
Dim i As Integer
i = 1
Do While i <= LastRow
Barray = Split(Range("B" & i), Chr(10))
Carray = Split(Range("C" & i), Chr(10))
Darray = Split(Range("D" & i), Chr(10))
LongestArray = GetLongestArray(Barray, Carray, Darray)
If LongestArray > 0 Then
' reset the values of B, C and D columns
On Error Resume Next
Range("B" & i).Value = Barray(0)
Range("C" & i).Value = Carray(0)
Range("D" & i).Value = Darray(0)
Err.Clear
On Error GoTo 0
' duplicate the row multiple times
For TempInt = 1 To LongestArray
Rows(i & ":" & i).Select
Selection.Copy
Range(i + TempInt & ":" & i + TempInt).Select
Selection.Insert Shift:=xlDown
' as each row is copied, change the values of B, C and D columns
On Error Resume Next
Range("B" & i + TempInt).Value = Barray(TempInt)
If Err.Number > 0 Then Range("B" & i + TempInt).Value = ""
Err.Clear
Range("C" & i + TempInt).Value = Carray(TempInt)
If Err.Number > 0 Then Range("C" & i + TempInt).Value = ""
Err.Clear
Range("D" & i + TempInt).Value = Darray(TempInt)
If Err.Number > 0 Then Range("D" & i + TempInt).Value = ""
Err.Clear
On Error GoTo 0
Application.CutCopyMode = False
Next TempInt
' increment the outer FOR loop's counters
LastRow = LastRow + LongestArray
i = i + LongestArray
End If
i = i + 1
Loop
End Sub
' ----------------------------------
Function GetLongestArray(ByRef Barray() As String, ByRef Carray() As String, ByRef Darray() As String)
GetLongestArray = UBound(Barray)
If UBound(Carray) > GetLongestArray Then GetLongestArray = UBound(Carray)
If UBound(Darray) > GetLongestArray Then GetLongestArray = UBound(Darray)
End Function
' ----------------------------------
Function GetLastRow() As Integer
Worksheets(1).Select
Range("A1").Select
Selection.End(xlDown).Select
GetLastRow = Selection.Row
Range("A1").Select
End Function
Give it a shot!

Pop-Up User Form To Select Non Empty Columns Selects Empty Ones

I have a workbook that is organized within a main sheet. Every item has 3 rows. These items are grouped and sub-grouped by row and columns.
I have developed several reporting options. These reports identify certain items based upon characteristics in the main sheet and copy them over to another sheet. So far, so good.
My final task would appear simple and based upon prior logic I developed. I need a pop-up window that prompts the user for a column. Based upon the column input, I grab all rows that are not empty (in their corresponding groups of 3) and copy them over. As I indicated, this logic worked previously. I leave a blank row between the groups for easy reading.
I take the column input and translate to column number (thanks to you and a previous post!). The problem is that the code copies over the groups correctly (with non-blank entries), and then once it leaves the first row grouping, it starts copying over non-blank entries.
I know what the entries will be in these columns and also tried using a key method - converting the known entries to ascii and checking cell value against that. Still, the same result.
I am wondering if the problem is the fact that the code resides in the userform? Do I need to separate the userform from the macro? Is columnNumber somehow getting overwritten (it appears that way). There may be artifacts (unused variables) from previous versions and troublshooting...
I grant this is not the most elegant coding I've done, but I am running out of time (I only have a few days left for this entire project). Here it is, and ANY advice or help is greatly appreciated. THANK YOU well in advance :)
Private Sub Cancel_Click()
UserForm4.Hide
End Sub
Private Sub Go_Click()
Dim Test As String
Dim colNumber, columnNumber As Integer
Dim m As Integer
Dim ws2 As String
Dim i, j, k, r As Integer
Dim BlankRow2
Dim ColorCode As Integer
Dim RqtRow As Integer
Dim Item As Integer
Dim ColVal, AscCol As String
Dim Row1Value, Row2Value, Row3Value As Integer
' Initialize Variables
ws1 = "Requirements_Matrix"
ws2 = "OUTPUT"
RqtRow = 8
BlankRow2 = 4
Item = BlankRow2
Lastrow1 = Sheets(ws1).Cells(Rows.Count, "A").End(xlUp).Row
Lastcol1 = Sheets(ws1).Cells(1, Columns.Count).End(xlToLeft).Column
Lastrow2 = Sheets(ws2).Cells(Rows.Count, "A").End(xlUp).Row
Lastcol2 = Sheets(ws2).Cells(1, Columns.Count).End(xlToLeft).Column
Test = UserForm4.WhichTest.Value
If Test <> "" Then
colLetter = UCase(Test)
colNumber = 0
For m = 1 To Len(colLetter)
colNumber = colNumber + (Asc(Mid(colLetter, Len(colLetter) - m + 1, 1)) - 64) * 26 ^ (m - 1)
Next
columnNumber = colNumber
If (columnNumber < 24) Or (columnNumber > 136) Then
UserForm5.Show 'outside test columns - do not have time to execute further error testing...
Else 'Copy requirements from Requirements_Matrix Sheet to Output Sheet
With Sheets(ws2)
Sheets(ws2).Select
Rows("4:5000").Select
Selection.Delete Shift:=xlUp
End With
Sheets(ws1).Select
For i = 8 To Lastrow1 'find non-empty cells
If Sheets(ws1).Cells(i, 3).Interior.ColorIndex = 34 Then
Row3Value = Sheets(ws1).Cells(i, 3).Value
End If
If Sheets(ws1).Cells(i, 2).Interior.ColorIndex = 44 Then
Row2Value = Sheets(ws1).Cells(i, 2).Value
End If
If Sheets(ws1).Cells(i, 1).Interior.ColorIndex = 37 Then
Row1Value = Sheets(ws1).Cells(i, 1).Value
End If
If Sheets(ws1).Cells(i, 5) = "Requirement" Then 'Requirement Row
RqtRow = i
End If
If (Sheets(ws1).Cells(i, columnNumber).Value <> Empty) And _
Sheets(ws1).Cells(i, 3).Interior.ColorIndex <> 34 And _
Sheets(ws1).Cells(i, 2).Interior.ColorIndex <> 44 And _
Sheets(ws1).Cells(i, 1).Interior.ColorIndex <> 37 Then
k = RqtRow + 2
Increment = BlankRow2 + 2
Sheets(ws1).Select
Rows(RqtRow & ":" & k).Select 'select requirement block containing non-blank cell
Selection.Copy
Sheets(ws2).Select
Range(BlankRow2 & ":" & Increment).Select
ActiveSheet.Paste
ActiveSheet.Cells(BlankRow2, 1).Value = Row1Value
ActiveSheet.Cells(BlankRow2, 2).Value = Row2Value
ActiveSheet.Cells(BlankRow2, 3).Value = Row3Value
BlankRow2 = Increment + 2 'leave a blank row between requirements
End If
Next
End If
Else
UserForm5.Show
End If
UserForm4.WhichTest.Value = Empty
UserForm4.Hide
End Sub