I am designing a time report for my colleagues. There are cells which contain a (hidden) formula but are unprotected because I need the user to still be able to manually override the formula.
Now, if a user enters his/her own content and then deletes it again, the cell is empty, which is what I don't want, as it will only lead to confusion.
I want to write a VBA macro which recognizes if the cell contents in a previously declared range are deleted / empty and if they are deleted / empty, then a formula from another (password-protected and hidden) cell should be copied to the empty cell.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myRange As Range
Set myRange = Intersect(Range("F9:I108"), Target)
If Not myRange Is Nothing Then
'I'm guessing something with WorksheetFunction and possibly CountA,
'but I don't know how to make it work
End If
End Sub
The formulas which should be entered if the content of a cell (or of multiple cells) is deleted is always in line 117 (same worksheet). For example, if the user deletes G50, then G117's formula should be copied into G50 in the same way you usually copy formulas in Excel (so if there's a non-$-reference in G117 that points to A117, it should then point to A50 after the formula is copied to G50).
If possible, I want to work without loops--they always take so long to execute.
Thanks in advance!
Here is a super simple example that involves only 3 cells, A1, A2 and A3. You must modify this to accommodate your formula-cells.
We first create a secret worksheet (called secret). We place the formulas from A1 through A3 from the main worksheet into the secret sheet, but we store them as Strings rather than Formulas:
Then we put the following worksheet event macro in the main sheet:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Range("A1:A3")
If Intersect(Target, rng) Is Nothing Then Exit Sub
If Target.Count <> 1 Then Exit Sub
If Target.Value <> "" Then Exit Sub
Application.EnableEvents = False
Target.Formula = Sheets("secret").Range(Target.Address).Value
Application.EnableEvents = True
End Sub
The sub monitors changes to the three cells and if any of them are cleared, that formula will be restored from the secret worksheet.
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!
Here's another possible answer. In order to copy the formula and have it maintain the "relative addressing" of the formula, you need to copy using the R1C1 notation. So a quick sub for this could look like
Option Explicit
Sub RestoreFormula(ByRef emptyCell As Range)
Dim formulaWS As Worksheet
Dim formulaCell As Range
Set formulaWS = ThisWorkbook.Sheets("Sheet1")
Set formulaCell = formulaWS.Range("A17")
emptyCell.FormulaR1C1 = formulaCell.FormulaR1C1
End Sub
The important line here is the emptyCell.FormulaR1C1 = formulaCell.FormulaR1C1 part.
Then, over in the Worksheet_Change event it could look like this
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim checkRange As Range
Set checkRange = ActiveSheet.Range("A1:A9")
If Not Intersect(checkRange, Target) Is Nothing Then
Dim changedCell As Range
For Each changedCell In Target
If IsEmpty(changedCell) Then
RestoreFormula changedCell
End If
Next changedCell
End If
End Sub
If anyone else ever has the same problem and maybe wants to use my solution, which is a combination of PeterT's and Gary's Student's suggestions (thank you both so much):
First I created a new worksheet, in which I copied all of the formulas I wish to retain. I made sure to copy them to the exact same cell as in the original sheet.
Then I appended this code to the original worksheet:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Bereich1 As Range
Set Bereich1 = Range("F9:I108") 'Do NOT enter multiple, non-contiguous ranges here! It crashes Excel!
If Not Intersect(Bereich1, Target) Is Nothing Then
Dim changedCell1 As Range
For Each changedCell1 In Target
If changedCell1 = "" Then
changedCell1.Formula = Sheets("Tagebuch_secret").Range(changedCell1.Address).Formula
End If
Next changedCell1
End If
Dim Bereich2 As Range
Set Bereich2 = Range("E112") 'instead duplicate the code snippet
If Not Intersect(Bereich2, Target) Is Nothing Then
Dim changedCell2 As Range
For Each changedCell2 In Target
If changedCell2 = "" Then
changedCell2.Formula = Sheets("Tagebuch_secret").Range(changedCell2.Address).Formula
End If
Next changedCell2
End If
End Sub
This works fine for every scenario in which cell contents get deleted, both if the user deletes contents of a single or multiple cells!
My next step is to make the _secret sheet very hidden, password-protect the workbook structure and then password-protect my vba project. Then only people who know the password (me) can destroy my file :)
Related
I really need your help.
Basically I have 2 sheets that I really am concerned for my project as pictured below.
MUFG Client
MUFG Matched
I am looking for VBA code that allows me to:
Double click on a cell within a range (B3:B300) on MUFG Client Sheet.
On Double clicking, it will take the content of the cell I have double clicked on (could be any cell in the above range) and paste the text/value into a different cell on MUFG Matched sheet (Cell D4) automatically.
Any help would be greatly appreciated. I have tried a couple of things such as making hyperlink to the content within the range but it still doesn't work at all and fails too many times.
Thanks
Rendi
The following VBA code should work as you described:
Option Explicit
Function InRange(Range1 As Range, Range2 As Range) As Boolean
' returns True if Range1 is within Range2
Dim InterSectRange As Range
Set InterSectRange = Application.Intersect(Range1, Range2)
InRange = Not InterSectRange Is Nothing
Set InterSectRange = Nothing
End Function
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If InRange(ActiveCell, Worksheets("MUFG Client").Range("B3:B300")) Then
Selection.Copy Worksheets("MUFG Matched").Range("d4")
End If
End Sub
Make sure that you place this code into the worksheet code area of MUFG Client, since that is where you will be double clicking.
You need a Worksheet_BeforedoubleClick event - look them up if you haven't met worksheet events before.
Then it would be something like;
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'Check if it's in the range:
If Target.Column = 2 And Target.Row <300 And Target.Row >3 Then
'Copy to relevant location
Target.Copy Worksheets("MUFG Matched").Range("D4")
End If
End Sub
I am trying to create a workbook where if I change a dropdown on 1 sheet, it automatically updates that same dropdown on a second sheet. These dropdowns will represent different scenarios and my purpose in creating this is to allow the end-user the ability to change the scenario dropdown from any sheet, rather than just one.
I used this reference to create a VBA for changing 1 dropdown -Original VBA code referenced - and it worked correctly (See example workbook to download). However, now I want to add the other 2 dropdowns so that if any changes are made to them it updates accordingly.
I'm also open to other solutions if you know of something better.
Sorry if this question was elementary -- I am new to VBA.
Using the example from the Original VBA code referenced, if you were looking to apply this rule to 2 sets of drop downs (4 total), instead of 1 set - you would duplicate the snippet from "If Not Intersect(..." to "..End if" and then update the reference to the 2nd set of cells.
EXAMPLE:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim targetSheet As Worksheet
If Not Intersect(Target, Range("A1")) Is Nothing Then ' watch only cell A1
Set targetSheet = ActiveWorkbook.Worksheets("Sheet2") ' define the sheet to copy to
On Error Resume Next
Application.EnableEvents = False
targetSheet.Range("B1") = Target.Value ' copy to cell B1 on the target sheet
Application.EnableEvents = True
End If
If Not Intersect(Target, Range("A2")) Is Nothing Then ' watch only cell A1
Set targetSheet = ActiveWorkbook.Worksheets("Sheet2") ' define the sheet to copy to
On Error Resume Next
Application.EnableEvents = False
targetSheet.Range("B2") = Target.Value ' copy to cell B1 on the target sheet
Application.EnableEvents = True
End If
End Sub
You would then repeat for the other worksheet.
I have been assigned simple task (at first I thought so), to monitor input into excel and if there is number (like 0000068145) I need to highlight it with it's colors. So I created two sheets Sheet1 and Database. In Database I keep my data like this:
So I used this code and it called whenever I change something :
Private Sub Worksheet_Change(ByVal Target As Range)
End Sub
And I thought about using Vlookup, but it will retrieve only value as far as I know.
So how would you realize this kind of operation?
I can't use Vlookup, and I really need "database" to be separate from main sheet.
Sorry for my english
I think your approach using Worksheet_Change is correct.
Put the following into the Sheet1 code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim oCell As Range, oDBCell As Range
Dim dbWS As Worksheet
Dim lColor As Long
Set dbWS = ThisWorkbook.Worksheets("Database")
For Each oCell In Target
Set oDBCell = dbWS.Range("A:A").Find(what:=oCell.Value, LookIn:=xlValues, lookat:=xlWhole)
If Not oDBCell Is Nothing Then
lColor = oDBCell.Interior.Color
oCell.Interior.Color = lColor
End If
Next
End Sub
Your "Database" sheet must be named Database.
Now if you put some value into a cell in Sheet1 which is also in column A of your database sheet, then the color is copied from this database sheet.
I have an excel workbook that contains multiple sheets within it. For the sake of this question, the sheets are named Sheet1, Sheet2, Sheet3, and so on. I would like to have Column A from sheet1 be replicated throughout the rest of the sheets and as new cells are added to column A in sheet1, they would automatically be entered into the other sheets within the workbook. I would prefer not to have a set "ending range; ie: A100000" for this. For example, if I enter First in cell A1 of Sheet1, the word "First" should now also appear in cell A1 of Sheet2. I have used the following code, and it does not seem to work. Any help would be greatly appreciated.
Private Sub Worksheet_Change(ByVal Target As Range)
Call UpdateFromSheet1
End Sub
Sub UpdateFromSheet1(ByVal Sh As Object, ByVal Target As Range)
If Sh.CodeName = "Sheet1" Then
If Not Intersect(Target(1, 1), Range("A1:A1000")) Is Nothing Then
Sh.Range("A1:A1000").Copy Sheet2.Range("A1")
End If
End If
End Sub
UPDATE
For a clean looking Non-VBA solution, you can use the formula references that others have mentioned, but enter it like this.
In Sheet2 cell A1 = If(Sheet1!A1="","",Sheet1!A1) That way you can fill down on the whole of column A and not have "0" pop-up if Sheet1 has a rows without data.
I think you have the general idea, but I suspect you may not have your code in the right place.
For the VBA solution:
First, you don't need to call the sub from Worksheet_Change event (unless of course you want to use this sub for other reasons and pass variables to it. Second, if you place this code in the worksheet object in the VBE of the "Sheet1" it will do as you wish:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Columns("A")) Is Nothing Then
Dim wks As Worksheet
For Each wks In Sheets(Array("Sheet2", "Sheet3"))
Target.EntireColumn.Copy wks.Columns(1)
Next
End If
End Sub
This is a very basic use for excel. You can set cells equal to each other. You in no way would need a VBA macro for this.
If you put this in cell "A1" on Sheet2 and Sheet3:
=Sheet1!A1
Then when you type something into A1, it will be "mirrored" on sheets 2 and 3. You can autofill this down to all the cells in column A on sheets 2 and 3.
Are you familiar with the term autofill?
If you don't understand anything I just said and you want to just run a macro then run this and start typing away:
Sub MacroBasicQuestion()
Dim wbk As Workbook
Set wbk = ThisWorkbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Set ws1 = wbk.Sheets(1)
Set ws2 = wbk.Sheets(2)
Set ws3 = wbk.Sheets(3)
Dim cell As Range
Set cell = ws2.Range("A1:A1")
ws2.Select
cell.FormulaR1C1 = "=Sheet1!RC"
cell.Select
Selection.AutoFill Destination:=Range("A:A"), Type:=xlFillDefault
Set cell = ws3.Range("A1:A1")
ws3.Select
cell.FormulaR1C1 = "=Sheet1!RC"
cell.Select
Selection.AutoFill Destination:=Range("A:A"), Type:=xlFillDefault
End Sub
Good Luck.
I'm very new to creating macros and programming in general. I have a worksheet of 38 tabs. 31 tabs are for the days of the month. I would like to create a macro that will prompt users with a warning message any time "MCO" is selected in column N for each of these 31 tabs. Is that possible?
Thanks
It is possible, using a workbook level SheetSelectionChange event. In the ThisWorkbook module in your VBA project paste the following code:
Option Compare Text
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
Dim SelectedCellsInColN As Range
' Make a range of the cells in Target range that intersect with the cells in the N column
Set SelectedCellsInColN = Intersect(Target, Target.Parent.Range("N1:N" & CStr(Target.Parent.Rows.Count)))
If Not SelectedCellsInColN Is Nothing Then
' The user has selected a cell in column N
Dim CurrCell As Range
For Each CurrCell In SelectedCellsInColN
' If the cell's value contains mco (in any case) then prompt the user with a messagebox
If CurrCell.Value Like "*MCO*" Then
MsgBox "You've selected MCO"
' Exit the sub so we don't keep bugging the user about it...
Exit Sub
End If
Next CurrCell
End If
End Sub
Basically what the code does is look at the Target range to see if any cells in the N column are selected, and then loops through any of those cells in column N that are selected to see if their value contains MCO (you can get rid of the stars if you only want a prompt when the cell contains just "MCO"), and if so prompts the user and exits out.
Hope that helps.
-Jon
Are you looking for a macro solution or a vba solution. The two are different. For the macro run through the steps using the macro recoder, for a VBA solution start with Jon's answer