Reputation: 247
It's the first time I'm trying some VBA code, so it might be a very noob mistake but I just can't see it, this is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
If InRange(ActiveCell, Range("N4:N33")) Then
If InStr(1, ActiveCell.Text, "EFECTIVO") > 0 Then
If (Not IsEmpty(ActiveCell.Offset(0, -1))) Then
If (ActiveCell.Offset(0, -1).Value > 0) Then
Cancel = True
Call RestaEfectivo
Range("F4").Select
End If
End If
End If
End If
End Sub
Function InRange(Range1 As Range, Range2 As Range) As Boolean
InRange = Not (Application.Intersect(Range1, Range2) Is Nothing)
End Function
Sub RestaEfectivo()
Range("F4").Value = Range("F4").Value - ActiveCell.Offset(0, -1).Value
End Sub
The idea is that I have a dropdown list on my cells N4 to N33, whenever I choose the option "EFECTIVO" it should take the value to the left of the ActiveCell (N#) and substract its value from the F4 cell. In essence F4 = F4 - N#.
The code does what it's supposed to do, however, it appears to execute 50 times? The original value of my F4 cell is 230, once I execute the code it turns into -20
Any idea where I messed up or if I'm missing some code, validation, etc?
As I said, I'm new to VBA for Excel Macros, so don't worry about pointing out noob mistakes.
Upvotes: 0
Views: 298
Reputation: 19319
You need to toggle the EnableEvents
property of Application
at the point where you call your RestaEfectivo
sub-routine. Notice that during handling the Worksheet_Change
event you call the RestaEfectivo
sub-routine which fires the worksheet change event again - that is why your macro executes more than once.
You can make the code change like this:
Cancel = True
' turn off events to enable changing cell value without a new 'change' event
Application.EnableEvents = False
Call RestaEfectivo
' re-enable events to ensure normal application behaviour
Application.EnableEvents = True
Range("F4").Select
OP asked a follow up question - how to make the range dynamic but ignore the bottom row as this would contain a SUM
formula.
One possible solution is to check for the change in any cell of column N
:
If InRange(ActiveCell, Range("N:N")) Then
And then recode the InRange
sub - see the code comments for logic and assumptions:
Function InRange(Range1 As Range, Range2 As Range) As Boolean
Dim blnInRange As Boolean
Dim blnResult As Boolean
Dim blnCellHasSumFormula As Boolean
Dim blnCellIsEmpty As Boolean
'primary check for cell intersect
blnInRange = Not (Application.Intersect(Range1, Range2) Is Nothing)
If blnInRange Then
'follow-up checks
blnCellIsEmpty = (Range1.Value = vbNullString)
If blnCellIsEmpty Then
'cell in range but empty - assume beneath row with SUM
blnResult = False
Else
If Range1.HasFormula Then
'check for sum formula
blnCellHasSumFormula = (InStr(1, Range1.Formula, "SUM(", vbTextCompare) > 0)
If blnCellHasSumFormula Then
' cell in the SUM row
blnResult = False
Else
' cell is in range, not empty and not a SUM formula
blnResult = True
End If
Else
'assume non-empty cell without formula is good
blnResult = True
End If
End If
Else
blnResult = False
End If
'return to event handler
InRange = blnResult
End Function
Upvotes: 1