How to exit Macro - excel

Here is the code I have. I am reading from one sheet and searching for that term on another sheet. If the search finds the match, it will copy that whole row and paste it onto the first sheet. The search, copy, and paste work. I do not recieve an error but it is as if the macro does not stop because Excel won't let me click out of the original cell the macro read. Am I missing a line of code that should end the macro? Ideally, it should just end the macro after the paste.
I went off the code from another thread:
How to Paste copied Row from one Sheet to Another
Sub Ref()
Dim rng1 As Range
Dim rng2 As Range
If Range("A11") = "SELECT" Then
Else
Set rng1 = Worksheets("MAIN").Range("A11")
For Each rng2 In Worksheets("REF").Range("A11:A2000")
If rng1 = rng2(1).Value Then
rng2.EntireRow.Copy
rng1.EntireRow.PasteSpecial (xlPasteFormulas)
Exit For
End If
Next rng2
End If
End Sub
This is where I call the macro
Private Sub Worksheet_Selection_Change(ByVal Target As Range)
Call Ref
End Sub
Thank you in advance

You need to stop the paste from re-triggering the change event:
...
Application.EnableEvents=False
rng1.EntireRow.PasteSpecial (xlPasteFormulas)
Application.EnableEvents=True
...
EDIT: You should probably be using the worksheet_change event, not selection_change. You can handle the event enabling there instead:
Private Sub Worksheet_Change(ByVal Target As Range)
If not application.intersect(me.range("A11"),Target) is nothing then
Application.EnableEvents=False
Call Ref
Application.EnableEvents=True
End if
End Sub

Related

How to trigger an event by a change to a listobject?

Excel 365.
When the user changes the value of a cell in a certain column of my Excel table (Listobject), I can use the Worksheet_Change event to trigger more code. I would use something like:
If Not Intersect(Target, Listobjects(1).listcolumns(2).DataBodyRange) Is Nothing Then
...to tell that one of these cells was changed. But how do I tell which cell it was?
On a releated note: Is there a way for Worksheet_Change to tell when a new row or column is added to the Listobject?
Sorry in advance if I misunderstood what you asked.
As Target.Address returns its cell location on the sheet, you can translate it to context of listobject by offsetting it with the location of first cell of the table
With me.Listobjects(1)
Debug.Print .DataBodyRange(Target.Row - .Range.Row + 1, _
Target.Column - .Range.column + 1).Address(0,0)
End with
secondly, if you can store the information of the initial table to some variables when opening the workbook, then you can compare the information every time workbook_change event takes place.
P/S: it is quite risky to leave a sheet that already has worksheet event macros in place like this to be unprotected and changed without restriction.
In a Module,
Dim start_LROW&, start_LCOL& 'Variable is declared first
Sub run_when_Open()
With sheet1.ListObjects(1)
start_LROW = .ListRows.Count
start_LCOL = .ListColumns.Count
End With
End Sub
in Workbook_Open event under ThisWorkbook module,
Private Sub Workbook_Open()
Call Module1.run_when_OPEN
End Sub
in Workbook_Change event under Sheet module,
Private Sub Worksheet_Change(ByVal Target As Range)
With Me.ListObjects(1)
If Not Intersect(Target, .DataBodyRange) is Nothing Then
If .ListRows.Count <> start_LROW Or _
.ListColumns.Count <> start_LCOL Then
Debug.Print "changed" 'Trigger some codes
start_LROW = .ListRows.Count 'update the new information to be compared for next trigger.
start_LCOL = .ListColumns.Count
End If
End If
End With
End Sub

Worksheet_FollowHyperlink(ByVal Target As Hyperlink) - Can I have more than one of these subs in a worksheet object?

