I have a bit of time series data, and potentially want to do a calculation on it. I allow a user to decide if the calculation should be done.
To achieve this, I have a cell that applies data validation to restrict its options to 'Yes' and 'No'. Then I use a conditional that just duplicates the source data, in an adjacent column, if the drop down is toggled to 'No'. If toggled to 'Yes' a lengthy function is applied. For example, =if($AO$9='No', B3, B3 * some long function), where AO9 contains the toggle and this would be entered in C3 and then extended the length of column B.
When toggled from 'No' to 'Yes' the sheet doesn't automatically recalculate. The odd thing is, if I modify any other cell subsequent to toggling between 'No' and 'Yes' it updates instantly and uses the appropriate condition. Additionally, after toggling the cell, if I click in and out of the formula bar it also updates appropriately. Neither of these are ideal solutions when there are other people working on this book. I've checked all of the usual suspects (i.e., calculation options set to automatic, proof below, and that the toggle cell is set to type general and not text).
I've used this sort of scheme for a long time to allow user interaction, and have never had a problem. I did however just upgrade to 365 (Version 1802 Build 9029.2253). Has anyone else encountered this? If so, any suggestions?
Thanks!
You've kept a lot of details super-secret but I would propose a Worksheet_Change event sub procedure that forces B3 to recalculate.
In B3's parent worksheet's private code sheet,
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AO9")) Is Nothing Then
On Error GoTo meh
Application.EnableEvents = False
Range("B3").Calculate
End If
meh:
Application.EnableEvents = True
End Sub
Failing that, just use INDIRECT or OFFSET inside the super-secret 'long formula' and it will recalculate whenever anything in any open workbook changes.
Related
We all know that Excel has some counter-intuitive behaviours and it is, I believe, one of them:
When you select a range of few cells, starting your selection with the cell with data validation list and choose value from drop-down list: only one cell changes (the one containing drop-down list) instead of all selected.
Sometimes a few magic keyboard shortcuts such as CTRL+d, or combination of CTRL+' and CTRL+ENTER can fix this behaviour, but from my experience clients doesn't like to learn some new hacks, they just want to work everything in as simple way as possible.
I found even similar questions on SO e.g. here:
Adding same drop-down value to multiple cells simultaneously
I know that this is very simple code, but following few lines of code make my life easier, and I am sure this will help somebody too. Code in Worksheet module of course:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
' MACRO FILLS THE WHOLE SELECTED RANGE
' WITH THE SAME VALUE USING DROP-DOWN LIST
' IN JUST ONE ACTIVE CELL
' change to false if all selected cells should be filled with value
Const FILL_VISIBLE_CELLS_ONLY As Boolean = True
' detecting if dropdown list was used
'
' I am using very clever solution by JvdV from SO
' ~~~~> stackoverflow.com/questions/56942551/
'
' If after edit we're in the same cell - drop-down list was used
' I know that may be also drag&drop or copy-paste
' but it seems no matters here.
' Warning! Should be add one more check if someone used
' 'accept OK character' next to formula bar, not implemented here.
'
If ActiveCell.Address <> Target.Address Then Exit Sub
' preventing error which sometimes occurs
If IsEmpty(ActiveCell.Value) Then Exit Sub
' fill a range or visible range with activeCell value
If FILL_VISIBLE_CELLS_ONLY Then
Selection.Cells.SpecialCells(xlCellTypeVisible) _
.Value = ActiveCell.Value
Else
Selection.Value = ActiveCell.Value
End If
End Sub
When you select a Range of more than one Cell, is is important to distinguish between the Active Cell (the single highlighted cell) and the Selection (the entire selected range, including the Active Cell).
Then:
Any Content (such as Values or Formulas) that you enter into the Formula bar is input into the Active Cell only, not the entire Selection.
Any Formatting changes you make are applied to the entire Selection, not just the Active Cell.
An exception is when entering an Array formula which applies to the Selection.
Since in this case you are making a change to content not formatting, it is applied to only the Active Cell.
When considering the above, it is not counterintuitive but entirely consistent with the design and operation of the software.
However, from a UX experience this may seem counterintuitive simply because it defies your expectation. This is kind of like a "customer is always right" type situation, which can be very frustrating for programmers, but is essential that it be understood. You can read more about the concept in a series of well-written articles on the topic at https://www.joelonsoftware.com/2000/04/10/controlling-your-environment-makes-you-happy/ (disclosure: the author of these articles happens to be integral to the development history of both Excel and SO, but it is linked here on merit). It was written more than 20 years ago and is still every bit as relevant today.
I have created a spreadsheet which uses the Worksheet_Change feature and the code associated with that works very well. I can stop it firing unnecessarily when inside the module by using Application.EnableEvents = False.
However, while I've created a form to enter data directly into the next available row (again, that works fine in terms of entry) it doesn't cause the formulae in the sheet to calculate (even though auto calculation is on and re-enabled within the module). If I manually place my cursor in the row, hit F2 and simply press enter, everything then fires up.
I have tried to enter data directly into the cells, but of course the Worksheet_Change feature then kicks in again and the cursor isn't simply moving to the next adjacent cell ....
I've tried to check firs for any direct entry with the code below and if it looks like the user isn't entering directly into the cell, the Worksheet_Change is disabled:
Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo eventhandler
Sheets(1).Range("a1").Select
LastCell2 = Sheets(1).Cells(Rows.Count, "A").End(xlUp).Row
Dim intersection As Range
Set intersection = Intersect(Target, Range("A3:F" & LastCell2))
If intersection.Row = LastCell + 1 Then
Exit Sub
End If
Application.EnableEvents = False
The code above is simply checking to see if data is being entered into the next empty cell and if that's the case I want it to just exit there but it isn't working.
So I actually have 2 problems :
the first is why this formula isn't triggering after entry via a vba form - I've used INDIRECT since there are other macros that delete rows by moving the remaining cells up and that was causing the count in the $A$3:$A$500 to reduce to $A$499 and then 498 etc - the addition is done depending on the system date and the transaction date so I get a current value and a future value using a standard sum statement:
=AD1-(SUMIF(INDIRECT("$A$3:$A$500"),"<="&TODAY(),INDIRECT("$E$3:$E$500")))+(SUMIF(INDIRECT("$A$3:$A$500"),"<="&TODAY(),INDIRECT("$F$3:$F$500")))
The second is why I can't enter data directly into the spreadsheet and trap the fact that I don't want it to do anything and simply allow the user to hit enter and move to the next adjacent cell to the one they just entered data into.
Is this a lost cause and am I trying to do too much here? I'm relatively new to coding and teaching myself so apologies if the standard and style isn't to everyone's taste.
Thanks in advance for any replies.
I have the following code to simulate some cells behave like buttons
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Application.ScreenUpdating = False
If Target.Cells.Count = 1 Then
'~~~~~~ pseudocode ~~~~~~
If {select cell is one of the chose ones}
{do some stuff}
End If
'~~~~~~ pseudocode ~~~~~~
End If
Range("A1").Select
'Application.ScreenUpdating = True
End Sub
It doesn't matter whereas I use the ScreenUpdating code, the "Selection box" is flying around from A1 to the selected cell and back and it make the sheet much slower.
Can this flying (animation) selection box be stoped?
So far I have found this, not possible to hide, but noting about the flying efect:
Hide the cell selection box in Excel
Edit:
I need (I think so) edit capabilities on the sheet, therefore the option of not changing selection cell is not applicable. Due to:
most of the sheet is informative, and should be available for copy (not edited)
some cells are input forms (free text thing), selection as usual
some cells should behave like buttons (plus/minus for a numeric value, sclaes, simple stuff, but thousand of then, so much easier do/maintain by code), and user must not edit them
grouping should be available, (so that's complicate protecting the sheet)
I am not closed to the option : Range("A1").Select after each (most) of user interaction, but no other method comes into mind to me now.
An example:
I know some would say: "you should make this out from excel", and I agree with you, but this is a mandatory thing, I do not have the power to raise this question
As you can see, I got the "flying selection" that I try to get rid off
cell A1 is already hodden, that will do most of the trick
final version sure will go with hidden gridlines and headlines
rows groups exist, and are important, so no protection possible
all the functionality, I can do easy with vba, just problem with the animation
Maybe this is not the answer that you have been waiting for, but as Mathieu mentioned in his comment, please try to avoid using Selection.
It does make things slower and often causes errors (in example try selecting cell from hidden sheet). Instead just do something with the range that you define with your if statements directly. Every property of Cell or Range can be accessed directly.
Hope it helps.
Not sure how you can achieve you "flying select box" problem, but at least you could add this code, so opening/closing groups are available on protected sheets:
'Password Protect Current Sheet
ActiveSheet.Protect Password:="Add_here_your_password", UserInterfaceOnly:=True
'Enable Group Collapse/Expand Capabilities
ActiveSheet.EnableOutlining = True
How about trying to remove the "back to A1" as much as possible?
Maybe do it only on absolutely necessary, or move back to the changed value (the 33 in your example), or to the question title (in your multi-option example)
I'm trying to finish up a project of mine and I right now have a Form Control that when pressed adds to the value of a number and another button will subtract that value.
Another value has the two different buttons for the same thing, but the value is also dependent on the first value and other things than just the buttons modify that value. I tried implementing this code for validation
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("F19")) Is Nothing Then
If Range("E19") = 2 And Range("F19") < 12 Then
Range("E20") = 1
End If
End If
End Sub
but Excel apparently doesn't recognize that cell F19 has changed when the change is caused by the button, only when it is caused by user input. So, what this is saying is, if F19 updates and 19 is 2 and F19 is less than 12 (the prerequisite for E12 being 2 is F19 being 12 or greater) then set E20 to 1 (E20 is a modifier for E19 which also has other modifiers going into it). This method works on other values that aren't button controlled, but how can I get excel to realize when the Form Control button changes the value (or at least monitor when the form control is pressed.)
Edit: The macro actually doesn't work if the cell changes by formula either. I don't think I can use Worksheet_Calculate to monitor the change in a specific cell.
Why are you doing this with code anyway? You could have Cell E20 have a formula like: =IF(AND(E19=2,F19<12),1,"") which would make the cell blank unless the condition is met.
If you really want to do it with code, you should take this into account: The Worksheet_Change event "Occurs when cells on the worksheet are changed by the user or by an external link."
I would recommend instead of having
If Range("E19") = 2 And Range("F19") < 12 Then
Range("E20") = 1
End If
In your Worksheet_Change event that you add it as a separate sub, that you call from Worksheet_Change. You would also call the sub from the code for your button, after you've performed whatever action your button does. That way, you're guaranteed the check gets run and do not try to rely on events.
Daniel is partialy right, Worksheet_Change "Occurs when cells on the worksheet are changed by the user or by an external link." But this includes changes caused by VBA, and Excludes changes by a formula.
Your problem may be caused (or at least exacerbated) by the only partial qualification of your ranges:
Range("E19") will refer to 'E19' on the active sheet, which may or may not be be the sheets Target is on. You got it right with Target.Worksheet.Range("F19")
Try (note the .'s)
With Target.Worksheet
If Not Intersect(Target, .Range("F19")) Is Nothing Then
If .Range("E19") = 2 And .Range("F19") < 12 Then
.Range("E20") = 1
End If
End If
End With
BTW. I'm with Daniel in that your whole solution seems a little off, but we may not be getting the whole picture...
So, it's a new week, and I've got new ideas for improving things. Part of what I do is send out reports to individual offices and departments all over the place; these offices in turn are supposed to go through the information and note inconsistencies. As with everything in life, this turns out to be more trouble than anything else. In an effort to make it a little bit more painless (I hope) I want to try somethinga little different for them. What I would like to do is set up something within the worksheet that the individuals receive that does two things:
First, I would like to set up the worksheet so that when the user
clicks on a cell the cell is highlighted;
Second, after the cell highlights then the activebox would
automatically transfer to a "comments" box at the end of the row
where the user would enter their comments as to why the cell in
question was highlighted; and
Third, assuming that someone will make a mistake and highlight
something by mistake I would like to add the additional function
that if a user selects a cell that is highlighted then it would
clear the highlight from the cell.
Possible? Suggestions? Thanks!
JMax is correct in identifying the flaw in that you cannot edit a cell if it changes color and selects a comments cell every time you click on it. The best way around this problem is to change the color only on double-click. I would also define the selected row/column and see if they fall within a table's range (instead of using Application.Intersect) but that's just personal preference
Something like...
Private Sub Worksheet_Beforedoubleclick(ByVal target As Range, cancel As Boolean)
Application.EnableEvents = False
Dim TargRow as Variant
Dim TargCol as Variant
TargRow = target.Row
TargCol = target.Column
'Define Header, FirstCol, CommentCol, LastCol as required to define your table/range where you wish these changes to be made. CommentCol is the cell in which comments should be made
If TargRow > Header And TargCol > FirstCol and TargCol < LastCol Then
If Cells(TargRow,TargCol).Interior.ColorIndex <> -4142 Then 'change color as required to match background
Cells(TargRow,TargCol).Interior.ColorIndex = 3 'change color as required; this makes them red
Cells(TargRow,CommentCol).Select
Else
Cells(TargRow,TargCol).Interior.ColorIndex = -4142 'match color from start of IF statement
End If
End If
Application.EnableEvents = True
End Sub
Note that we disable events so no other code can be triggered by us selecting a different cell. This is an absolute necessity when implementing the Worksheet_SelectionChange event, less so with the BeforeDoubleClick event
It's very important to consider how you trigger macros and how they give the user flexibility. This Excel help video provides a reasonable introduction
What you can (and probably have to) use is the Worksheet_SelectionChange event procedure:
See MSDN for how it works.
You also should have a look at Chip Pearson's page about events.
When the user changes the selection, you should check wheter you are in the right cells (using Intersect) and if so, change the Target background color and change the ActiveCell to the one where you should put comments.
Btw, you can check if the cell is aldreay highlighted before moving to another cell.
The main drawback of this method is that it will move the Excel Selection every time the user clicks on a corresponding cell. A solution would be to tell the user to use the Scroll Lock key and to navigate with arrows. See this link on how it works.