I would like to develop a code where I can have a dropdown list of sheet names which I want to unhide with a password. I have tried a lot but got no success.
Suppose, I have a multiple sheets by names, "A", "B", "C", up to "F". When I select one or multiple sheet names from dropdown box, it should prompt for password to unhide sheet. Please suggest the best way to do so.
Private Sub Worksheet_Change(ByVal Target As String)
Dim Target As String, msg As Variant
Set Target = Sheets("Sheet1").Range("A1")
If Target.Visible = False Then
msg = Application.InputBox("Password", "Password", "", Type:=2)
If response = "pgdb" Then
Target.Visible = True
Target.Select
Else
Target.Visible = False
End If
End Sub
Thanks. Made below changes in code, but getting Error 9 "Subscript out of range" after assigning the value to Target variable. Please advise.
'Private Sub Worksheet_Change(ByVal Target As Range)
Dim msg As Variant, sh As Range
Target = Sheets("Sheet32").Range("A1")
sh = Target.Value
If Application.ActiveSheet.Name = sh Then
Application.EnableEvents = False
Application.ActiveSheet.Visible = False
msg = Application.InputBox("Password", "Password", "", Type:=2)
If msg = "pgdb" Then
Application.sh.Visible = True
Application.sh.Select
Else
Application.sh.Visible = False
End If
End If
Application.EnableEvents = True
End Sub
It would look something like below:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim DropDownCell As Range
Set DropDownCell = Me.Range("A1") 'me points to the workbook the code is written in
If Not Intersect(DropDownCell, Target) Is Nothing Then 'run the following only if the DropDownCell is part of (intersects) with the changed cells (Target)
Dim PasswordInput As Variant
PasswordInput = Application.InputBox("Password", "Password", "", Type:=2)
If PasswordInput = "pgdb" Then
Dim SheetToUnhide As Worksheet
On Error Resume Next 'next line throws error if sheet does not exist. Hide all error messages from now.
Set SheetToUnhide = ThisWorkbook.Worksheets(DropDownCell.Value)
On Error Goto 0 're-enable error reporting (or you won't notice any further errors if they occur.
'note that SheetToUnhide is Nothing here if the workbook with the name of the drop down value does not exist.
If Not SheetToUnhide Is Nothing Then 'sheet exists
SheetToUnhide.Visible = True
SheetToUnhide.Select
Else 'sheet does not exist
MsgBox "Sheet '" & DropDownCell.Value & "' does not exist.", vbCritical
End If
End If
End If
End Sub
Note that this procedure Private Sub Worksheet_Change(ByVal Target As Range) runs every time any cell gets changed in the worksheet. Target reprecents cell that was changed. Note that Target is a Range and can be multiple cells (if multiple cells get changed at the same time eg. by copy/paste).
This line If Not Intersect(DropDownCell, Target) Is Nothing Then makes sure the code runs only if the drop down cell was changed, and not on every cell change.
Related
Private Sub Workboook_Open()
'Auto Dating Test (1)'
If Range("i4").Value = "CR" Then
Range("I5").Value = Date
End If
Range("I5").Value = Date
End Sub
So I'm trying to get it to work with any variable/information in i4 aswell Delete the date if the value has been deleted, and not automatically update. so it only pulls the date from when the information was entered on i4. so if going back to the document days later it doesn't update automatically to the day the document was opened again. I can't get the thing to run automatically aswell as I haven't even figured out where to begin to delete the date in i5 say if the information in i4 is deleted. nor just a universal detection if somethings in i4 and not just a specific string.
A 'True' Worksheet Change Backed Up By a Workbook Open
These codes have to be copied into three different modules. Additionally, the sheet code name (Sheet1) in PopulateVariables has to be adjusted.
ThisWorkbook
Option Explicit
Private Sub Workboook_Open()
PopulateVariables
End Sub
Sheet Module e.g. Sheet1
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
DateChange Target
End Sub
Standard Module e.g. Module1
Option Explicit
Private Const CHANGE_CELL As String = "I4"
Private Const DATE_CELL As String = "I5"
Private ChangeCellValue As Variant
Private DateCellValue As Variant
' Called by the Workbook Open event.
' Note that the worksheet has to be specified. It's preferable to use
' the code name to allow changing the (tab) name.
Sub PopulateVariables()
ChangeCellValue = Sheet1.Range(CHANGE_CELL).Value ' adjust the sheet!
DateCellValue = Sheet1.Range(DATE_CELL).Value ' adjust the sheet!
End Sub
' Called by the Worksheet Change event.
' If you select a cell and click into the formula bar and press enter
' or you double-click the cell and press enter, you haven't changed
' the value but the Worksheet Change event got triggered anyway.
' That is the meaning of an invalid change.
Sub DateChange(ByVal Target As Range)
On Error GoTo ClearError
Dim cCell As Range, dCell As Range, HaveValuesChanged As Boolean
With Target.Worksheet
Set cCell = .Range(CHANGE_CELL)
Set dCell = .Range(DATE_CELL)
End With
Dim Today As Date: Today = Now ' when done testing, use 'Date'
' Handle change in Change cell.
If Not Intersect(cCell, Target) Is Nothing Then ' change detected
If CStr(cCell.Value) <> CStr(ChangeCellValue) Then ' valid change
Application.EnableEvents = False ' to not retrigger the event
If IsEmpty(cCell) Then
DateCellValue = Empty
dCell.Value = DateCellValue
Else
If CStr(dCell.Value) <> CStr(Today) Then ' date is different
DateCellValue = Today
dCell.Value = DateCellValue
'Else ' date is the same; do nothing
End If
End If
ChangeCellValue = cCell.Value
HaveValuesChanged = True
'Else ' invalid change; do nothing
End If
'Else ' no change detected; do nothing
End If
' Handle change in Date cell.
If Not HaveValuesChanged Then ' previous invalid change or no change
If Intersect(dCell, Target) Is Nothing Then Exit Sub ' no ch. detected
If CStr(dCell.Value) <> CStr(DateCellValue) Then ' valid change
Application.EnableEvents = False ' to not retrigger the event
dCell.Value = DateCellValue
'Else ' invalid change; do nothing
End If
End If
ProcExit:
On Error Resume Next
If Not Application.EnableEvents Then Application.EnableEvents = True
On Error GoTo 0
Exit Sub
ClearError:
Debug.Print "Run-time error '" & Err.Number & "':" & vbLf & Err.Description
Resume ProcExit
End Sub
did you mean like if A4 gets deleted so does A5 and if A4 gets edited the date is shown in A5? try below
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge > 1 Then Exit Sub
If Not Intersect(Target, Range("A4")) Is Nothing Then
If Target.Value = "" Then
Range("A5") = "" 'if A4 gets deleted same goes for A5
Else
Range("A5") = Date 'if A4 gets edited with any value show the date in A5
End If
End If
End Sub
The following code successfully changes the sheet name based on the value in cell "E26" i.e. if the value in "E26" is 'Test', sheet name will be named 'Test'.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set Target = Range("E26")
If Target = "" Then Exit Sub
Application.ActiveSheet.Name = VBA.Left(Target, 31)
Exit Sub
End Sub
Problem is, if I copy the sheet but want to keep the value in cell "E26" the same, the copied sheet name becomes "Test (1)" but I get a Run time error '1004': That name is already taken. Try a different one. obviously.
Question: How can I automatically add a number after each subsequent copy of the sheet i.e. Test (1), Test (2), etc. to avoid getting the error while still keeping the value in cell "E26" the same i.e. Test?
I don't know if I understood the idea, but try to count the current sheets in your book and concat to the name you want
Private Sub Worksheet_SelectionChange(ByVal Target As Range)`
Set Target = Range("E26")
Dim nSheets As Double
nSheets = ThisWorkbook.Sheets.Count
If Target = "" Then Exit Sub
'+1 is optional in order you have a secuence
Application.ActiveSheet.Name = Target & "(" & nSheets + 1 & ")"
End Sub
Let me suggest a bit more complex solution that hopefully also addesses all sort of end cases.
First, let's create a helper function that can answer the question "Is there a sheet with the name x?".
Function sheetExists(name) As Boolean
sheetExists = False
For i = 1 To Application.Worksheets.Count
shtName = Application.Worksheets(i).name
If shtName = name Then
sheetExists = True
Exit Function
End If
Next
End Function
Now that we have that option, let's build the actual code:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MaxTabs = 10 ' Adjust this number as needed.
BaseName = Range("E26").Value
If (BaseName = "") Then
Exit Sub
End If
name = BaseName
i = 0
For i = 1 To MaxTabs
If (Not sheetExists(name)) Then
Application.ActiveSheet.name = name
Exit Sub
End If
name = BaseName + " (" + Trim(Str(i)) + ")"
Next
End Sub
Worksheet Change
You could rather use the Worksheet_Change event and suppress the error(s) by using On Error.
The Code
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rg As Range: Set rg = Intersect(Range("E26"), Target)
If Not rg Is Nothing Then
Application.EnableEvents = False
On Error GoTo clearError
Me.Name = Left(rg.Value, 31)
Application.EnableEvents = True
End If
Exit Sub
clearError:
'Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Resume Next
End Sub
I have programming, with major help from others, that works great for two separate workbooks. The problem is that I can't seem to have them both work within the same workbook and I don't know why.
We have a large contact database (4800 rows) workbook with a lot of sorting macros. I use the following to allow the user to double-click a cell to select or de-select a contact. This is under the Excel Objects, Sheet1 (MASTER):
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'Limit Target count to 1
If Target.Count > 1 Then Exit Sub
'Isolate Target to a specific range
If Intersect(Target, Range("SelectionMaster")) Is Nothing Then Exit Sub
'set Target font tp "marlett"
Target.Font.Name = "marlett"
'Check value of target
If Target.Value < "a" Then
Target.Value = "a" 'Sets target Value = "a"
Cancel = True
Exit Sub
End If
If Target.Value = "a" Then
Target.Value = "r"
Cancel = True
Exit Sub
End If
If Target.Value = "r" Then
Target.ClearContents 'Sets Target Value = ""
Cancel = True
Exit Sub
End If
End Sub
In another workbook, I tested the following for locking a particular row if an 'X' is placed in Column AZ (end of contact data). This is under the Excel Objects, Sheet1 (Sheet1):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LR As Long
If Not Target.Column = 52 Then Exit Sub
If Target.Count > 1 Then Exit Sub
If UCase(Target.Value) = "X" Then
ActiveSheet.Unprotect
Target.EntireRow.Locked = True
ActiveSheet.Protect
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Locked Then
If MsgBox("Row is locked. Do you want to change the value ?", vbYesNo) = vbYes Then
ActiveSheet.Unprotect
Target.EntireRow.Locked = False
Cells(ActiveCell.Row, 52).Value = ""
ActiveSheet.Protect
End If
End If
End Sub
In the Database file, I have certain rows that identify the contact's category that I would like to have locked. All other cells can be changed. If I copy over the 2nd code to the database file, it doesn't work correctly. Instead it locks all of the cells and prompts the message box regardless of an 'X' in Column AZ. Can these two not co-exist or what is this newb doing wrong?
I want to clear the contents of the cell after clicking the ok button in a message pop up window.
When the pop up window disappears, after clicking ok button umpteen times, the script terminates by throwing the below error
Run time error '-2147417848(80010108)':
Method 'Range of object'_Worksheet'Failed
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = Range("N4:O4")
If Not Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
If (Range("E9") = "" Or Range("F9") = "") Then
MsgBox "Reopen Date and Closed Date should not be populated before calculating the Benefit Begin Date and Maximum Benefit Date"
Sheets("Calculation Tool").Range("N4").Clear ----->Code written to clear the cells
Else
If (Range("N4") = "" Or Range("O4") = "") Then
Set b1 = Sheets("Calculation Tool").CommandButton22
b1.Enabled = False
Else
Set b1 = Sheets("Calculation Tool").CommandButton22
b1.Enabled = True
End If
End If
End If
End Sub
I wanted to tell #BigBen that his suggestion worked for me, but my low rep won't allow me to comment. The answer field is the only way of expression for me!
So I might as well formulate a valid answer, here it goes. :)
So I had the same problem within a Worksheet_Change event macro, in this casual event macro:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RangeToCheck As Range
Set RangeToCheck = ActiveSheet.Range("O3:O32")
(above is the line that triggered randomly that Run time error '-2147417848(80010108)' you encountered; on with the script)
If Not Application.Intersect(Target, RangeToCheck) Is Nothing Then
Target.Value = VBA.Replace(Target.Value, ".", ",")
Debug.Print Target.Address, Target.Value
Else
Debug.Print "Not in RangeToCheck"
End If
End Sub
Following BigBen's link, I found that the following code works fine :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RangeToCheck As Range
On Error GoTo enableEventsOn:
Application.EnableEvents = False
Set RangeToCheck = ActiveSheet.Range("O3:O32")
Application.EnableEvents = True
On Error GoTo 0
If Not Application.Intersect(Target, RangeToCheck) Is Nothing Then
Target.Value = VBA.Replace(Target.Value, ".", ",")
Debug.Print Target.Address, Target.Value
Else
Debug.Print "Not in RangeToCheck"
End If
enableEventsOn:
Application.EnableEvents = True
End Sub
I am trying to prevent pasting over a dropdown in Excel. The code I came up with is the following:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
'turn off events so this routine is not continuously fired
Set BoroughTrainingTookPlaceIn = Range("BoroughTrainingTookPlaceIn")
Set StartTimeOfSession = Range("StartTimeOfSession")
Set TypeOfSession = Range("TypeOfSession")
Set BikeabilityLevelRatingBeforeTraining = Range("BikeabilityLevelRatingBeforeTraining")
Set BikeabilityLevelRatingAfterTraining = Range("BikeabilityLevelRatingAfterTraining")
If RangesIntersect(Target, BoroughTrainingTookPlaceIn) Then
PreventPaste (BoroughTrainingTookPlaceIn)
ElseIf RangesIntersect(Target, StartTimeOfSession) Then
PreventPaste (StartTimeOfSession)
ElseIf RangesIntersect(Target, TypeOfSession) Then
PreventPaste (TypeOfSession)
ElseIf RangesIntersect(Target, BikeabilityLevelRatingBeforeTraining) Then
PreventPaste (BikeabilityLevelRatingBeforeTraining)
ElseIf RangesIntersect(Target, BikeabilityLevelRatingAfterTraining) Then
PreventPaste (BikeabilityLevelRatingAfterTraining)
End If
Application.EnableEvents = True
End Sub
Private Function HasValidation(r) As Boolean
' Returns True if every cell in Range r uses Data Validation
On Error Resume Next
x = r.Validation.Type
If Err.Number = 0 Then HasValidation = True Else HasValidation = False
End Function
Function RangesIntersect(ByVal Range1 As Range, ByVal Range2 As Range) As Variant
Dim intersectRange As Range
Set intersectRange = Application.Intersect(Range1, Range2)
If intersectRange Is Nothing Then
RangesIntersect = False
Else
RangesIntersect = True
End If
End Function
Private Function PreventPaste(ByVal Target As Range) As Variant
If Not HasValidation(Target) Then
Application.Undo
MsgBox "Invalid value. Please chose a value from the dropdown"
End If
End Function
The line x = r.Validation.Type is causing Error 1004 when I try to copy by dragging a cell in the dataValdiation Range. I am using named ranges.
I looked trough the already opened questions but didn't find answer there. All help is greatly appreciated.
EDIT:
I was trying to cut it and not to copy and paste it by dragging. Still for newbies like me might be useful to record the macro first and see what you are actually doing