I am using Excel from MSFT 365. I am an excel expert but a VBA novice.
I created the following code within a worksheet object which essentially moves the workbook to a designated page and filters based on the value in the cell that was clicked initially.
Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
Application.ScreenUpdating = False
Dim i As Long
For i = 3 To 5000
If Target.Range.Address = "$B$" & i Then
Worksheets("Jobs").Range("A2").AutoFilter Field:=2, Criteria1:=Worksheets("Orders").Range("B" & i)
End If
Next i
End Sub
My question is the following. Can I add another similar sub within this same worksheet object using the same action? If I use the same action, I get an ambiguous name error because both subs are named the same (and I don't think I can change the name of the sub).
Or, do I have to incorporate all actions into this single Worksheet_FollowHyperlink sub?
You can use Application.Intersect here - no need to loop
Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
Dim rng As Range
'Is Target in B3:B5000 ?
'in a worksheet code module `Me` refers to the sheet itself
Set rng = Application.Intersect(Target.Range, Me.Range("B3:B5000"))
If Not rng Is Nothing Then 'in range?
Worksheets("Jobs").Range("A2").AutoFilter Field:=2, Criteria1:=rng.Value
End If
'Add other case(s) here....
End Sub

How to fire worksheet_calculate event when data in a specific cell in a different sheet, is changed?

I created a worksheet_calculate event macro to return a message box (CHANGE DETECTED!) whenever the value in the cells W4656:W4657 change. These values are referenced from another sheet in the same workbook.
My problem is the worksheet_calculate event is fired whenever data is entered anywhere in the workbook.
Could this be modified such that the worksheet_calculate event is fired only when data in a specific cell (a cell in a different sheet) is changed.
Private Sub Worksheet_Calculate()
Dim Xrg As Range
Set Xrg = Range("W4656:W4657")
If Not Intersect(Xrg, Range("W4656:W4657")) Is Nothing Then
MsgBox ("CHANGE DETECTED!!")
ActiveWorkbook.Save
End If
End Sub
Well, if we examine these lines of your code
Dim Xrg As Range
Set Xrg = Range("W4656:W4657")
If Not Intersect(Xrg, Range("W4656:W4657")) Is Nothing Then
Since we set Xrg, then immediately use it, we can rewrite that as
If Not Intersect(Range("W4656:W4657"), Range("W4656:W4657")) Is Nothing Then
which will always be true. So, every time the worksheet Calculates, it will say "CHANGE DETECTED!"
Ideally, you want to store the values in those Cells somewhere, and then just run a comparison between the cells and the stored values. Using Worksheet Variables, you could get the following: (You could also store the values in hidden worksheet as an alternative)
Option Explicit 'This line should almost ALWAYS be at the start of your code modules
Private StoredW4656 As Variant 'Worksheet Variable 1
Private StoredW4657 As Variant 'Worksheet Variable 2
Private Sub Worksheet_Calculate()
On Error GoTo SaveVars 'In case the Variables are "dropped"
'If the values haven't changed, do nothing
If (Me.Range("W4656").Value = StoredW4656) And _
(Me.Range("W4657").Value = StoredW4657) Then Exit Sub
MsgBox "CHANGE DETECTED!", vbInformation
SaveVars:
StoredW4656 = Me.Range("W4656").Value
StoredW4657 = Me.Range("W4657").Value
End Sub
So I've managed to find a solution (work around?) to my problem.
I ended up using a macro to check if the the number in Sheet 38, Cell W4656 which was referenced from Sheet 5, Cell J2, has changed. If yes, fire a macro. If not, do nothing.
I've realized that with the code below, worksheet_calculate event is fired only when there is change in Sheet 5, Cell J2 or Sheet 38, Cell W4656 which is what I want.
Private Sub Worksheet_Calculate()
Static OldVal As Variant
If Range("w6").Value <> 24 Then
MsgBox ("XX")
'Call Macro
End If
End Sub
I've updated my code and made it cleaner, and shamelessly stole some of
Chronocidal's approach (my original code required the workbook to be closed and opened to work). So here is what Sheet5 looks like in my example:
And here is Sheet38. In my example I simply setup formulas in Sheet38!W4656:W4657 to equal Sheet5!$J$2 ... so when Sheet5!$J$2 changes so does Sheet38!W4656:W4657 which will trigger the code.
And copy this code into ThisWorkbook ...
Option Explicit
Dim vCheck1 As Variant
Dim vCheck2 As Variant
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If vCheck1 <> Sheet38.Range("W4656") Or vCheck2 <> Sheet38.Range("W4657") Then
MsgBox ("CHANGE DETECTED!!")
Application.DisplayAlerts = False
ActiveWorkbook.Save
Application.DisplayAlerts = True
vCheck1 = Sheet38.Range("W4656")
vCheck2 = Sheet38.Range("W4657")
End If
End Sub
Like this ...

Excel VBA - "for loop" for unconnected cells

My purpose is to run a macro automatically on some 20 cells across my active worksheet whenever these are edited. Instead of having the same macro in place for every cell individually (makes the code very long and clumsy), I want to create a for loop which goes something like this:
for i="A10","A21","C3" ... etc
if target.address = "i" then
'execute macro
end if
I'm not quite sure how to do this... maybe another way would be a better option?
I'd really appreciate your help in the matter - thank you very much indeed.
You can use the Worksheet_Change event. Below is sample code. You need to put the code on the sheet code section
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim rng As Range
Set rng = Range("A1:B5")
' If there is change in this range
If Not Intersect(rng, Target) Is Nothing Then
MsgBox Target.Address & " range is edited"
' you can do manipulation here
End If
Application.EnableEvents = True
End Sub
You can use the Worksheet_Change event to capture the edits. See http://msdn.microsoft.com/en-us/library/office/ff839775.aspx.
The event body receives a Range object that represents the modified cells. You can then use Application.Intersect to determine if one of your target cells is in the modified range.

Excel Worksheet_Change Event not working

I am trying to write a macro where changing any column
should automatically save worksheet.
My Excel sheet expands till G25.
I tried this but its not working:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("G25")) Is Nothing Then
ActiveWorkbook.Save
End Sub
I have save it under ThisWorkBook.
Any help is appreciated.
Under ThisWorkbook that handler is called Workbook_SheetChange and it accepts two arguments, Sh (of type Object) and Target (a Range). So, your code won't work there.
If you put your code in the sheet you want (Sheet1, for instance) instead of in the ThisWorkbook, put the End If and change the range to "A1:G25" (representing a square from row 1 column A to row 25 column 25), it should work.
This did:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("A1:G25")) Is Nothing Then
MsgBox "changed"
End If
End Sub
For completeness, under ThisWorkbook, this will work:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("A1:G25")) Is Nothing Then
MsgBox "changed"
End If
End Sub
The other common reason why an Event doesn't work is that EnableEvents has been set to False
I would code your problem like this as
typically you need to work with the range of interest that is being tested. So creating a variable rng1 below serves both as an early exit point, and a range object to work with. On a sheet event Target.Worksheet.Range("A1:G25") will work but it is lengthy for it's actual use
If you do have a range to manipulate then making any further changes to the sheet will trigger a recalling of the Change event and so on, which can cause Excel to crash. So it is best to disable further Events, run your code, then re-enable Events on exit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Set rng1 = Intersect(Target, Range("A1:G25"))
If rng1 Is Nothing Then Exit Sub
Application.EnableEvents = False
'work with rng1
Application.EnableEvents = True
End Sub

Resources