i am self taught with VBA and still have a very basic Knowledge but learning Quickly
I Have 3 Sheets in 1 Workbook,
"Purchase Control"
"Material Index Sheet"
"Manufacturing"
This Works Manually but this isnt good as these documents are constantly updated, Column 'P' hold Test Certificates which are acquired later, with this i need the rows to copy to the "Material Index Sheet" and "Manufacturing", if the test Cert is changed it also updates on the next sheets.
i also need something that adds rows for me, instead of having my data be hardcopied B8:P200 which some of these documents dont have 200 rows.
Sub MaterialProcess Code
Sub MaterialProcess()
'Filter Based on Test Certs being Filled in
ActiveSheet.Range("$B$8:$P$202").AutoFilter Field:=15, Criteria1:="<>"
'Copy all Relevant Cells Based Above
Worksheets("Purchase Control").Range("B9:P200").Copy
Worksheets("Material Index Sheet").Range("$B$9:$P$200").PasteSpecial Paste:=xlPasteValues 'it pastes that row and doesnt affect any other row'
Worksheets("Purchase Control").Range("B9:H200").Copy
Worksheets("Manufacturing").Range("B9:H200").PasteSpecial Paste:=xlPasteValues
Worksheets("Purchase Control").Range("$B$8:$P$8").AutoFilter Field:=15
'New Customer
Range("D3:E3").Select 'Merged Cells'
Selection.Copy
Sheets("Material Index Sheet").Select
Range("D3:E3").Select
ActiveSheet.Paste
Sheets("Manufacturing").Select
Range("D3:E3").Select
ActiveSheet.Paste
'Contract Review
Sheets("Purchase Control").Select
Range("D5:E5").Select 'Merged Cells'
Application.CutCopyMode = False
Selection.Copy
Sheets("Material Index Sheet").Select
Range("D5:E5").Select
ActiveSheet.Paste
Sheets("Manufacturing").Select
Range("D5:E5").Select
ActiveSheet.Paste
'Order Num
Sheets("Purchase Control").Select
Range("G3").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Material Index Sheet").Select
Range("G3").Select
ActiveSheet.Paste
Sheets("Manufacturing").Select
Range("G3").Select
ActiveSheet.Paste
'Working Order
Sheets("Purchase Control").Select
Range("G5").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Material Index Sheet").Select
Range("G5").Select
ActiveSheet.Paste
Sheets("Manufacturing").Select
Range("G5").Select
ActiveSheet.Paste
'Unit
Sheets("Purchase Control").Select
Range("I4").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Material Index Sheet").Select
Range("I4").Select
ActiveSheet.Paste
Sheets("Manufacturing").Select
Range("I4").Select
ActiveSheet.Paste
End Sub
This Private Sub allows us to Track anything that is getting manufactured by colour: Red, Yellow, Green,
I am able to get the Date the cell was doubleclicked To yellow or green, this also forces a comment to be added, any information can be commented for the job.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim MyRange As Range
'(1) Desired Range where it works:
Set MyRange = Range("$I$9:$Q$50")
Cancel = True
'(1) Check if double clicked cell is one where the code should work:
If Not Intersect(Target, MyRange) Is Nothing Then
Custom_ColourChange Target
End If
End Sub
'(2) Changed from default Worksheet_Selection event to Custom Sub:
Private Sub Custom_ColourChange(ByVal Target As Range)
'If the target cell is clear
If Target.Interior.ColorIndex = xlNone Then
'Double Click Turns Red
Target.Interior.ColorIndex = 3
'But if the target cell is already Red
ElseIf Target.Interior.ColorIndex = 3 Then
'Double click Turns Yellow
Target.Interior.ColorIndex = 6
'But if the target cell is already Yellow
ElseIf Target.Interior.ColorIndex = 6 Then
'Then change the background to Green
Target.Interior.ColorIndex = 4
'But if the target cell is already Green
ElseIf Target.Interior.ColorIndex = 4 Then
'Then clear the background color
Target.Interior.ColorIndex = xlNone
End If
End Sub
You can get the last row in a spreadsheet with the following code:
dim wSheet as Worksheet : Set wSheet = ThisWorkbook.Worksheets("SHEETNAME")
dim lastRow : lastRow = wSheet.Cells(wSheet.Rows.Count,"B").End(xlUp).Row
This would allow you to copy only the populated rows with
Worksheets("Purchase Control").Range("B9:P" & lastRow).Copy
You can easily get the date of the double click with a
dateTimeClicked = Now
which can then be pushed into whatever cell/comment/wherever you need
Related
I have a file that consists of 5 data related sheets and an additional master sheet. These master sheet has a functionality that retrieves the data from all sheets into master sheet based on the ID.
The flow of the code for now is:
Range().Select
Application.CutCopyMode = False
Selection.Copy
Sheets("mSheet").Select
ActiveSheet.Paste
It does what I want in a simple way that it only shows the necessary data. What I ideally want is to have link between this data and actual sheet, so that once I retrieve data in the master sheet and perform any edit - this edit is made in the actual corresponding sheet.
Any idea and suggestion is appreciated.
Original partial VBA code:
Sheets("dSheet1").Select
ActiveSheet.ListObjects("Table").Range.AutoFilter Field:=3, Criteria1:=id
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("masterSheet").Select
ActiveSheet.Paste Destination:=Sheets("masterSheet").Range("A8")
The following will copy the contents of your selection, but instead of pasting the value will enter the reference to the cell, so when the cell gets updated, so would the master sheet:
Sub foo()
Range("A1").Select
Sheets("mSheet").Range("A2").Formula = "=" & Selection.Address
End Sub
EDIT
The following will do the opposite of the code above, so it will copy the data, paste it in your master Sheet and then go back to the original copied range and enter the cell reference there so when the master is updated, so is that range:
Sub foo()
Range("A1").Select 'select the range to be copied
Application.CutCopyMode = False
Selection.Copy 'copy it
Sheets("mSheet").Range("A2").PasteSpecial (xlPasteValues) 'paste the value into your master sheet
Range("A1").Formula = "=" & Sheets("mSheet").Range("A2").Address
'go back to your previous selection and enter the formula to reference the specific cell
End Sub
UPDATE
Replace your code with the following, as it does the same but with fewer lines of code an without any Select statement:
Sub foo2()
Sheets("dSheet1").ListObjects("Table").Range.AutoFilter Field:=3, Criteria1:=ID
Sheets("dSheet1").Range("A2:D2").Copy Destination:=Sheets("masterSheet").Range("A8")
'change the range above to copy as many columns as you need
End Sub
Then add the following code behind you Master Sheet to detect changes:
Private Sub Worksheet_Change(ByVal Target As Range)
'place this code behing the masterSheet
LastRow = Sheets("dSheet1").Cells(Sheets("dSheet1").Rows.Count, "A").End(xlUp).Row
'get the last row of dSheet1
If Target.Address = "$A$8" Then 'if A8 changes
For i = 1 To LastRow 'loop through dSheet1 to find the ID
If Sheets("dSheet1").Cells(i, 3) = Range("C8").Value Then 'when ID found
Sheets("dSheet1").Cells(i, 1) = Range("A8").Value 'change relevant cell with new data
End If
Next i
End If
'below do the same as above to change data for other columns, add more to adapt it to be able to make changes to however many columns you are copying over
If Target.Address = "$B$8" Then
For i = 1 To LastRow
If Sheets("dSheet1").Cells(i, 3) = Range("C8").Value Then
Sheets("dSheet1").Cells(i, 2) = Range("B8").Value
End If
Next i
End If
If Target.Address = "$D$8" Then
For i = 1 To LastRow
If Sheets("dSheet1").Cells(i, 3) = Range("C8").Value Then
Sheets("dSheet1").Cells(i, 4) = Range("D8").Value
End If
Next i
End If
End Sub
This assumes that your ID's are unique and you are getting a single row as a result of your autofilter.
How about adding buttons.
CopyID - Copy range from SheetID = B1
After Editing, EditID - will clear range in SheetID = B1, and rewrites everything from mSheet Range from A3 then paste in SheetID = B1
Edit ID code:
Public Sub EditID(ID As String)
Sheets(ID).Select
If Range("A1").Value <> "" Then
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Clear
End If
Sheets("mSheet").Select
If Range("A3").Value <> "" Then
Range("A3").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets(ID).Select
Range("A1").Select
ActiveSheet.Paste
End If
Sheets("msheet").Select
End Sub
I have 2 sheets in my workbook, "Sheet1" and "Data". In Sheet1 I have used a Worksheet_Change macro so that when a change happens in column C:
A timestamp appears in column D
That range will get copied into the "Data" sheet.
Here is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Location As Range
If Target.Column > 3 Or Target.Column < 3 Then Exit Sub
Application.EnableEvents = False
Cells(Target.Row, 4) = Now
Application.EnableEvents = True
Selection.End(xlToLeft).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Sheets("data").Unprotect
Sheets("data").Range("a1").End(xlDown).Offset(1, 0).PasteSpecial _
Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Sheets("data").Protect
Range("a1").Select
End Sub
My problem is that the PasteSpecial is not working more than one time.
The problem was that unprotecting the sheet was clearing the clipboard, meaning there was nothing to paste! Here is adapted code, which I've also changed in a couple of other ways to greatly improve it, see the comments for details.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Location As Range
' Use <> to mean "not equal to"
If Target.Column <> 3 Then Exit Sub
Application.EnableEvents = False
' Fully qualify the cells object
ThisWorkbook.Sheets("Sheet1").Cells(Target.Row, 4).Value = Now
Application.EnableEvents = True
' Avoid using .Select and Selection, the user could have clicked anywhere after the value change
' Use a With block to fully qualify your range objects
With ThisWorkbook.Sheets("data")
.Unprotect
' Copy immediately before paste
Target.EntireRow.Copy
.Range("A1").End(xlDown).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
.Protect
End With
Application.CutCopyMode = False
End Sub
Currently, this just overwrites the same line on the "data" sheet, because the data you're pasting has nothing in column A, so the End(xlDown) in column A returns the same position. You may need to change this to column C, or use
.Cells(Rows.Count,"C").End(xlUp).Offset(1, 0).PasteSpecial
Which is still column dependant but goes up to get the last row. There is a dot . before Cells because that line would be within the With block.
Not sure what is being copied as you have used Selection and that depends upon how you input value in column C, whether by hitting Enter or Ctrl+Enter.
Say if you input a value in B2 and press Enter to submit it, cell B3 will get selected and as per your code a range from row3 will be copied to Data sheet. Whereas if you hit Ctrl+Enter, the selection will remain in B2 so a range from row2 will be copied to data sheet.
But that you can tweak yourself.
See if the tweaked code works for you.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Location As Range
If Target.Column <> 3 Then Exit Sub
Application.ScreenUpdating = False
Application.EnableEvents = False
Cells(Target.Row, 4) = Now
Application.EnableEvents = True
Selection.End(xlToLeft).Select
Range(Selection, Selection.End(xlToRight)).Select
Sheets("data").Unprotect
Selection.Copy
Sheets("Data").Range("A" & Rows.Count).End(3)(2).PasteSpecial xlPasteValues
Sheets("data").Protect
Range("a1").Select
Application.ScreenUpdating = True
End Sub
I am using the code below to time stamp my employees priority list when they change a task to Completed. The code works fine but has to be replicated for each cell that I want to track the changes in.
Ideally, I would like the code to have the exact same functionality but compressed so that I can have it look at a large range, M5:M2500, and if cell M250 is changed to Completed have it look through Y5:Y500 and paste the time stamp in cell Y250.
Hopefully this make sense and thanks for any suggestions!
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$M$5" Then
Call Complete5
End If
If Target.Address = "$M$6" Then
Call Complete6
End If
End Sub
Sub Complete5()
ActiveSheet.Unprotect Password:="unlock"
If InStr(1, Range("$M$5"), "Completed") > 0 Then
Range("$Y$5").Select
ActiveCell.FormulaR1C1 = "=NOW()"
ActiveCell.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Range("$M$5").Select
Else
Range("$Y$5").Select
ActiveCell.ClearContents
Range("$M$5").Select
End If
End Sub
Sub Complete6()
ActiveSheet.Unprotect Password:="unlock"
If InStr(1, Range("$M$6"), "Completed") > 0 Then
Range("$Y$6").Select
ActiveCell.FormulaR1C1 = "=NOW()"
ActiveCell.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Range("$M$6").Select
Else
Range("$Y$6").Select
ActiveCell.ClearContents
Range("$M$6").Select
End If
End Sub
You can do this very cleanly right within the Worksheet_Change event itself. This code will evaluate the row in M that was changed and modify the corresponding row in Y accordingly and will also work if a user marks several rows complete at the same time (Ctrl + Enter). Warning, it will not fire when a user pastes a value into the cell.
Also, pay close attention to how I removed all the .Select and .Activate statements and worked directly with the objects themselves.
Private Sub Worksheet_Change(ByVal Target As Range)
With Me
If Not Intersect(Target, .Range("M5:M2500")) Is Nothing Then
Application.EnableEvents = False
.Unprotect Password:="unlock"
Dim rng As Range, cel As Range
Set rng = Target
For Each cel In rng
If InStr(1, cel, "Completed") Then
'use offset of 12 columns to get to column "Y"
cel.Offset(, 12).Value = Now
Else
cel.Offset(, 12).ClearContents
End If
Next
Application.EnableEvents = True
End If
'.Protect Password:="unlock"
End With
End Sub
I would like to copy the data from 'Sheet1' ($A:$N ; may fluctuate), select the range of the data and paste it in 'Sheet3'.
I also need to copy the data from 'Sheet2' without the first row (same headers as 'Sheet1') and paste it underneath the data of 'Sheet1' that is now in 'Sheet3'.
Sub CopyPaste()
Sheets("PC_VIEWS").Select
Range("A1:Q231").Select
Selection.Copy
Sheets("PC_LTC_VIEWS").Select
Range("A1").Select
ActiveSheet.Paste
Range("A1").Select
Selection.End(xlDown).Select
Range("A232").Select
Sheets("LTC_VIEWS").Select
Range("A1").Select
Application.CutCopyMode = False
Range("A1:M1264").Select
Selection.Copy
Sheets("PC_LTC_VIEWS").Select
ActiveSheet.Paste
End Sub
I am open to other solutions!
This code is enough. Try it.
Public Sub CopyAndPaste()
Dim firstRowCount, secondRowCount As Integer
'Copy from "PC_VIEWS" sheet.
Sheets("PC_VIEWS").Select
'Getting the last row from "PC_VIEWS" sheet.
firstRowCount = Range("A:Q").SpecialCells(xlLastCell).row
Range("A1:Q" & firstRowCount).Select
Selection.Copy
'Paste to "PC_LTC_VIEWS" sheet.
Sheets("PC_LTC_VIEWS").Select
Range("A1").Select
ActiveSheet.Paste
'Reset clipboard
Application.CutCopyMode = False
'Copy from "LTC_VIEWS" sheet.
Sheets("LTC_VIEWS").Select
'Getting the last row from "LTC_VIEWS" sheet.
secondRowCount = Range("A:Q").SpecialCells(xlLastCell).row
Range("A2:Q" & secondRowCount).Select
Selection.Copy
'Paste to "PC_LTC_VIEWS" sheet.
Sheets("PC_LTC_VIEWS").Select
Range("A" & firstRowCount + 1).Select
ActiveSheet.Paste
'Reset clipboard
Application.CutCopyMode = False
End Sub
I would like to loop through column A in Worksheet1 and find the first cell which has a specified text "Oil Production". This cell is the first cell in the array I wish to copy to Worksheet2. This cell and the size of the array will change from time to time, hence the code I have used. I then paste it into cell B7 in Worksheet2 which will never change.
This is my formula. I get the error at line ActiveSheet.Paste
Sub Test()
Application.ScreenUpdating = False
For Each Cell In Sheets("Sheet1").Range("A:A")
If Cell.Value = "Oil Production" Then
ActiveSheet.Cells.Select
Range(ActiveCell, Cells(ActiveCell.End(xlDown).Row, ActiveCell.End(xlToRight).Column)).Select
Selection.Copy
Sheets("Sheet2").Select
Range("B7").Select
ActiveSheet.Paste
End If
Next
End Sub
resize the area:
Sub Test()
Dim MyRowCount As Long, MyColCount As Long
Application.ScreenUpdating = False
For Each Cell In Sheets("Sheet1").Range("A1:A" & Range("A" & Rows.count).end(xlup).row) 'This make it poll the used data rather than the whole column
If Cell.Value = "Oil Production" Then
ActiveSheet.Cells.Select
With Range(ActiveCell, Cells(ActiveCell.End(xlDown).Row, ActiveCell.End(xlToRight).column))
.Copy
MyRowCount = .Rows.Count
MyColCount = .Columns.Count
End With
Sheets("Sheet2").Select
Range("B7").Resize(MyRowCount, MyColCount).PasteSpecial xlPasteAll
'Do you need to flick back to Sheet1 after pasting?
End If
Next
End Sub
Also I took out a bunch of selects for you.
Range("A1").Select
Selection.Paste
can be written as
Range("A1").PasteSpecial XLPasteAll
You can chop out most selects this way, you can see I have also done it with the Range you are copying