I am working with Excel VBA and I have a macro that is fired everytime a specific cell is changed. That macro affects the value and properties of many cells on the worksheet, so I used
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
[...] 'mycode
Application.EnableEvents = True
End Sub
At the beginning and end of the macro. Otherwise whenever I change the cell that fires the macro, the macro changes cell and thus fires itself over and over again.
I would like for the macro to be fired if I manually change a cell (without having to insert a command button that fires the macro or something similar)
Is that possible?
Thanks for the help
Private Sub Worksheet_Change(ByVal Target As Range)
If (Target.Column =4) Then
MsgBox ("mycell changed")
End If
End Sub
This basically says if the column change occurs in Index 4 (D) then msgbox.
if you didn't have the if statement the messgbox would occur anytime a change occurs to any cell in the worksheet.
Related
Is it possible to use the mouse to select a cell whilst a user form is open, then programmatically transfer that cell address into the user form (similar to defining a data source range for a chart)??
For that you will need to do two things:
1 - Show your UserForm as Modeless, to do so:
Sub ShowUserForm()
UserForm1.Show vbModeless
End Sub
2 - In the worksheet code, you will need to add an action under the SelectionChange:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If UserForm1.Visible Then
UserForm1.TextBox1.Text = Target.Address
End If
End Sub
I read a lot of pages saying that, but none of them put the solution if the value change by an "if function" not by hand.
The code I get is that:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("A18:A30")) Is Nothing Then Exit Sub
Application.EnableEvents = False 'to prevent endless loop
On Error GoTo Finalize 'to re-enable the events
MsgBox "You changed THE CELL!"
Finalize:
Application.EnableEvents = True
End Sub
It only works if I change the value by hand.
Thank you in advance.
Another solution; instead of triggering your function every time when your worksheet recalculates, add a function in a module:
Function DetectChange() As Integer
MsgBox "You changed THE CELL!"
DetectChange = 0
End Function
Assuming the outcome of your formula is numeric:(otherwise outcome of function must be a empty string and the "+" must be "&")
Add to your IF-formula at the end ...+Detectchange()
Now there will be a msgbox only when your formula is recalculated
Edit by Darren Bartrup-Cook:
I found this code gave worked when the formula recalculated. It didn't fire if I changed a cell that doesn't affect the cell it's entered to and it didn't fire using Calculate Now or Calculate Sheet.
It did occasionally fire for all formula that I used the function in, but that seemed to be when I was debugging - maybe further investigation needed.
Public Function DetectChange()
MsgBox "You changed cell " & Application.Caller.Address
End Function
e.g.:
=IF(A1=1,A2,A3) & DetectChange() entered in cell A4 displays the message "You changed cell $A$4" if cells A1, A2 or A3 is changed.
Write this in Sheet1 and run the TestMe sub:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("A1:A30")) Is Nothing Then Exit Sub
Application.EnableEvents = False
On Error GoTo Finalize
MsgBox "You changed THE CELL!"
Finalize:
Application.EnableEvents = True
End Sub
Sub TestMe()
Range("A1") = 34
End Sub
It has worked quite ok on my PC.
If the cell is changed by a built-in Excel function, then the comment of #Vincent G states the correct answer:
Worksheet_Change event occurs when cells on the worksheet are changed by the user or by an external link. and This event does not occur when cells change during a recalculation. Use the Calculate event to trap a sheet recalculation.
If you want to track the calclulation event based on some changes at Range(A18:A30) this is a working solution:
Add a new Worksheet to your Workbook (Sheet2);
In the current Worksheet write the Calculate event:
Private Sub Worksheet_Calculate()
Dim cell As Range
For Each cell In Sheet2.Range("A18:A30")
If cell <> Sheet1.Range(cell.Address) Then
cell = Sheet1.Range(cell.Address)
End If
Next cell
End Sub
In the Sheet2 write an event, catching the changes.
As simple as #Vincent G says.
Private Sub Worksheet_Calculate()
Call YourFunction
End Sub
I want to clear the selection on sheet "sheet2" when leaving the sheet. (e.g reset to cell A1)
I tried:
Private Sub Worksheet_Deactivate()
ActiveSheet.Range("A1").Select
End Sub
And:
Private Sub Worksheet_Deactivate()
Sheets("Sheet2").Range("A1").Select
End Sub
But this is not working. (first one selects A1 on the current sheet, and the second one gives an error)
The reason why I want this, is because a macro has selected an object (Shape form control) that is protected (locked text). When a user leaves and returns to the sheet, while this object is still selected an error occurs:
You cannot use this command on a protected sheet. To use this command... etc
The reason why a macro selected the object in the first place, is because the user clicked on a hyperlink that would highlight this object. (I can't think of a different way then 'select' to highlight a shape form control)
Possible solution:
The only other method I can think of is have a Sub "Worksheet_Deactivate()" that first activates sheet "Sheet2" clears the selection to A1 and then returns to the sheet the user has initially clicked on when leaving the sheet..... but this feels cumbersome.
Is there another solution/method? any help is appreciated!
This will work so long as you are not working in a shared workbook:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name = "Sheet2" Then Sh.Protect
End Sub
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
If Sh.Name = "Sheet2" Then Sh.Unprotect
End Sub
Cheers!
Based on this answer, you can use the Workbook_SheetDeactivate event and get a WorkSheet object that you can then change the selection on without switching the active sheet.
Further reading seems to indicate Me will contain the sheet that has just been deactivated in the Worksheet_Deactivate handler, so you could also use that.
I have a very simple Worksheet_Change event running so that if any cell on the worksheet changes a cell on another sheet changes to 1. I am using that cell as a flag to know if any changes have been made to the worksheet. I have a shape that I assigned a macro to when selected. The macro checks to see if any changes have been made (if that cell is set to 1), and if it is my code fires.
The problem is if for example
cell A1 contains the name Bob.
A user selects cell A1 and changes the name from Bob to Steve
but then instead of first clicking out of the cell and then clicking the shape they directly hit the shape without deselecting the cell.
The problem with this is that the worksheet_change event doesn't trigger until after my macro completes. So while the macro runs the flag is set to 0, but once it's done the flag gets set to 1.
Any ideas on how to stop this?
Private Sub Worksheet_Change(ByVal Target As Range)
sheets("Cond For").Range("A1").Value = 1
End Sub
Sub saveData()
if sheets("Cond For").Range("A1").Value = 1 Then
'my code
End if
End Sub
Use two routines like so (rename Sheet1.Reallysave to your sheet's codename and routine name):
Sub SaveData()
Application.Ontime Now, "Sheet1.ReallySave"
End Sub
Sub ReallySave()
'Your current code
End Sub
Is there an object and/or function that can detect or represent a general change on a worksheet? Something similar to (for example) ComboBox1_Change() but could be applied to a whole worksheet. Almost something like Worksheet1_Change(). Any suggestions are welcome. Thanks.
The simplest would be to use the worksheet change event:
Private Sub Worksheet_Change(ByVal Target As Range)
MsgBox "Change Detected!"
End Sub
There are instances will this will throw you in to an infinite loop. Consider this code:
Private Sub Worksheet_Change(ByVal Target As Range)
Range("A1").Value = "Change"
End Sub
Set a breakpoint on the Range("A1") code and make a change somewhere else on the sheet and count how many time that breakpoint gets hit. When you get tired of hitting F5, stop the code and try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Range("A1").Value = "Change"
Application.EnableEvents = True
End Sub
You'll see that the code only fires once. Which is probably what you're after.
It's very important that you have the Application.EnableEvents = True line in there, or else you'll get the appearance that your code isn't working (by default EnableEvents does not revert back to True at the end of the code).