I have a cell that states the status of a project, and this status will change frequently.
Whenever the status gets changed, I would like a row to state the time the status was changed and the name of the new status.
I have next to no experience with VBA, so any assistance would be greatly appreciated. So far I have this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 4 And Target.Row = 4 Then
Target.Offset(10, 3) = Format(Now(), "YYYY-MM-DD HH:MM:SS")
End If
End Sub
This code successfully lists the time in cell G7 whenever the status contained in cell D4 changes, but it always repopulates the same cell, I would like each successive status change to list the date stamp in cell G8, then G9, then G10, and so on.
It also doesn't list what the status cell D4 is changed too, ideally I would like that to be listed in F7, then F8, then F9, and so on.
If you are only interested in a Worksheet_Change on cell D4, you can use the Intersect method shown below
To start a running list, you will need to determine that last used cell in Column G and offset accordingly
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D4")) Is Nothing Then
Dim LR As Long: LR = Range("G" & Rows.Count).End(xlUp).Offset(1).Row
Target.Offset(LR - Target.Row, 3) = Format(Now(), "YYYY-MM-DD HH:MM:SS")
Target.Offset(LR - Target.Row, 4) = Target
End If
End Sub
Please try this.
Private Sub Worksheet_Change(ByVal Target As Range)
Const Tgt As String = "D4" ' monitored cell
Const FirstRecord As Long = 7 ' change as required
Const Fmt As String = "yyyy-mm-dd hh:mm:ss"
Dim Rl As Long ' last used row
If Target.Address = Range(Tgt).Address Then
Application.EnableEvents = False
Rl = Application.WorksheetFunction.Max( _
Cells(Rows.Count, "F").End(xlUp).Row + 1, FirstRecord)
With Cells(Rl, "G")
.Value = Now()
.NumberFormat = Fmt
Target.Copy Destination:=.Offset(0, -1)
End With
Application.EnableEvents = True
End If
End Sub
Related
I'm trying to record the value that changes every one minute from cell "B2" into cell "D2". When the values are recorded to "D2" in a row, I want to add the date and time at the same time it recorded into cell "E". Here, below is my code.
Private Sub Worksheet_Calculate()
Application.EnableEvents = False
Me.Range("D" & Me.Rows.Count).End(xlUp).Offset(1).Value = Me.Range("B2").Value
Application.EnableEvents = True
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim targetRng As Range
Dim rng As Range
Dim c As Integer
Set targetRng = Intersect(Application.ActiveSheet.Range("D:C"), Target)
c = 1
If Not targetRng Is Nothing Then
Application.EnableEvents = False
For Each rng In targetRng
If Not VBA.IsEmpty(rng.Value) Then
rng.Offset(0, c).Value = Now
rng.Offset(0, c).NumberFormat = "dd/mm/yyyy, hh:mm:ss AM/PM"
Else
rng.Offset(0, c).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
It seems that every time the value has recorded, the date and time in cell "E" do not appear to work together.
Any solution here?
I recommend creating a seperate Sub that is not directly hit by an event. Rewrite code below for your purposes.
Private Sub Worksheet_Calculate()
SharedSheetEvent()
end sub
Private Sub Worksheet_Change(ByVal Target As Range)
EditingSheet = true
call SharedSheetEvent()
editingsheet = false
end sub
global EditingSheet as bool
public Sub SharedSheetEvent()
if (EditingSheet) Then
do some stuff
else
do some other stuff
end if
end sub
The code below will do what you want. No two procedures are needed but if you don't specify the sheet, meaning you let it work on the ActiveSheet, it would be a bit of a lose cannon.
Private Sub Worksheet_Calculate()
Dim LastRecord As Range ' cell last written to
Dim NewValue As Variant ' current value in B2
Debug.Print "calculate"
With Worksheets("Sheet1") ' change to suit
Set LastRecord = .Cells(.Rows.Count, "D").End(xlUp)
NewValue = .Cells(2, "B").Value
With LastRecord
If .Value <> NewValue Then ' skip if no change
Application.EnableEvents = False
.Offset(1).Value = NewValue
With .Offset(1, 1)
.Value = Now()
.NumberFormat = "dd/mm/yyyy, hh:mm:ss AM/PM"
End With
Application.EnableEvents = True
End If
End With
End With
End Sub
The question is not, however, how the code works but when. I presume that B2 is changed by a program that works on a timer. The change generated by it doesn't trigger the Worksheet's Change event. You did find out, however, that it triggers the Calculate event. That is my presumption and I couldn't test it. If that is so my procedure will solve your problem.
I have programmed a similar thing recently using a timer of my own to trigger running my procedure. It's just a timer that runs at the same interval as the other and checks every minute (for example) if B2 has changed and records the change if there was one. That works. But if your updater triggers the Calculate event that looks like a neater idea.
I have a large workbook and am trying to increase performance.
Is it possible/viable to store my formulas in some sort of list contained within the code rather than in the cells on the spreadsheet?
Variable SelectedRow = the currently selected row
For example:
ColumnBFormula = A(SelectedRow) + 1
ColumnCFormula = A(SelectedRow) + 2
If the user enters 4 in cell A3, then the macro writes formulas above ONLY in empty cells B3 and C3, then converts to values. The rest of the spreadsheet remains unchanged (should only have values everywhere).
Then the user enters a 6 in cell A4 and the spreadsheet writes the formulas to empty cells B4 and C4, calculates then converts to values.
Thanks
Try:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Lastrow As Long
'Refer to Sheet1
With ThisWorkbook.Worksheets("Sheet1")
'Check if Column A affected
If Not Intersect(Target, Range("A:A")) Is Nothing And IsNumeric(Target) Then
'Disable event to avoid event trigger
Application.EnableEvents = False
Target.Offset(0, 1).Value = Target + 1
Target.Offset(0, 2).Value = Target + 2
'Enable event
Application.EnableEvents = True
End If
End With
End Sub
Instructions:
Enable Events:
Given you know what you want the code to do, you could do this without entering formulas.
In the VBA editor, add this code into the "ThisWorkbook" object ...
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim objCell As Range
Application.EnableEvents = False
For Each objCell In Target.Cells
If objCell.Column = 1 Then
If objCell.Value = "" Then
objCell.Offset(0, 1) = ""
objCell.Offset(0, 2) = ""
Else
objCell.Offset(0, 1) = objCell.Value + 1
objCell.Offset(0, 2) = objCell.Value + 2
End If
End If
Next
Application.EnableEvents = True
End Sub
Hopefully that works for you.
FYI - You'll need to add the relevant error checking for values if not numeric etc, it will need to be improved.
I am looking to parse an entire row in a particular excel sheet for any change in data in that row. If there is any change in data in that row then i want to add the date in which that particular cell of that row. I want to pass the row as an input. I tried the following code but it doesnt work.
Private Function User_func1(ByVal i As Long)
Dim j As Long
For j = 1 To j = 100
If Cells(i, j).Value > 1 Then
Cells(i, 2) = Now()
End If
Next j
End Function
You can use the Worksheet_Change event in the sheet you want to scan.
Option Explicit
Const RowtoTest = 2
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Row = RowtoTest Then
Target.Value = Date
End If
Application.EnableEvents = True
End Sub
Option 2: Get the row to test from a certain cell, lets say Cell "A1" (value is set to 2, means look for changes in cells in row 2).
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
' compare the row number to the number inputted as the row to test in cell A1
If Target.Row = Range("A1").Value Then
Target.Value = Date
End If
Application.EnableEvents = True
End Sub
I need to create a timestamp log of changes to a cell. For example if cell D1's value changes from previous value Column A will log the timestamp.
private sub worksheet_change(ByVal Target as Range)
if Range("d1") then
applicaton.enableevents = false
range("a1") = DATE + Time
applicaton.enableevents = true
end if
End sub
This is what I have so far, this logs the changes to D1 but it doesn't populate the next row of column A with a timestamp, it just modifies cell A1 with the current timestamp. I need to track the changes with a new entry of timestamp. I need it to populate the entire column A with timestamp every time there is a change to cell D1.
A solution:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$D$1" Then
Application.EnableEvents = False
Dim LastRow As Long, ws As Worksheet
Set ws = Target.Worksheet
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
ws.Range(ws.Cells(LastRow + 1, 1), ws.Cells(LastRow + 1, 1)).Value = DateValue(Now()) & ", " & TimeValue(Now())
Application.EnableEvents = True
End If
End Sub
Notes:
It is important to fully qualify ranges.
Finding the last row might be tricky in some cases. See this. I assume you do not have one such case.
That's already a good start point. Now you need only to make sure the modification time is appended at the end of the last log registered in column A. I think replacing this line:
range("a1") = DATE + Time
with this line
Cells(Rows.Count, 1).End(xlUp).offset(1,0) = "D1 Modified on " & DateSerial(Year(Now()),Month(Now()),Day(Now())) & " at " & TimeSerial(Hour(Now()), Minute(Now()), Second(Now()))
should do the trick for what you want.
I am currently trying to add a script into excel. excuse my terminology, I am not that hot with programming!
I do all of my accounting on excel 2003, and I would like to be able to add the value of say cells f6 to f27 to the cells e6 to e27, respectively. The thing is, I want the value of the "f" column to reset every time.
So far I have found this code, which works if I copy and paste it into VBA. but it only allows me to use it on one row:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Address = Range("f7").Address Then
Range("e7") = Range("e7") + Range("f7")
Range("f7").ClearContents
End If
Application.EnableEvents = True
End Sub
would somebody be kind enough to explain how I can edit this to do the same through all of my desired cells? I have tried adding Range("f7",[f8],[f9] etc.. but i am really beyond my knowledge.
First, you need to define the range which is supposed to be "caught"; that is, define the range you want to track for changes. I found an example here. Then, simply add the values to the other cell:
Private Sub Worksheet_Change(ByVal Target as Range)
Dim r as Range ' The range you'll track for changes
Set r = Range("F2:F27")
' If the changed cell is not in the tracked range, then exit the procedure
' (in other words, if the intersection between target and r is empty)
If Intersect(Target, r) Is Nothing Then
Exit Sub
Else
' Now, if the changed cell is in the range, then update the required value:
Cells(Target.Row, 5).Value = Cells(Target.Row, 5).Value + Target.Value
' ----------------^
' Column 5 =
' column "E"
' Clear the changed cell
Target.ClearContents
End if
End Sub
Hope this helps
Try this
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ErrHandler
Application.ScreenUpdating = False
Application.EnableEvents = False
If Intersect(Target, Range("B1:B5,F6:F27")) Then 'U can define any other range
Target.Offset(0, -1) = Target.Offset(0, -1).Value + Target.Value ' Target.Offset(0,-1) refer to cell one column before the changed cell column.
'OR: Cells(Target.row, 5) = Cells(Target.row, 5).Value + Target.Value ' Where the 5 refer to column E
Target.ClearContents
End If
ErrHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub