Automatically creating worksheets based on a list in excel - vba

I am trying to achieve the following.
When I enter a value on 'Master' worksheet in the Range A5:A50, a macro is run which creates a new worksheet with the same name as the value and then copies the template onto the new sheet.
In addition to this I would also like to copy the value adjacent to the value enter on Master worksheet to this new worksheet so it does calculations automatically.
For example I enter '1' in A5 and '2' in B5. I would like to create a new worksheet with name '1', copy the template from 'Template' worksheet and copy the value of B5 on to the new worksheet named '1'.
I have following code but it also tries to copy Template worksheet with macro is run which results in an error because a worksheet with name 'Template' already exists.
Sub CreateAndNameWorksheets()
Dim c As Range
Application.ScreenUpdating = False
For Each c In Sheets("Master").Range("A5:A50")
Sheets("Template").Copy After:=Sheets(Sheets.Count)
With c
ActiveSheet.Name = .Value
.Parent.Hyperlinks.Add Anchor:=c, Address:="", SubAddress:= _
"'" & .Text & "'!A1", TextToDisplay:=.Text
End With
Next c
Application.ScreenUpdating = True
End Sub

Right-click the Master worksheet's name tab and select View Code. When the VBE opens up, paste the following into the window titled something like Book1 - Master (Code).
Private Sub Worksheet_Change(ByVal target As Range)
If Not Intersect(target, Rows("5:50"), Columns("A:B")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Dim r As Long, rw As Long, w As Long
For r = 1 To Intersect(target, Rows("5:50"), Columns("A:B")).Rows.Count
rw = Intersect(target, Rows("5:50"), Columns("A:B")).Rows(r).Row
If Application.CountA(Cells(rw, 1).Resize(1, 2)) = 2 Then
For w = 1 To Worksheets.Count
If LCase(Worksheets(w).Name) = LCase(Cells(rw, 1).Value2) Then Exit For
Next w
If w > Worksheets.Count Then
Worksheets("Template").Visible = True
Worksheets("Template").Copy after:=Sheets(Sheets.Count)
With Sheets(Sheets.Count)
.Name = Cells(rw, 1).Value2
.Cells(1, 1) = Cells(rw, 2).Value
End With
End If
With Cells(rw, 1)
.Parent.Hyperlinks.Add Anchor:=Cells(rw, 1), Address:="", _
SubAddress:="'" & .Value2 & "'!A1", TextToDisplay:=.Value2
End With
End If
Next r
Me.Activate
End If
bm_Safe_Exit:
Worksheets("Template").Visible = xlVeryHidden
Me.Activate
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Note that this depends on you having a worksheet named Template in order to generate the new worksheets. It also keeps the Template worksheet xlVeryHidden which means that it will not show up if you try to unhide it. Go into the VBE and use the Properties window (e.g. F4) to set the visibility to visible.
This routine should survive pasting multiple values into A2:B50 but it will discard proposed worksheet names in column A that already exists. There must be a value i both column A and column B of any row before it will proceed.
There are currently no checks for illegal worksheet name characters. You may want to familiarize yourself with those and add some error checking.

Another example relevant to the post title but not the specific application. Code updates sheets in master list with list row number creating sheet from template if it doesn't exist.
Other reference: https://stackoverflow.com/a/18411820/9410024.
Sub UpdateTemplateSheets()
' Update sheets in list created from a template
'
' Input: List on master sheet, template sheet
' Output: Updated sheet from template for each item in list
'
Dim wsInitial As Worksheet
Dim wsMaster As Worksheet
Dim wsTemp As Worksheet
Dim lVisibility As XlSheetVisibility
Dim strSheetName As String
Dim rIndex As Long
Dim i As Long
On Error GoTo Safe_Exit
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
' Application.Calculation = xlCalculationManual
Set wsInitial = ActiveSheet
Set wsMaster = Sheets("Summary")
Set wsTemp = Sheets("Template")
lVisibility = wsTemp.Visible ' In case template sheet is hidden
wsTemp.Visible = xlSheetVisible
For rIndex = 2 To wsMaster.Cells(Rows.Count, "A").End(xlUp).Row
' Ensure valid sheet name
strSheetName = wsMaster.Cells(rIndex, "A").Text
For i = 1 To 7
strSheetName = Replace(strSheetName, Mid(":\/?*[]", i, 1), " ")
Next i
strSheetName = Trim(Left(WorksheetFunction.Trim(strSheetName), 31))
' Ensure sheet name doesn't already exist
If Not Evaluate("IsRef('" & strSheetName & "'!A1)") Then
wsTemp.Copy after:=Sheets(Sheets.Count)
With Sheets(Sheets.Count)
.Name = strSheetName
End With
End If
With Sheets(strSheetName)
.Range("B59").Value = rIndex * 16 + 1 ' Update template block option row
End With
Next rIndex
Safe_Exit:
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayAlerts = True
'Application.Calculation = xlCalculationAutomatic
wsInitial.Activate
wsTemp.Visible = lVisibility ' Set template sheet to its original visible state
End Sub

Related

table of contents vba- Visible sheets only

I'm trying to create a VBA code that will only create a ToC for visible sheets. I found some VBA code online and modified it to include Visible = True in the loop, but the hidden sheets are still displaying when I run the macro. I've included the code below and would appreciate any advice on tweaking it to only display visible sheets.
Sub TableOfContents_Create()
'Add a Table of Contents worksheets to easily navigate to any tab
Dim sht As Worksheet
Dim Content_sht As Worksheet
Dim myArray As Variant
Dim x As Long, y As Long
Dim shtName1 As String, shtName2 As String
Dim ContentName As String
'Inputs
ContentName = "Contents"
'Optimize Code
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'Delete Contents Sheet if it already exists
On Error Resume Next
Worksheets("Contents").Activate
On Error GoTo 0
If ActiveSheet.Name = ContentName Then
myAnswer = MsgBox("A worksheet named [" & ContentName & _
"] has already been created, would you like to replace it?", vbYesNo)
'Did user select No or Cancel?
If myAnswer <> vbYes Then GoTo ExitSub
'Delete old Contents Tab
Worksheets(ContentName).Delete
End If
'Create New Contents Sheet
Worksheets.Add Before:=Worksheets(1)
'Set variable to Contents Sheet
Set Content_sht = ActiveSheet
'Format Contents Sheet
With Content_sht
.Name = ContentName
.Range("B1") = "Table of Contents"
.Range("B1").Font.Bold = True
End With
'Create Array list with sheet names (excluding Contents)
ReDim myArray(1 To Worksheets.Count - 1)
For Each sht In ActiveWorkbook.Worksheets
If sht.Name <> ContentName Then
myArray(x + 1) = sht.Name
x = x + 1
End If
Next sht
'Alphabetize Sheet Names in Array List
For x = LBound(myArray) To UBound(myArray)
For y = x To UBound(myArray)
If UCase(myArray(y)) < UCase(myArray(x)) Then
shtName1 = myArray(x)
shtName2 = myArray(y)
myArray(x) = shtName2
myArray(y) = shtName1
End If
Next y
Next x
'Create Table of Contents
For x = LBound(myArray) To UBound(myArray)
Set sht = Worksheets(myArray(x))
sht.Activate
With Content_sht
.Hyperlinks.Add .Cells(x + 2, 3), "", _
SubAddress:="'" & sht.Name & "'!A1", _
TextToDisplay:=sht.Name
.Cells(x + 2, 2).Value = x
End With
Next x
Content_sht.Activate
Content_sht.Columns(3).EntireColumn.AutoFit
ExitSub:
'Optimize Code
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
The .Visible property of the worksheet has three options:
As you can probably imagine, 0 is converted to False, and 1 or 2 to True. This causes errors, if you try to convert .Visible to a Boolean value.
Thus the idea is to loop only through worksheets, that are xlSheetVisible. Checking simply sht.Visible can lead to an error, if the sheet is xlSheetVeryHidden, because xlSheetVeryHidden is evaluated to True:
Public Sub TestMe()
Dim sht As Worksheet
Set sht = Worksheets(1)
sht.Visible = xlSheetVeryHidden
Debug.Print CBool(sht.Visible) 'prints true
End Sub
Thus use:
If sht.Visible = xlSheetVisible and sht.Name <> ContentName
loop only through visible sheets:
If sht.Name <> ContentName And sht.Visible Then

vba lookup value from other workbook and copy corresponding values?

I have two workbooks.
Workbook A
Item number Item description Supplier name
1234 x c
123 y r
1111 b e
Workbook B:
1234
123
1111
When the user types or pastes in an item number in workbook B, the item description and supplier name should be pulled through from workbook A.
This works. But sometimes its a bit temperamental. Sometimes the code works, but then as the user makes changes to the workbook, like when they delete a row in workbook B, this will stop the code from executing for the next time the user types in an item number.
Here's my code:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo Message
On Error Resume Next
ActiveSheet.DisplayPageBreaks = False
'Insert Depot Memo Data for user
Dim oCell As Range, targetCell As Range
Dim ws2 As Worksheet
On Error GoTo Message
If Not Intersect(Target, Range("B:B")) Is Nothing Then ' <-- run this code only if a value in column B has changed
If Not GetWb("Depot Memo", ws2) Then Exit Sub
With ws2
For Each targetCell In Target
Set oCell = .Range("J1", .Cells(.Rows.Count, "J").End(xlUp)).Find(What:=targetCell.Value, LookIn:=xlValues, LookAt:=xlWhole)
If Not oCell Is Nothing Then
Application.EnableEvents = False
'Set Format of cell
targetCell.ClearFormats
targetCell.Font.Name = "Arial"
targetCell.Font.Size = "10"
targetCell.Font.Color = RGB(128, 128, 128)
targetCell.HorizontalAlignment = xlCenter
targetCell.VerticalAlignment = xlCenter
targetCell.Borders(xlEdgeBottom).LineStyle = xlContinuous
targetCell.Borders(xlEdgeTop).LineStyle = xlContinuous
targetCell.Borders.Color = RGB(166, 166, 166)
targetCell.Borders.Weight = xlThin
targetCell.Offset(0, -1).Value = Now()
targetCell.Offset(0, 1).Value = oCell.Offset(0, 1)
targetCell.Offset(0, 2).Value = oCell.Offset(0, -2)
targetCell.Offset(0, 3).Value = oCell.Offset(0, -7)
Application.EnableEvents = True
End If
Next
End With
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
Message:
Application.DisplayAlerts = False
Exit Sub
End Sub
'=================================================================
Function GetWb(wbNameLike As String, WS As Worksheet) As Boolean
Dim Wb As Workbook
For Each Wb In Workbooks
If Wb.Name Like "*" & wbNameLike & "*" Then '<-- check if workbook name contains "Depot Memo"
Set WS = Wb.Worksheets(1)
Exit For
End If
Next
GetWb = Not WS Is Nothing
End Function
Please can someone show me where i am going wrong?

VBA: Copy cell from all worksheets and paste into column

New in VBA and learning on my own.
The intent for the code below is to copy cell "D5" from every sheet in workbook and then paste all the data in workbook "Data", range D4:D300 (the range is pretty broad so it will have more cell available than cells copied). The problem is that the code below is not working. All the code is doing is coping cell D5 from the first sheet over the range indicated (D4:D300). Basically copying the same value 266 times. Any help is highly appreciated.
If there is a more elegant/efficient way to write this code, please advise.
Sub copycell()
Dim sh As Worksheet
Dim wb As Workbook
Dim DestSh As Worksheet
Dim LastRow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wb = ThisWorkbook
Set DestSh = wb.Sheets("Data")
' Loop through worksheets that start with the name "20"
For Each sh In ActiveWorkbook.Worksheets
' Specify the range to copy the data
sh.Range("D5").Copy
' Paste copied range into "Data" worksheet in Column D
With DestSh.Range("D4:D300")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
Next
End Sub
You don't need to specify an end range -- just 'count' the number of sheets to determine the total # of values you'll need to add to the data tab. Also added in a check to see if you're on the Data worksheet so you don't copy the D5 value from Data again into a row in the same worksheet.
Sub copycell()
Dim sh As Worksheet
Dim wb As Workbook
Dim DestSh As Worksheet
Dim i As Integer
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wb = ThisWorkbook
Set DestSh = wb.Sheets("Data")
' Loop through worksheets that start with the name "20"
i = 4
For Each sh In ActiveWorkbook.Worksheets
If sh.Name = "Data" Then Exit Sub
sh.Range("D5").Copy
With DestSh.Range("d" & i)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
i = i + 1
Next
End Sub
On each pass through your ActiveWorkbook.Worksheets loop, paste into the cell below the last cell in column D unless D4 is blank, in which case paste in D4. I'm assuming column D is completely blank before running the macro but if D3 has something in it you can do away with the .Range("D4") = "" test.
Sub copycell()
Dim sh As Worksheet
Dim wb As Workbook
Dim DestSh As Worksheet
Dim LastRow As Long
On Error GoTo GracefulExit:
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wb = ThisWorkbook
Set DestSh = wb.Sheets("Data")
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> "Data" Then
sh.Range("D5").Copy
' Paste copied range into "Data" worksheet in Column D
' starting at D4
With DestSh
If .Range("D4") = "" Then
With .Range("D4")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
Else
With .Cells(.Cells(.Rows.Count, 4).End(xlUp).Row + 1, 4)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
End If
End With
End If
Application.CutCopyMode = False
Next
GracefulExit:
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
If Err <> 0 Then
MsgBox "An unexpected error no. " & Err & ": " _
& Err.Description & " occured!", vbExclamation
End If
End Sub
if you are more concerned about values, then a more concise code could be the following:
Option Explicit
Sub copycell()
Dim sh As Worksheet
Dim iSh As Long
With ThisWorkbook
ReDim dataArr(1 To .Worksheets.Count - 1)
For Each sh In .Worksheets
If sh.Name <> "Data" Then
iSh = iSh + 1
dataArr(iSh) = sh.Range("D5").Value
End If
Next
.Worksheets("Data").Range("D4").Resize(.Worksheets.Count - 1).Value = Application.Transpose(dataArr)
End With
End Sub
where you first store all sheets D5 cell values into an array and then write them in one shot into Data worksheet

make my macro don't duplicate results

When I run my code more than one time it will duplicate results in sheets. I need to remove the previous data and paste the new data every time I run it.
Sub CreateMonthlySheets()
Dim lastRow, mMonth, tstDate1, tstDate2, shtName, nxtRow
On Error Resume Next
'Turn off ScreenUpdating
Application.ScreenUpdating = False
'Make a copy of the data sheet and sort by date
Sheets("Main Data Sheet").Copy After:=Sheets(1)
Sheets(2).Name = "SortTemp"
With Sheets("SortTemp")
lastRow = .Cells(Rows.Count, 1).End(xlUp).Row
Rows("2:" & lastRow).Sort Key1:=Range("C2"), Order1:=xlAscending
'Using SortTemp Sheet, create monthly sheets by
'testing Month and Year values in Column A
'Loop through dates
For Each mMonth In .Range("C2:C" & lastRow)
tstDate1 = Month(mMonth) & Year(mMonth)
tstDate2 = Month(mMonth.Offset(-1, 0)) & Year(mMonth.Offset(-1, 0))
'If Month and Year are different than cell above, create new sheet
If tstDate1 <> tstDate2 Then
ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
'Name the sheet based on the Month and Year
ActiveSheet.Name = MonthName(Month(mMonth)) & " " & Year(mMonth)
'Copy Column Widths and Header Row
.Rows(1).Copy
ActiveSheet.Rows(1).PasteSpecial Paste:=8 'ColumnWidth
ActiveSheet.Rows(1).PasteSpecial 'Data and Formats
End If
Next
On Error GoTo 0
'Loop through dates, copying row to the correct sheet
For Each mMonth In .Range("C2:C" & lastRow)
'Create sheetname variable
shtName = MonthName(Month(mMonth)) & " " & Year(mMonth)
'Determine next empty row in sheet
nxtRow = Sheets(shtName).Cells(Rows.Count, 1).End(xlUp).Row + 1
'Copy Data
.Range(mMonth.Address).EntireRow.Copy Destination:=Sheets(shtName).Cells(nxtRow, 1)
Next
End With
'Delete SortTemp sheet
Application.DisplayAlerts = False
Sheets("SortTemp").Delete
Application.DisplayAlerts = True
'Turn on ScreenUpdating
Application.ScreenUpdating = True
End Sub
Try this
Option Explicit
Sub CreateMonthlySheets()
Dim mMonth As Range
Dim shtName As String
Dim monthSht As Worksheet
Dim newSheet As Boolean
' 'Turn off ScreenUpdating
Application.ScreenUpdating = False
'Make a copy of the data sheet and sort by date
With GetSheet("SortTemp", True, newSheet) '<-- get your "temp" sheet: if not existent then create it
If Not newSheet Then .Cells.Clear '<--| if it existed then clear it
Sheets("Main Data Sheet").UsedRange.Copy Destination:=.Cells(1, 1) '<--| fill it with "Main Data Sheet" sheet
'Using SortTemp Sheet, create monthly sheets by
'testing Month and Year values in Column A
'Loop through dates
For Each mMonth In .Range("C2:C" & .Cells(.Rows.Count, 1).End(xlUp).row)
shtName = MonthName(Month(mMonth)) & " " & Year(mMonth) '<--| build "month" sheet name
Set monthSht = GetSheet(shtName, False, newSheet) 'Set "month" sheet: if not existent then create it
If newSheet Then '<--| if it didn't exist...
'...Copy Column Widths and Header Row
.Rows(1).Copy
monthSht.Rows(1).PasteSpecial Paste:=8 'ColumnWidth
monthSht.Rows(1).PasteSpecial 'Data and Formats
Else 'otherwise...
monthSht.UsedRange.Offset(1).Clear '<--| ...clear it from row 2 downwards (assuming row 1 has at least one value...)
End If
'Copy Data
mMonth.EntireRow.Copy Destination:=monthSht.Cells(monthSht.Rows.Count, 1).End(xlUp).Offset(1)
Next
End With
'Delete SortTemp sheet
Application.DisplayAlerts = False
Sheets("SortTemp").Delete
Application.DisplayAlerts = True
'Turn on ScreenUpdating
Application.ScreenUpdating = True
End Sub
'Sub main()
' Dim sh As Worksheet
' Dim existent As Boolean
'
' Set sh = GetSheet("data1", False, existent)
'
'End Sub
Function GetSheet(shtName As String, Optional okClear As Boolean = False, Optional newSheet As Boolean = False) As Worksheet
On Error Resume Next
Set GetSheet = Worksheets(shtName)
On Error GoTo 0
If GetSheet Is Nothing Then
newSheet = True
Set GetSheet = ActiveWorkbook.Sheets.Add(After:=Worksheets(Worksheets.Count))
GetSheet.Name = shtName
Else
If okClear Then GetSheet.Cells.Clear
newSheet = False
End If
End Function
which results from:
avoid On Error Resume Next ruling for more than strictly needed
no need to loop twice
I Found The Solution>>thanks For all
Option Explicit
Sub CreateMonthlySheets()
Dim mMonth As Range
Dim shtName As String
Dim monthSht As Worksheet
Dim newSheet As Boolean
' 'Turn off ScreenUpdating
Application.ScreenUpdating = False
'Make a copy of the data sheet and sort by date
With GetSheet("SortTemp", True, newSheet) '<-- get your "temp" sheet: if not existent then create it
If Not newSheet Then .Cells.Clear '<--| if it existed then clear it
Sheets("Main Data Sheet").UsedRange.Copy Destination:=.Cells(1, 1) '<--| fill it with "Main Data Sheet" sheet
'Using SortTemp Sheet, create monthly sheets by
'testing Month and Year values in Column A
'Loop through dates
For Each mMonth In .Range("C2:C" & .Cells(.Rows.Count, 1).End(xlUp).Row)
shtName = MonthName(Month(mMonth)) & Year(mMonth) '<--| build "month" sheet name
Set monthSht = GetSheet(shtName, False, newSheet) 'Set "month" sheet: if not existent then create it
monthSht.UsedRange.Offset(1).Clear
Next
For Each mMonth In .Range("C2:C" & .Cells(.Rows.Count, 1).End(xlUp).Row)
shtName = MonthName(Month(mMonth)) & Year(mMonth) '<--| build "month" sheet name
Set monthSht = GetSheet(shtName, False, newSheet) 'Set "month" sheet: if not existent then create it
' monthSht.UsedRange.Offset(1).Clear
' If newSheet Then '<--| if it didn't exist...
'...Copy Column Widths and Header Row
.Rows(1).Copy
monthSht.Rows(1).PasteSpecial Paste:=8 'ColumnWidth
monthSht.Rows(1).PasteSpecial 'Data and Formats
' Else 'otherwise...
'monthSht.UsedRange.Offset(1).Clear '<--| ...clear it from row 2 downwards (assuming row 1 has at least one value...)
' End If
'Copy Data
mMonth.EntireRow.Copy Destination:=monthSht.Cells(monthSht.Rows.Count, 1).End(xlUp).Offset(1)
Next
End With
'Delete SortTemp sheet
Application.DisplayAlerts = False
Sheets("SortTemp").Delete
Application.DisplayAlerts = True
'Turn on ScreenUpdating
Application.ScreenUpdating = True
End Sub
Function GetSheet(shtName As String, Optional okClear As Boolean = False, Optional newSheet As Boolean = False) As Worksheet
On Error Resume Next
Set GetSheet = Worksheets(shtName)
On Error GoTo 0
If GetSheet Is Nothing Then
newSheet = True
Set GetSheet = ActiveWorkbook.Sheets.Add(After:=Worksheets(Worksheets.Count))
GetSheet.Name = shtName
Else
If okClear Then GetSheet.Cells.Clear
newSheet = False
End If
End Function

VBA: Copy entire row with the condition TRUE to TempSheet2

Can someone help me with an VBA script that copy entire rows with the condition TRUE from column U in TempSheet over to TempSheet2.
use something like this:
Sub test()
Dim i&, z&, oCell As Range
Application.ScreenUpdating = 0
z = 1: i = Sheets("TempSheet").Cells(Rows.Count, "U").End(xlUp).Row
For Each oCell In Sheets("TempSheet").Range("U1:U" & i)
If oCell.Value = True Then
oCell.EntireRow.Copy Sheets("TempSheet2").Rows(z)
z = z + 1
End If
Next
Application.ScreenUpdating = 1
End Sub
This macro checks each row for the value "True" in the U column.
The columns with true value in column U as then copied to the other sheet.
Option Explicit
Sub CopyRow()
Dim Row As Integer
Dim sRow As String
Dim i As Long
Application.ScreenUpdating = False
i = 1 'To ensure each time the macro is run it starts at row 1
For i = 1 To 1048576 'for each row in the sheet
If Range("U" & i).Value = True Then 'If the U value is true then copy it
Row = i
sRow = CStr(Row) 'convert row number to string
Rows(sRow & ":" & sRow).Select
Selection.Copy
Sheets("Sheet2").Select
Rows(sRow & ":" & sRow).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
Application.CutCopyMode = False
End If
Next i
Range("A1").Select
Application.ScreenUpdating = True
End Sub
I am uncertain as to how you want the macro triggered but a worksheet change may suit.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
' The variable KeyCells contains the cells that will
' trigger the macro if they are changed
Set KeyCells = Range("U:U")
Call CopyRow
End If
End Sub
Note: Worksheet_Change goes in the code for sheet1 and the macro goes in a module