Link Excel Chart Axis Scale to Values in Cells - vba

I have this Gantt Chart and i'm looking at Planned Vs Actual dates.
the problem is that the chart wont sync the start/end date.
i'm trying to link the max/min values to the cell with VBA but it wont to it.
I tried to use this site:
https://peltiertech.com/link-excel-chart-axis-scale-to-values-in-cells/
but his code doesn't work for my chart.
here is a picture:
the dates MUST be the same, and change together if i change some values in the table on the right
any ideas?
thanks
Private Sub Worksheet_Change(ByVal Target As Range)
With ActiveSheet.ChartObjects("Chart 2").Chart
Select Case Target.Address
Case "$G$161"
.Axes(xlCategory).MaximumScale = Target.Value
Case "$F$163"
.Axes(xlCategory).MinimumScale = Target.Value
Case "$G$161"
.Axes(xlValue).MaximumScale = Target.Value
Case "$F$163"
.Axes(xlValue).MinimumScale = Target.Value
End Select
End With
End Sub

The code you have re-used is a simple demonstration program which allows the axes of a chart to be manipulated when one of 6 specific cells on the worksheet is changed. However, these changes are intended to be made by the user through the keyboard. Making a change in this way triggers the Worksheet_Change event and allows the changed cell to be identified. The code within the event routine modifies the chart's axes according to which specific worksheet cell has been changed.
Your issue, as David Ziemens noted in his comment, is that if a cell changes value because it is recalculated through a formula then this change does not trigger a Worksheet_Change event. (Of course, it is entirely possible that a manually entered change elsewhere on the worksheet will have triggered both a Worksheet_Change event and a recalculation causing a cell of interest to change its value via a formula. In this case, however, the Target argument will identify the cell that was manually changed rather than the one recalculated through a formula.)
Throw away the Select ... Case structure, that is really only useful in the context of the demonstration program you are trying to re-use. Instead, change the code so that it unconditionally updates all 4 of your chart properties directly from cells G161 and F163 (so use ws.Range("G161").Value and ws.Range("F163").Value instead of Target.Value for assigning the chart properties, where ws represents whichever worksheet these cells are located on - eg ActiveSheet or Worksheets("Sheet1") or whatever the worksheet is called). Wrap the assignment of the chart properties inside a Workbook_SheetChange sub rather than Worksheet_Change and your chart will update whenever the workbook recalculates.
This is not a very pure solution in that it does not detect whether cells F163 and G161 actually change when recalculation takes place. So it runs the risk that the 4 properties are being unnecessarily assigned with values that are unchanged. However, unless you have a very large workbook and you are pushing the limits of what your computer can handle, this won't matter from a practical point of view.

Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
With ActiveSheet.ChartObjects("Chart 2").Chart
ActiveSheet.ChartObjects("Chart 2").Activate
' for main axes
ActiveChart.Axes(xlValue).MaximumScale = Worksheets("Single
Tool").Range("$G$161").Value
ActiveChart.Axes(xlValue).MinimumScale = Worksheets("Single
Tool").Range("$F$163").Value
'for secondary axes
ActiveChart.Axes(xlValue, xlSecondary).MaximumScale = Worksheets("Single
Tool").Range("$G$161").Value
ActiveChart.Axes(xlValue, xlSecondary).MinimumScale = Worksheets("Single
Tool").Range("$F$163").Value
End With
End Sub
i found that this works best. thank you all

Related

ByVal with a range in which formulas are used.

Private Sub Worksheet_Change(ByVal Target As Range)
'Hvis du på noget tidspunkt tilføjer flere rows, så sig til.
Application.EnableEvents = False
If Not Intersect(Range("B27:B33"), Target) Is Nothing Then
Target.Offset(, 1).Formula = "=UDF_Now()"
End If
Application.EnableEvents = True
End Sub
I am using the following VBA code to execute my user defined function whenever a cell value in the Range("B27:B33") changes.
This works fine, as long as I am changing the cell values in the range manually. The issue is now that I want this macro to work for a given range that is made up by formulas. Whenever I change any of the precedents, a cell value of the range changes, but my macro does not execute.
I want this to work with formulas, so that the macro gets executed whenever I change a precedent and thus change the values of the cells within the range.
I hope this is useful explanation.
The Change Event code doesn't get triggered when the cell content is changed due to a formula.
If you want to trigger a event when the value is being changed by a formula, you may consider Worksheet_Calculate also along with change event code if that is also required.

Excel VBA to call a single macro by mutliple independent worksheet changes

I have used the following Worksheet Change VBA code which is applied to a single cell reference, and is used to call a macro dependent on selection from a data validation list. The event triggered by the macro applies to the row of the active cell.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address(True, True) = "$H$2" Then
Select Case Target
Case "Yes"
Call StandardEntry
Case Else
'Do nothing
End Select
End If
End Sub
I would now like to be able to apply this worksheet change event to be triggered by individual cells within the same column, generating the same event within the active cells row and not affecting any other rows. Identical data validation has been applied to the other cells in the column.
I would appreciate assistance in writing the appropriate code or adjusting the code above to suit.
Thanks #YowE3K!Changing
If Target.Address(True, True) = "$H$2" Then
to
If Target.Column = 8 Then
did the trick and is a really simple solution! Yeehar!

Circle Invalid-data Macro

I have a worksheet with many dependant dropdowns that are liable to having invalid data if the initial drop down is altered. I would like a simple auto-macro that would automatically run the "circle invalid data" command every time a cell change within a specified range (D8:T800) is detected.
It sounds fairly straightforward but I am not sure how to do this.
Question - as this macro will run every single time a cell is amended would this macro slow down the worksheet?
EDIT:
Also: as this might be slow,is there a way we can run this command over a selected range?
Your thoughts thanks.
Try this
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.Range("D8:T800")) Is Nothing Then
Me.CircleInvalid
End If
End Sub
Note that CircleInvalid applies to the whole sheet, so while this code only triggers when a cell inside D8:T800 changes, all invalid cells on the sheet will be circled
Try placing this code inside your Worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)
' Check target range has changed
If (Not Intersect(Target, Range("D8:T800")) Is Nothing) Then
' Prevent recusrive looping
Application.EnableEvents = False
' Refresh validation circles
Target.Worksheet.CircleInvalid
Application.EnableEvents = True
End If
End Sub
Note that this will NOT work if the values in those cells change due to a calculation from outside the specified range.
Also, the CircleInvalid method applies to the whole worksheet.
You could try editing the code in the conditional to 'do something' if the Target is validated — this would result in you changing the format of invalid cells instead of having the red circles around them.
**PSEUDO-CODE**
For each cell in Target.Range
cell.colour = bright red
Next cell

Call a function when only a specific Excel cell changes on Formula Recalculation

As far as i know, Worksheet_Calculate is called when the value of any cell in a worksheet changes on Formula recalculation.
Is there a way so that i need a function to be called only when a specific cell changes on Formula Recalculation
To make something happen when a specific cell is changed, you need to embed the relevant selection change event within the file Worksheet_Change(byval target as Range). We can re-calculate a worksheet when your cell changes as follows:
Private Sub Worksheet_Change(byval target as range)
If target.address = Range("YourCell").Address Then Application.Calculate
End Sub
Now what you want to do is switch off calculations the rest of the time. If you only want to switch off calculations on the single sheet (and not your whole file), you will need to turn calculations off when it is activated, and on when deactivated e.g.
Private Sub Worksheet_Activate
Application.Calculation = xlCalculationManual
End Sub
Private Sub Worksheet_Deactivate
Application.Calculation = xlCalculationAutomatic
End Sub
Of course, your requirements to re-calculate may be considerably more complex than the example above. Firstly, you may open the file whilst on the sheet in question in which case you should use the Workbook_Open event to detect your sheet, and set calculations accordingly
Then you may have several cells that may require some sort of calculation. Presumably the reason you want to switch off calculations is that the file is running too slowly. If so, and you are identifying all the input cells, you could enter the outputs using code. One method would be to enter the formulas using this guide to entering formulas in Excel Visual Basic. You could then replace the formula with the calculated value e.g. Range("YourCell") = Range("YourCell").Value...so stopping the number of formulas in the sheet constantly growing
Let me see if I interpret your question correctly. You want to know if it is possible to only kickoff a macro if a particular cell (or group of cells) is changed.
The answer is Yes. To tweak Ed's code a little.
Private Sub Worksheet_Change(byval target as range)
If Not Intersect(target.address, Range("YourCells")) is Nothing Then
MyMacro()
End If
End Sub
I think your use of "function" is throwing people off. That's why Ed's answer is so elaborate.
Ok. It is possible that you stated your question correctly and you just want to gain efficiency. In that case, Ed's answer solves your immediate problem, but will cause the spreadsheet NOT to calculate automatically when you change other cells.

OnClick in Excel VBA

Is there a way to catch a click on a cell in VBA with Excel? I am not referring to the Worksheet_SelectionChange event, as that will not trigger multiple times if the cell is clicked multiple times. BeforeDoubleClick does not solve my problem either, as I do not want to require the user to double click that frequently.
My current solution does work with the SelectionChange event, but it appears to require the use of global variables and other suboptimal coding practices. It also seems prone to error.
Clearly, there is no perfect answer. However, if you want to allow the user to
select certain cells
allow them to change those cells,
and
trap each click,even repeated clicks
on the same cell,
then the easiest way seems to be to move the focus off the selected cell, so that clicking it will trigger a Select event.
One option is to move the focus as I suggested above, but this prevents cell editing. Another option is to extend the selection by one cell (left/right/up/down),because this permits editing of the original cell, but will trigger a Select event if that cell is clicked again on its own.
If you only wanted to trap selection of a single column of cells, you could insert a hidden column to the right, extend the selection to include the hidden cell to the right when the user clicked,and this gives you an editable cell which can be trapped every time it is clicked. The code is as follows
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'prevent Select event triggering again when we extend the selection below
Application.EnableEvents = False
Target.Resize(1, 2).Select
Application.EnableEvents = True
End Sub
In order to trap repeated clicks on the same cell, you need to move the focus to a different cell, so that each time you click, you are in fact moving the selection.
The code below will select the top left cell visible on the screen, when you click on any cell. Obviously, it has the flaw that it won't trap a click on the top left cell, but that can be managed (eg by selecting the top right cell if the activecell is the top left).
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'put your code here to process the selection, then..
ActiveWindow.VisibleRange.Cells(1, 1).Select
End Sub
SelectionChange is the event built into the Excel Object model for this. It should do exactly as you want, firing any time the user clicks anywhere...
I'm not sure that I understand your objections to global variables here, you would only need 1 if you use the Application.SelectionChange event. However, you wouldn't need any if you utilize the Workbook class code behind (to trap the Workbook.SelectionChange event) or the Worksheet class code behind (to trap the Worksheet.SelectionChange) event. (Unless your issue is the "global variable reset" problem in VBA, for which there is only one solution: error handling everywhere. Do not allow any unhandled errors, instead log them and/or "soft-report" an error as a message box to the user.)
You might also need to trap the Worksheet.Activate() and Worksheet.Deactivate() events (or the equivalent in the Workbook class) and/or the Workbook.Activate and Workbook.Deactivate() events so that you know when the user has switched worksheets and/or workbooks. The Window activate and deactivate events should make this approach complete. They could all call the same exact procedure, however, they all denote the same thing: the user changed the "focus", if you will.
If you don't like VBA, btw, you can do the same using VB.NET or C#.
[Edit: Dbb makes a very good point about the SelectionChange event not picking up a click when the user clicks within the currently selected cell. If you need to pick that up, then you would need to use subclassing.]
I don't think so. But you can create a shape object ( or wordart or something similiar ) hook Click event and place the object to position of the specified cell.
This has worked for me.....
Private Sub Worksheet_Change(ByVal Target As Range)
If Mid(Target.Address, 3, 1) = "$" And Mid(Target.Address, 2, 1) < "E" Then
' The logic in the if condition will filter for a specific cell or block of cells
Application.ScreenUpdating = False
'MsgBox "You just changed " & Target.Address
'all conditions are true .... DO THE FUNCTION NEEDED
Application.ScreenUpdating = True
End If
' if clicked cell is not in the range then do nothing (if condttion is not run)
End Sub
NOTE: this function in actual use recalculated a pivot table if a user added a item in a data range of A4 to D500. The there were protected and unprotected sections in the sheet so the actual check for the click is if the column is less that "E" The logic can get as complex as you want to include or exclude any number of areas
block1 = row > 3 and row < 5 and column column >"b" and < "d"
block2 = row > 7 and row < 12 and column column >"b" and < "d"
block3 = row > 10 and row < 15 and column column >"e" and < "g"
If block1 or block2 or block 3 then
do function .....
end if
I had a similar issue, and I fixed by running the macro "onTime", and by using some global variables to only run once the user has stopped clicking.
Public macroIsOnQueue As Boolean
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
macroIsOnQueue = False
Application.OnTime (Now() + TimeValue("00:00:02")), "addBordersOnRow"
macroIsOnQueue = True
End sub
Sub addBordersOnRow()
If macroIsOnQueue Then
macroIsOnQueue = False
' add code here
End if
End sub
This way, whenever the user changes selection within 2 seconds, the macroIsOnQueue variable is set to false, but the last time selection is changed, macroIsOnQueue is set to true, and the macro will run.
Hope this helps,
Have fun with VBA !!
Just a follow-up to dbb's accepted answer: Rather than adding the immediate cell on the right to the selection, why not select a cell way off the working range (i.e. a dummy cell that you know the user will never need). In the following code cell ZZ1 is the dummy cell
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.EnableEvents = False
Union(Target, Me.Range("ZZ1")).Select
Application.EnableEvents = True
' Respond to click/selection-change here
End Sub