Trying to use VBA to enter break time in a spreadsheet. 1st Break, Lunch, 2nd Break. I have three sets of code in vba but am only able to get the 1st break code to work other two do not give a result. I have attached the VBA Code. I am new to VBA as you can see.
Private Sub Worksheet_Calculate()
End Sub
Private Sub Worksheet1_Change(ByVal Target As Range)
'Break 1
Dim xCellColumn As Integer
Dim xTimeColumn As Integer
Dim xRow, xCol As Integer
Dim xDPRg, xRg As Range
xCellColumn = 15
xTimeColumn = 6
xRow = Target.Row
xCol = Target.Column
If Target.Text <> "" Then
If xCol = xCellColumn Then
Cells(xRow, xTimeColumn) = Now()
Else
On Error Resume Next
Set xDPRg = Target.Dependents
For Each xRg In xDPRg
If xRg.Column = xCellColumn Then
Cells(xRg.Row, xTimeColumn) = Now()
End If
Next
End If
End If
End Sub
Private Sub Worksheet2_Change(ByVal Target As Range)
'Lunch Break
Dim xCellColumn As Integer
Dim xTimeColumn As Integer
Dim xRow, xCol As Integer
Dim xDPRg, xRg As Range
xCellColumn = 16
xTimeColumn = 8
xRow = Target.Row
xCol = Target.Column
If Target.Text <> "" Then
If xCol = xCellColumn Then
Cells(xRow, xTimeColumn) = Now()
Else
On Error Resume Next
Set xDPRg = Target.Dependents
For Each xRg In xDPRg
If xRg.Column = xCellColumn Then
Cells(xRg.Row, xTimeColumn) = Now()
End If
Next
End If
End If
End Sub
Private Sub Worksheet3_Change(ByVal Target As Range)
'Break 2
Dim xCellColumn As Integer
Dim xTimeColumn As Integer
Dim xRow, xCol As Integer
Dim xDPRg, xRg As Range
xCellColumn = 17
xTimeColumn = 10
xRow = Target.Row
xCol = Target.Column
If Target.Text <> "" Then
If xCol = xCellColumn Then
Cells(xRow, xTimeColumn) = Now()
Else
On Error Resume Next
Set xDPRg = Target.Dependents
For Each xRg In xDPRg
If xRg.Column = xCellColumn Then
Cells(xRg.Row, xTimeColumn) = Now()
End If
Next
End If
End If
End Sub
There are three columns where time is entered, and three columns that a dropdown has the reference to run formula.
Further to #Scott Craner’s advice, you could do a nested IF solution – but with all your currentIF Else End If conditions in your existing code, I think it would become too difficult to maintain. Another possibility is to use a Select Case approach, and the code below uses that instead. I tested it and it seems to give you what you want.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo GetOut
Application.EnableEvents = False
Dim xCellColumn As Integer, xTimeColumn As Integer
Dim xRow As Integer, xCol As Integer
Dim xDPRg As Range, xRg As Range
If Not Intersect(Range("O:Q"), Target) Is Nothing Then
xCellColumn = Target.Column
Select Case xCellColumn
Case Is = 15
xTimeColumn = 6
xRow = Target.Row
xCol = Target.Column
If Target.Text <> "" Then
If xCol = xCellColumn Then
Cells(xRow, xTimeColumn) = Now()
Else
On Error Resume Next
Set xDPRg = Target.Dependents
For Each xRg In xDPRg
If xRg.Column = xCellColumn Then
Cells(xRg.Row, xTimeColumn) = Now()
End If
Next
End If
End If
Case Is = 16
xTimeColumn = 8
xRow = Target.Row
xCol = Target.Column
If Target.Text <> "" Then
If xCol = xCellColumn Then
Cells(xRow, xTimeColumn) = Now()
Else
On Error Resume Next
Set xDPRg = Target.Dependents
For Each xRg In xDPRg
If xRg.Column = xCellColumn Then
Cells(xRg.Row, xTimeColumn) = Now()
End If
Next
End If
End If
Case Is = 17
xTimeColumn = 10
xRow = Target.Row
xCol = Target.Column
If Target.Text <> "" Then
If xCol = xCellColumn Then
Cells(xRow, xTimeColumn) = Now()
Else
On Error Resume Next
Set xDPRg = Target.Dependents
For Each xRg In xDPRg
If xRg.Column = xCellColumn Then
Cells(xRg.Row, xTimeColumn) = Now()
End If
Next
End If
End If
End Select
End If
Continue:
Application.EnableEvents = True
Exit Sub
GetOut:
MsgBox Err.Description
Resume Continue
End Sub
Related
I'm new to vba and frustrated.
I have the following code :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim VolRange As Range
Dim AffectVolRange As Range
Set VolRange = ActiveSheet.Range("AH:AK")
Set AffectVolRange = Intersect(Target, VolRange)
If Not AffectVolRange Is Nothing Then
Dim vRow As Variant
For Each vRow In AffectVolRange.Rows
With VolRange
Cells(vRow.Row, 37).Value = .Cells(vRow.Row, 34).Value * .Cells(vRow.Row, 35).Value *
.Cells(vRow.Row, 36).Value
End With
Next vRow
End If
End Sub
Initial value in columns 34,35,36, is null
You almos got it.
Take into account that your column indexes are relative to your new range, so 1, 2, 3, 4.
Also you need to disable the events with Application.EnableEvents = False to avoid recursive call to the function on the cells changed by the code event.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim VolRange As Range
Dim AffectVolRange As Range
Set VolRange = ActiveSheet.Range("AH:AK")
Set AffectVolRange = Intersect(Target, VolRange)
If Not AffectVolRange Is Nothing Then
Dim vRow As Variant
Application.EnableEvents = False
For Each vRow In AffectVolRange.Rows
With VolRange
.Cells(vRow.Row, 4).Value = .Cells(vRow.Row, 1).Value _
* .Cells(vRow.Row, 2).Value _
* .Cells(vRow.Row, 3).Value
End With
Next vRow
Application.EnableEvents = True
End If
End Sub
I am attempting to write a macro that will send an email if a specific range is selected and meets certain criteria. I have several email subs that will be called depending upon which range is selected/activated. I'm trying to use the Intersect(Range, Target) method to restrict which range will call which email sub. The problem I'm having is that my code always defaults to the first range in the sheet, but I need it to just use the active range. I've included a sample of my code below.
Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Target.Cells.Count > 1 Then Exit Sub
'Checklist Setup Review
Dim LastRow As Long
Dim i As Long
Dim xRg As Range
Dim x As String
Dim NewRng As Range
LastRow = Cells(Rows.Count, "H").End(xlUp).Row
For i = 1 To LastRow
If UCase(Cells(i, "H").Value) = "P" Then
If NewRng Is Nothing Then
Set NewRng = Cells(i, "A")
Else
Set NewRng = Union(NewRng, Cells(i, "A"))
End If
End If
Next i
'Initial Lidar Review
Dim LastRow1 As Long
Dim e As Long
Dim NewRng1 As Range
LastRow1 = Cells(Rows.Count, "I").End(xlUp).Row
For e = 1 To LastRow1
If UCase(Cells(e, "I").Value) = "P" Then
If NewRng1 Is Nothing Then
Set NewRng1 = Cells(e, "A")
Else
Set NewRng1 = Union(NewRng1, Cells(e, "A"))
End If
End If
Next e
'Initial Ground Macro Review
Dim LastRow2 As Long
Dim xRg2 As Range
Dim j As Long
Dim NewRng2 As Range
LastRow2 = Cells(Rows.Count, "J").End(xlUp).Row
For j = 1 To LastRow2
If UCase(Cells(j, "J").Value) = "P" Then
If NewRng2 Is Nothing Then
Set NewRng2 = Cells(j, "A")
Else
Set NewRng2 = Union(NewRng2, Cells(j, "A"))
End If
End If
Next j
'Call Email subs
If xRg Is Nothing Then
Set xRg = Intersect(NewRng, Target)
x = True
For Each r In NewRng
If r.Value <> "Pass" And r.Value <> "Complete" Then
x = False
End If
Next r
If x = True Then
MsgBox "Project Setup Review Complete: Auto Email Sent."
Call SetupReview_Email
End If
ElseIf xRg Is Nothing Then
Set xRg = Intersect(NewRng1, Target)
If xRg Is Nothing Then Exit Sub
x = True
For Each r In NewRng1
If r.Value <> "Pass" And r.Value <> "Complete" Then
x = False
End If
Next r
If x = True Then
MsgBox "Intial Lidar Review Completed: Auto Email Sent."
InitialLidarReview_Email
End If
ElseIf xRg Is Nothing Then
Set xRg = Intersect(NewRng2, Target)
For Each r In NewRng2
If r.Value <> "Pass" And r.Value <> "Complete" Then
x = False
End If
Next r
If x = True Then
MsgBox "Ground Macro Review Completed: Auto Email Sent."
Call GroundMacro_Email
End If
End If
End Sub
Doing this slightly rushed but hopefully you get the gist. Should the If statements actually be checking if the Intersect is NOT Nothing?
Set xRg = Intersect(NewRng, Target)
If xRg Is Nothing Then
'stuff
Else
Set xRg = Intersect(NewRng1, Target)
If xRg Is Nothing Then
'stuff
Else
Set xRg = Intersect(NewRng2, Target)
If xRg Is Nothing Then
'stuff
End If
End If
End If
I am not used to writing code. I normally generate my code via macro and I am facing this issue. Can someone please help me?
Sub Test()
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("B8:B38"), Target)
xOffsetColumn = 19
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
Dim WorkRng1 As Range
Dim Rng1 As Range
Dim xOffsetColumn1 As Integer
Set WorkRng1 = Intersect(Application.ActiveSheet.Range("C8:C38"), Target)
xOffsetColumn1 = 18
If Not WorkRng1 Is Nothing Then
For Each Rng1 In WorkRng1
If Not VBA.IsEmpty(Rng1.Value) Then
Rng1.Offset(0, xOffsetColumn1).Value = Now
Rng1.Offset(0, xOffsetColumn1).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng1.Offset(0, xOffsetColumn1).ClearContents
End If
Next
Application.EnableEvents = True
End If
....................................
..............................
Dim WorkRng132 As Range
Dim Rng132 As Range
Dim xOffsetColumn132 As Integer
Set WorkRng132 = Intersect(Application.ActiveSheet.Range("EJ8:EJ38"), Target)
xOffsetColumn132 = 1
If Not WorkRng132 Is Nothing Then
For Each Rng132 In WorkRng132
If Not VBA.IsEmpty(Rng132.Value) Then
Rng132.Offset(0, xOffsetColumn132).Value = Now
Rng132.Offset(0, xOffsetColumn132).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng132.Offset(0, xOffsetColumn132).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
One useful maxim in programming is Don't Repeat Yourself (DRY) - duplicated code is longer, harder to understand, and difficult to maintain.
There's a clear repeating pattern in your code. This block:
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("B8:B38"), Target)
xOffsetColumn = 19
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
Can be refactored into a re-usable method with two parameters:
Sub Test()
'....
ProcessRange Application.Intersect(Me.Range("B8:B38"), Target), 19
ProcessRange Application.Intersect(Me.Range("C8:C38"), Target), 18
'etc for the other ranges
'....
End sub
'subprocedure
Sub ProcessRange(WorkRng As Range, offsetCol as Long)
Dim Rng As Range
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
With Rng.Offset(0, offsetCol)
If Not VBA.IsEmpty(Rng.Value) Then
.Value = Now
.NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
.ClearContents
End If
End With
Next
Application.EnableEvents = True
End If
End Sub
I am using the spreadsheet to do inventory- scanning parts in bin
I am trying to add a A2 Value next to the (Target.Row, 5)(row 6)
how do I make A2 or A9 or the next scan Value show up on Column F so if column E & F don't match I know the part is sitting on the wrong bin
I have tried .Value = Target.Worksheet.Cells(Target.Row, 1).Value but not working
Here is my complete code
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Target.Cells.Count > 1 Or IsEmpty(Target) Or Target.Column <> 1 Then Exit Sub
If Not SheetExists("WarehouseInventory") Then Exit Sub
Dim Result As Variant
Set Result = Sheets("WarehouseInventory").Cells.Range("E:E").Find(Target)
If Result Is Nothing Then
Target.Worksheet.Cells(Target.Row, 2) = "Data New Bin"
Else
Target.Worksheet.Cells(Target.Row, 2) = Result.Worksheet.Cells(Result.Row, 4)
Target.Worksheet.Cells(Target.Row, 3) = Result.Worksheet.Cells(Result.Row, 5)
Target.Worksheet.Cells(Target.Row, 4) = Result.Worksheet.Cells(Result.Row, 6)
Target.Worksheet.Cells(Target.Row, 5) = Result.Worksheet.Cells(Result.Row, 7)
End If
End Sub
Public Function SheetExists(SheetName As String) As Boolean
Dim ws As Worksheet
SheetExists = False
For Each ws In ThisWorkbook.Worksheets
If ws.Name = SheetName Then SheetExists = True
Next ws
End Function
this an example how you can achieve required result
Private Sub Worksheet_Change(ByVal Target As Range)
Dim x&, y&
If Target.Column = 6 Then
y = 5: x = Target.Row
While Cells(x, y) <> "": x = x - 1: Wend
If Cells(Target.Row, 5) <> "" Then Cells(Target.Row, 6) = Cells(x, 1)
End If
End Sub
output
UPDATE
here your updated code, tested, works fine, insert it into "Cycle Count" sheet
Private Sub Worksheet_Change(ByVal Target As Range)
Dim x&, y&, Result As Range, ws As Worksheet
Application.EnableEvents = 0
If Target.Count > 1 Then
Application.EnableEvents = 1
Exit Sub
End If
If Not Intersect(Target, [A1:A99999]) Is Nothing Then
With ThisWorkbook
For Each ws In .Worksheets
If ws.Name = "WarehouseInventory" Then
Set ws = .Worksheets("WarehouseInventory")
Set Result = ws.[E:E].Find(Target.Value)
Exit For
End If
Next ws
If Result Is Nothing Then
Target.Offset(, 1).Value = "Data New Bin"
Application.EnableEvents = 1
Exit Sub
Else
Target.Offset(, 1).Value = ws.Range(Result.Address).Offset(, -1).Value
Target.Offset(, 2).Value = ws.Range(Result.Address).Value
Target.Offset(, 3).Value = ws.Range(Result.Address).Offset(, 1).Value
Target.Offset(, 4).Value = ws.Range(Result.Address).Offset(, 2).Value
y = 5: x = Target.Row
While .ActiveSheet.Cells(x, y) <> "": x = x - 1: Wend
Target.Offset(, 5).Value = .ActiveSheet.Cells(x, 1).Value
End If
End With
End If
Application.EnableEvents = 1
End Sub
sample file here http://www.filedropper.com/book1_5
What about Target.Worksheet.Cells(Target.Row, 6).Value = Target.Worksheet.Cells(Target.Row,1).Value ?
If you want only A2, in all rows substitute Target.Row with 2
My codes gives me a Object Required 424 error on this line:
lngRow = .Cells(.Rows.Count, 1).End(xlUp).Row
My full code:
Private Sub Worksheet_Change(ByVal Target As Range)
' If Target.Count > 1 Then Exit Sub
' If Target.Column > 2 Then Exit Sub
Application.EnableEvents = False
If Target.Column = 6 Then
If Target.Offset(0, 1).Value <> "" Then
MsgBox "You must only fill in one of the two columns"
Target.ClearContents
GoTo ExitSub
End If
End If
If Target.Column = 7 Then
If Target.Offset(0, -1).Value <> "" Then
MsgBox "You must only fill in one of the two columns"
Target.ClearContents
GoTo ExitSub
End If
End If
Dim arrData() As Variant
Dim i As Long
Dim lngRow As Long
Dim myNum As Variant
Dim ws As Worksheet
myNum = Target.Value
If Target.Column = 6 Then
With BogieInspectionPoints 'this is a sheet name
lngRow = .Cells(.Rows.Count, 1).End(xlUp).Row
arrData = .Range("a1:b" & lngRow)
End With
End If
If Target.Column = 7 Then
With WagonInspectionPoints 'this is a sheet name
lngRow = .Cells(.Rows.Count, 1).End(xlUp).Row
arrData = .Range("a1:b" & lngRow)
End With
End If
For i = 1 To lngRow
If myNum = arrData(i, 1) Then
Cells(Target.Row, 8).Value = arrData(i, 2)
Exit For
End If
Next
ExitSub:
Application.EnableEvents = True
End Sub
It looks like those sheet variables aren't set.
You will need to add this at the top.
Dim BogieInspectionPoints as Worksheet
Dim WagonInspectionPoints as Worksheet
Set BogieInspectionPoints = ActiveWorkbook.Sheets("BogieInspectionPoints")
Set WagonInspectionPoints = ActiveWorkbook.Sheets("WagonInspectionPoints")
I was assuming there was other code. When you add this line all the With statements should process correctly using the code you posted.
What you're doing with the With statements is shorthanding the object. Instead of writing
BogieInspectionPoints.Range("A1")
'More code
You can write
With BogieInspectionPoints
.Range("A1")
End With
It keeps you from having to write the full object name out.