I'd like to create a macro on Excel to highlight a range of cells when the date in a particular cell changes. The cell draws the date information from Bloomberg (BDP formula), and the workbook refreshes daily.
I've tried this solution:
Private Sub Worksheet_Change(ByVal Target As Range)
(https://www.thespreadsheetguru.com/blog/trigger-your-vba-macros-to-run-based-on-specific-cell-value-change).
However, it only works when the formula in the cell changes, and not when the cell automatically updates the date information when refreshed.
Is there a simple solution to my problem?
If what you want to detect is just one cell, the solution is perhaps easy. Put a Worksheet_Calculate event in the worksheet that contains this cell:
Private Sub Worksheet_Calculate()
Static oldVal As Variant
If Me.Range("A1").Value <> oldVal Then
Me.Range("A2:C4").Interior.ColorIndex = 6
End If
oldVal = Me.Range("A1").Value
End Sub
This supposes you want to detect the change in cell A1 and the range you want to highlight is A2:C4. Adjust these ranges to your need.
Related
Does anyone know how I can add some code to my worksheet in VBA that evaluates a cell color only when the color is changed? So it would be similar to something like this
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$1" Then
Call Search_Batch_Docs
End If
End Sub
But would only trigger on a fill color change.
I have a sheet where I have color coded a column but I also have a column that contains a specific word that coincides with the color of the first column.
Excel doesn't have an event specifically for background color change. But checking the color of a single cell with each change shouldn't be unreasonable for most use-cases.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$1" And Target.Interior.color <> xlNone Then
Select Case Target.Interior.ColorIndex
Case 3
Target.offset(0, 1).Value = "Text if adjacent cell is red"
'And so on
End If
End Sub
EDIT: As per the comments below, this assumes that a VALUE in the targeted range has been changed, not only the formatting. If you require an event-based solution that is called more frequently, you could try Worksheet_SelectionChange to be called every time a new range becomes the active selection, but it will be less efficient.
If possible, it might be best to have a button to update values when pressed. And/or have it update when the worksheet is activated using Worksheet_Activate.
I have a worksheet that is basically a calendar in which I add certain tasks.
Now I would like for excel to add a certain text below a cell if I enter a certain text in this cell.
E.g. If I wrote "Evaluation" in cell A1, the text "Personnel" would appear in cell A2. However, if I wrote "Evaluation" in cell B1, the text "Personnel" would appear in B2 and so on. Furthermore, I would also probably write "Evaluation" in more than one cell and the insertion of "Personnel" should apply to all these cells.
Since it is completely variable where I enter the text ("Evaluation") and all other cells also need to be free, I cannot do it with basic Excel formulas. Thus, I think, VBA is the only way to go.
Unfortunately I have not much experience with VBA, so I would be very glad if you could help me out.
Put this in the worksheet's private code sheet.
private sub worksheet_change(byval target as range)
application.enableevents = false
dim t as range
for each t in intersect(target, target.parent.usedrange)
if lcase(t.value2) = "evaluation" then
t = "Evaluation"
t.offset(1, 0) = "Personnel"
end if
next t
meh:
application.enableevents = true
end sub
I am very new at VBA, but have managed to make a code which links the header of my worksheet to a cell on another sheet.
The code runs every time I click a cell in the active worksheet. I'd like for the code to only run when a certain cell in the other worksheet changes.
"Report" has the header
"Input" has the cells which the code refers to (B18) and the cell I want the code to run on when changed (B3).
The following is the code that I already have.
Private Sub Worksheet_selectionChange(ByVal Target As Range)
ActiveSheet.PageSetup.RightHeader = "&28" & Format(Worksheets("Input").Range("b18").Text)
End Sub
Any help is much appreciated!!!
Not sure about your second paragraph; my understanding is that you want to monitor cell B3 on the Input worksheet, and when it changes, adjust the RightHeader of the PageSetup of worksheet Report so it reflects what's in cell B18 on the Input worksheet. If that's correct, you could put the following code behind the Input worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Me.Range("B3")) Is Nothing Then
ThisWorkbook.Worksheets("Report").PageSetup.RightHeader = "&28" & Me.Range("B18").Text
End If
End Sub
...and remove your Worksheet_SelectionChange procedure.
The idea is to monitor for changes on the Input worksheet, and act upon those involving its B3 cell.
Ideally, you'd give names to the cells above, so that your code would continue working even if you add or delete rows and columns on the Input worksheet. See Define and use names in formulas. If you were to define Inputs!B3 as MyMonitoredValue and Inputs!B18 as MyPageSetupValue, the code above would become:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Me.Range("MyMonitoredValue")) Is Nothing Then
ThisWorkbook.Worksheets("Report").PageSetup.RightHeader = "&28" & Me.Range("MyPageSetupValue").Text
End If
End Sub
...and you could re-organize the layout of the Input worksheet without worries.
Finally, instead of referring to worksheets by their tab's name (as seen from Excel), you can refer to them directly using their CodeName, as seen from the VBA editor, in the Properties window, under the worksheet's (Name) property (press Ctrl+R to show the Project Explorer, click on the worksheet under the Microsoft Excel Objects node, then press F4 to display the Properties window). You can change this value; I'd typically change it to shtReport. Yet another version of the code would then be:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Me.Range("MyMonitoredValue")) Is Nothing Then
shtReport.PageSetup.RightHeader = "&28" & Me.Range("MyPageSetupValue").Text
End If
End Sub
...which is able to withstand both changes in the Report worksheet's tab name, and reorganization of the Input worksheet.
I am trying to detect if there are changes in a cell value, not particularly the cell contents. I have found multiple solutions to find out if a cell contents has changed, but it does not work when a cell is equal to another cell.
For example, I have cell A1 set to equal B1 and then B1 has a formula that calls in multiple other cells, so I am not able to go back to the beginning and determine whether the cell has changed from that. It needs to come directly from A1.
This is one of the examples I found on this site, but does not determine if the value of A1 has changed, just whether the contents has changed.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 Then
Cells(Target.Row, 3).Value = Date
End If
End Sub
The function application.volatile TRUE at the top of your sub will make your sub calculate each time any value in Excel changes. So then you need a global variable which stores the last-known value of your specified range, and any time the sub runs, start with an
If new_cell_value <> stored_global_variable then...
and close with
stored_global_variable = new_cell value'
End If
See here for further info [h/t to vzczc for the original answer and method]: Refresh Excel VBA Function Results
I have a two (very long) TO-DO lists- one going across and the other going down.
What i want to achieve is for a blank cell to appear at the start of the list instead of having to scroll to the end of the lists to enter a new item.
So then when i have entered an item in a cell and hit enter, i want the cell just populated to move down the list (or across if i hit tab) and a new empty cell to appear at the start of the list.
It would be useful for the new blank cell to be pre-populated with the current date but that is not essential.
Thanks for your help.
NOT FOR POINTS.
Piggy-backing on Gary's answer, the mistake is that you set A to Range("C4:C6"). What happens is, when you enter data into any of C4, C5, and C6, they are all moved to the right because of A.Insert, which refers to all the cells assigned to A.
The trick here is to fully qualify your requirements for Target. Let's say you have a table from B1:E3, like below:
Now, let's say you want to move row 1 if you enter something into A1, row 2 if A2, etc. The following macro should do it (notice the difference with Gary's macro):
Private Sub Worksheet_Change(ByVal Target As Range)
Dim QualifyingRange As Range
'Dim OrigRng As String
Set QualifyingRange = Range("A1:A3")
If Intersect(Target, QualifyingRange) Is Nothing Then Exit Sub
Application.EnableEvents = False
'OrigRng = Target.Address
Target.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
'Range(OrigRng).Value = Date
Application.EnableEvents = True
End Sub
What is the difference in the above? Very simple but very important. When a Worksheet_Change is in a sheet's code, every time you do a valid change to the sheet, the macro fires. The range you just edited will be known to the macro as Target. Now, usually, if you don't declare what the qualifications for Target are, the Worksheet_Change macro just fires indiscriminately. How do we qualify Target properly then?
We use Intersect. First, we declare a range of cells that we want to track. These cells, when changed, should fire the macro. Otherwise, macro is kaput. This line: If Intersect(Target, QualifyingRange) Is Nothing Then Exit Sub basically reads: If Target is not inside my desired range, then nothing happens.
This is the reason why I declared A1:A3 as my QualifyingRange. This way, if my change is to any of the cells above, the macro will fire. HOWEVER, .Insert should not be applied to the whole range but to Target alone. This is because if we do QualifyingRange.Insert, every time a change is detected in any cells in A1:A3, all three rows will move. This is what happened when you set A to three cells and kept A.Insert.
Hopefully, this clears up the confusion. Let us know if this helps.
Here is a partial solution. The following event macro monitors entry to cell A1 . Once you have entered a value in A1, the macro "pushed" the values in column A down by one. This means that value you just entered has been pushed down to A2 and A1 is empty:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range
Set A = Range("A1")
If Intersect(A, Target) Is Nothing Then Exit Sub
Application.EnableEvents = False
A.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Application.EnableEvents = True
End Sub
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
EDIT#1
To push across rather than down:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range
Set A = Range("A1")
If Intersect(A, Target) Is Nothing Then Exit Sub
Application.EnableEvents = False
A.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Application.EnableEvents = True
End Sub
To handle multiple cells, you must specify which cells get pushed across and which cells get pushed down.