I've got some Excel spreadsheets that are hitting the database pretty hard (100+ queries against the general ledger table... yikes!). Refreshing just the sheet I'm on (SHIFT+F9) is helpful in some spreadsheets, but I wanted a way to refresh just the selected cells. I'm came up with the following code, placed in the ThisWorkbook object:
Dim currentSelection As String
Private Sub Workbook_Open()
Application.OnKey "+^{F9}", "ThisWorkbook.RecalculateSelection"
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
currentSelection = Target.Address
End Sub
Private Sub RecalculateSelection()
Range(currentSelection).Calculate
End Sub
If possible, I'd like to make this more portable, such as storing it in an XLA file and loading it as an Excel addin. Is this possible with the method I'm using? Is there a better way to achieve this?
You should be able to use the following:
Public Sub RecalculateSelection()
Dim rng As Range
Set rng = Application.Selection
rng.Calculate
End Sub
You should place some error handling around the 'Set rng' line, as the user may not have selected a range (e.g. they may have selected a chart).
By using the application object you don't need to capture the Workbook_SheetSelectionChange event.
if your using the method from the accepted answer above you should first check that...
If Not Selection Is Nothing Then
If TypeName(Application.Selection) = "Range" Then
Dim Rng As Range
Set Rng = Application.Selection
Rng.Calculate
End If
End If
Also you might like to add it to the sheet and sheetname context menus.
The name of the two commandbars that you need to do that are...
"Cell" and "Ply"
If you just want to recalculate the currently selected cells, ignoring cells that are dependent on them you can use my RangeCalc addin, downloadable from
http://www.decisionmodels.com/downloads.htm
Related
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 ...
I'm somewhat newer to VBA, and this particular action seems like it may be out of my current scope of knowledge.
Is there a way to code VBA to have it actively select the same cell on all worksheets as the current cell selected? I have a model I've put together to allow my team to enter data simultaneously regarding product SKUs in Column A on Sheet1, but due to the large amount of information that we enter per item, I used multiple sheets
For example, if I have cell H4 selected on Sheet1, is it possible to have all other sheets active cell H4 upon switching to the other worksheets?
This is what I've come up with so far on a test workbook, but it does not seem to work:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Select Case LCase(Sh.Name)
Case Is = "sheet1", "sheet2", "sheet3"
If CurRow > 0 Then
With Application
.EnableEvents = False
.Goto Sh.Cells(CurRow, CurCol), Scroll:=True
Sh.Range(ActCellAddr).Select
.EnableEvents = True
End With
End If
End Select
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
Select Case LCase(Sh.Name)
Case Is = "sheet1", "sheet2", "sheet3"
CurRow = ActiveWindow.ScrollRow
CurCol = ActiveWindow.ScrollColumn
ActCellAddr = ActiveCell.Address
End Select
End Sub
I've located this code below:
Excel VBA code to allow the user to choose the same cell on every sheet
But this requires the user actually enter the cell they'd like to have selected. I am looking for it to be automatic.
Any tips or suggestions? Any help is greatly appreciated.
You can post the following to every sheet in your workbook.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set CurrWS = ActiveSheet
For Each WS In ThisWorkbook.Worksheets
WS.Activate
WS.Range(Target.Address).Select
Next
CurrWS.Activate
End Sub
Every time you select a cell, it will cycle through all the worksheets and select the same cell there. The downside to this is obvious: if you have too many sheets, it's going to be tedious. The other problem is that it's going to cycle through everything. So it might mess up some other sheets if you're going to use this for data entry.
Otherwise, if it's just selecting the cell, then this is harmless though the flicker can be noticeable at times, based on how many sheets you have.
Not as elegant as one would want, but it works. Good luck and let us know if this helps.
Worth noting there is a workbook-level event handler which handles the same event, so you only need to add the code once to the ThisWorkbook code module:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _
ByVal Target As Range)
Sh represents the ActiveSheet.
Probably also worth disabling events while you're selecting the ranges on the other sheets, or that will re-trigger your event handler (don't forget to turn event handling back on before exiting your code!)
This approach will test for hidden sheets. It selects all non-hidden sheets, selects the target cell then returns to the original sheet. It works pretty fast even if you have many many tabs.
targetcell = ActiveCell.Address
OriginSheet = ActiveSheet.Name
Dim ws As Worksheet
For Each ws In Sheets
If ws.Visible = True Then ws.Select (False)
Next ws
range(targetcell).Select
Sheets(OriginSheet).Select
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.
I usually try to avoid VBA in Excel, but it would be convenient to be able to type text into a cell, and have its column get wider or narrower to accommodate the text remaining as it's entered or deleted.
This would be subject, of course, to the lengths of the text in the other cells in the column.
'Auto-fit as you type', I guess you might call it.
Is there an easy way to do this in a suitable handler?
I'm not sure if there is a way to do it while your typing. I think excel generally stretches the cell view to display all the text before it fires the worksheet_change event.
This code will resize the column after you have changed and moved the target to a new range. Place it in the worksheet module.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim nextTarget As Range
Set nextTarget = Range(Selection.Address) 'store the next range the user selects
Target.Columns.Select 'autofit requires columns to be selected
Target.Columns.AutoFit
nextTarget.Select
End Sub
If your just looking to do it for a particular column you would need to check the target column like this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim nextTarget As Range
Set nextTarget = Range(Selection.Address) 'store the next range the user selects
If Target.Column = 1 Then
Target.Columns.Select 'autofit requires columns to be selected
Target.Columns.AutoFit
nextTarget.Select
End If
End Sub
I cannot think of a way to do what you ask for but something very close to your need.
In modern versions of Excel (2010+, I don't know about the 2007 version) you could use the following macro to resize your column to fit data as soon you finished entering data in a cell.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Application.ScreenUpdating = False
ActiveSheet.Columns.AutoFit
End Sub
Put the macro in ThisWorkbook module
This will automatically fit columns width
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Columns.AutoFit
End Sub
I just tried the previous two answers on a sheet and they didn't do anything, idk if the "ByVal Sh" is the problem?? was it a typo?
Anyhow, here is my answer, checked it and it works:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target Is Nothing Then
Exit Sub
Else
With Target
.Columns.Select
.Columns.AutoFit
End With
End If
End Sub
-.Reverus.
I have two spreadsheets... when one gets modified in a certain way I want to have a macro run that modifies the second in an appropriate manner. I've already isolated the event I need to act on (the modification of any cell in a particular column), I just can't seem to find any concrete information on accessing and modifying another spreadsheet (this spreadsheet is located on a different LAN share also... the user has access to both, though).
Any help would be great. References on how to do this or something similar are just as good as concrete code samples.
In Excel, you would likely just write code to open the other worksheet, modify it and then save the data.
See this tutorial for more info.
I'll have to edit my VBA later, so pretend this is pseudocode, but it should look something like:
Dim xl: Set xl = CreateObject("Excel.Application")
xl.Open "\\the\share\file.xls"
Dim ws: Set ws = xl.Worksheets(1)
ws.Cells(0,1).Value = "New Value"
ws.Save
xl.Quit constSilent
You can open a spreadsheet in a single line:
Workbooks.Open FileName:="\\the\share\file.xls"
and refer to it as the active workbook:
Range("A1").value = "New value"
After playing with this for a while, I found the Michael's pseudo-code was the closest, but here's how I did it:
Dim xl As Excel.Application
Set xl = CreateObject("Excel.Application")
xl.Workbooks.Open "\\owghome1\bennejm$\testing.xls"
xl.Sheets("Sheet1").Select
Then, manipulate the sheet... maybe like this:
xl.Cells(x, y).Value = "Some text"
When you're done, use these lines to finish up:
xl.Workbooks.Close
xl.Quit
If changes were made, the user will be prompted to save the file before it's closed. There might be a way to save automatically, but this way is actually better so I'm leaving it like it is.
Thanks for all the help!
Copy the following in your ThisWorkbook object to watch for specific changes. In this case when you increase a numeric value to another numeric value.
NB: you will have to replace Workbook-SheetChange and Workbook-SheetSelectionChange with an underscore. Ex: Workbook_SheetChange and Workbook_SheetSelectionChange the underscore gets escaped in Markdown code.
Option Explicit
Dim varPreviousValue As Variant ' required for IsThisMyChange() . This should be made more unique since it's in the global space.
Private Sub Workbook-SheetChange(ByVal Sh As Object, ByVal Target As Range)
' required for IsThisMyChange()
IsThisMyChange Sh, Target
End Sub
Private Sub Workbook-SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
' This implements and awful way of accessing the previous value via a global.
' not pretty but required for IsThisMyChange()
varPreviousValue = Target.Cells(1, 1).Value ' NB: This is used so that if a Merged set of cells if referenced only the first cell is used
End Sub
Private Sub IsThisMyChange(Sh As Object, Target As Range)
Dim isMyChange As Boolean
Dim dblValue As Double
Dim dblPreviousValue As Double
isMyChange = False
' Simple catch all. If either number cant be expressed as doubles, then exit.
On Error GoTo ErrorHandler
dblValue = CDbl(Target.Value)
dblPreviousValue = CDbl(varPreviousValue)
On Error GoTo 0 ' This turns off "On Error" statements in VBA.
If dblValue > dblPreviousValue Then
isMyChange = True
End If
If isMyChange Then
MsgBox ("You've increased the value of " & Target.Address)
End If
' end of normal execution
Exit Sub
ErrorHandler:
' Do nothing much.
Exit Sub
End Sub
If you are wishing to change another workbook based on this, i'd think about checking to see if the workbook is already open first... or even better design a solution that can batch up all your changes and do them at once. Continuously changing another spreadsheet based on you listening to this one could be painful.