Converting cells to a range of cells within a BeforeClose VBA - excel

I have looked and tried all the arrays and set functions but when I run it in the program it does not work.
This is my program
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Sheets("Check").Range("G16").Value = "Special Request" And _
Range("G17").Value = "" Or _
Range("G18").Value = "" Or _
Range("G19").Value = "" Or _
Range("G20").Value = "" Then
MsgBox "Please verify that all tabs are check using the check tab"
Cancel = True
End If
End Sub
Instead of naming each cell i would like to insert ranges. an example will be;
G17:G20 or
G24:G29 or
G33:G38 then_
If anyone has any suggestions it would be greatly appreciated

Use WorksheetFunction.CountA() to count the number of non blank values in the range and compare it against the ranges cell count.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim Target As Range
Set Target = Range("G17:G20,G33:G38")
If Sheets("Check").Range("G16").Value = "Special Request" And _
WorksheetFunction.CountA(Target) < Target.count Then
MsgBox "Please verify that all tabs are check using the check tab"
Cancel = True
End If
End Sub

Related

Get address of cell that triggered userform load, populate input fields via offset

I load a userform via a double-click event executed on a range of cells. Once any of the cells in the range gets double clicked, my userform is loaded.
I would like the input boxes of the userform populated with data that is based on an offset of the triggering cell.
I am struggling with capturing the address of the cell that triggered the event, and consequently would need to figure out how to offset from that cell's column and obtain the relevant value for population in the userform.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Not Application.Intersect(Target, Sheets("Daily Summary").Range("D27:D93")) Is Nothing Then
Cancel = True
CommentDetails.Show
End If
End Sub
a) How do I capture the dynamic cell address that triggered the userform load?
b) How do I offset three columns to the right, capture that cell's value and load it into the userform's input field named first_name?
Thanks to #Zwenn in the comments for pointing me in the right direction with Application.Caller. Updated code below, it executes but shows a Object Required error.
The name of the form is CommentDetails, the name of the input field is TextBoxArrival, both of which matches the code.
Private Sub Userform_initialize()
Me.TextBoxArrival.Value = Cells(Application.Caller.Row, Application.Caller.Column + 1)
'TextBoxArrival.Value = Cells(Application.Caller.Row, Application.Caller.Column + 1)
'MsgBox Cells(Application.Caller.Row, Application.Caller.Column + 1).Value, vbOKOnly
End Sub
I understand I have to declare application.caller along with the calling method, which in my case is Sub Worksheet_BeforeDoubleClick. Still getting the same error. I tried circumventing this by calling another separate sub before loading the userform.
Where do I define application.caller?
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim callingCellRow As Integer
If Not Application.Intersect(Target, Sheets("Daily Summary").Range("D27:D29")) Is Nothing Then
Select Case TypeName(Application.Caller)
Case "Range"
callingCellRow = Application.Caller.Row
callingCellColumn = Application.Caller.Column
Case "String"
callingCellRow = Application.Caller.Row
callingCellColumn = Application.Caller.Column
callingCellSheet = Application.Caller
Case "Error"
MySheet = "Error"
Case Else
MySheet = "unknown"
End Select
With CommentDetails
.Tag = callingCellRow '<~~ tell the UserForm there's something to bring in so that it'll fill controls from the sheet instead of initializing them
.Show
.Tag = ""
End With
Unload CommentDetails
End If
End Sub
There's 3 ways to do this explained on Daily Dose of Excel by Dick Kusleika (18 years ago!). I prefer the 3rd option as it handles the form instance with a variable.
In Worksheet_BeforeDoubleClick you can have this:
Option Explicit
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim objForm As UserForm1
If Not Application.Intersect(Target, Me.Range("B2:D2")) Is Nothing Then
Cancel = True
Set objForm = New UserForm1 ' <-- use a variable for the form instance
Set objForm.rngDoubleClicked = Target ' <-- set property of the form here with Target
objForm.Show
End If
End Sub
And then in the form code:
Option Explicit
Private m_rngDoubleClicked As Range
' set only
Public Property Set rngDoubleClicked(rng As Range)
Set m_rngDoubleClicked = rng
End Property
' use the property
Private Sub UserForm_Activate()
Dim strAddress As String
Dim rngOffset As Range
' m_rngDoubleClicked is now the range that was double clicked
strAddress = m_rngDoubleClicked.Parent.Name & "!" & m_rngDoubleClicked.Address
Set rngOffset = m_rngDoubleClicked.Offset(3, 0)
Me.TextBox1.Text = "The address of the double clicked cell is " & strAddress
Me.TextBox2.Text = "The value 3 rows down from double clicked cell is " & rngOffset.Text
End Sub
Private Sub UserForm_Initialize()
' no args for initialization unfortunately :(
End Sub
Example:

unhide excel sheets from dropdown with password

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.

Hide Entire given rows if a specified cell is blank

I am a newbie in VBA coding.
I am trying to achieve that inside my function
sub Private Sub Worksheet_Change(ByVal Target As Range)
where it checks some specified cells value change to run a given macro. The additional macro that i want to add is that when ever cell a62 is Empty, it will hide rows a56:a61. and consecutively if a82 is empty, it will hide rows a78:a82.
i have the following code but it only hides the rows from the first empty cell until end of sheet.
Sub Test()
Dim i As Long
For i = 4 To 800
If Sheets("Results").Cells(i, 1).Value = "" Then
Rows(i & ":" & Rows.Count).EntireRow.Hidden = True
Rows("1:" & i - 1).EntireRow.Hidden = False
Exit Sub
End If
Next
End Sub
Please, check the next event code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$62" Or Target.Address = "$A$82" Then
Select Case Target.Address
Case "$A$62"
If Target.Value = "" Then
Range("A56:A61").EntireRow.Hidden = True
Else
Range("A56:A61").EntireRow.Hidden = False
End If
Case "$A$82"
If Target.Value = "" Then
Range("A78:A81").EntireRow.Hidden = True
Else
Range("A78:A81").EntireRow.Hidden = False
End If
End Select
End If
End Sub
It will be triggered only if you MANUALLY change the value of one of the two required cells.
If their value is the result of a formula, Worksheet_Calculate event must be used, but in a different way. This event does not have any argument (no Target) and you must check the two cells in discussion and act according to their value, independent if they were changed or not when the Calculate event is triggered. If this is the case, I can post such an event code, too.
Edited:
For the version which does not involve the manual changing of the values, please copy this event code in the sheet code module:
Private Sub Worksheet_Calculate()
If Me.Range("A62").Value = "" Then
Me.Range("A56:A61").EntireRow.Hidden = True
Else
Me.Range("A56:A61").EntireRow.Hidden = False
End If
If Me.Range("A82").Value = "" Then
Me.Range("A78:A82").EntireRow.Hidden = True
Else
Me.Range("A78:A82").EntireRow.Hidden = False
End If
'Edited:
'The part for both analyzed ranges being empty:
If Me.Range("A62").Value = "" And _
Me.Range("A82").Value = "" Then
'Do here what you need...
End If
End Sub

how to retrieve a value from an userform

I'm trying to write a code to trace every change made by the user on any worksheet. The user will input data and from time to time will erase said data and/or correct the original value they inserted. If the change is either deletion or modification, an Userform will pop up and the user will include a reason for that change. Right now I'm able to display the form everytime the user makes one of the changes mentioned before, but I'm not able to retrieve the reason, could you guys help me?
This is what I have for the UserForm
Private Sub CommandButton1_Click()
Dim msgvalue As VbMsgBoxResult
Dim value As String
msgvalue = MsgBox("Do you wish to save the change?", vbYesNo + vbInformation, "Confirm")
If msgvalue = vbNo Then GoTo Command
If msgvalue = vbYes Then
value = UserForm1.txtCmmt.Value
If value = "" Then GoTo Command
End
End If
Command:
MsgBox ("A reason must be provided")
With UserForm1
.txtCmmt.Value = ""
End With
End Sub
So if a user tries to delete a value, the code is the following:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim sLastAction As String
Dim Cell As Range
sLastAction = Application.CommandBars("Standard").Controls("&Undo").List(1)
For Each Cell In Target
If sLastAction = "Clear" Or sLastAction = "Delete" Or Left(sLastAction, 9) = "Typing ''" Then
UserForm1.Show 'this is where I'm stuck, I'm not sure how to retrieve the value from the form
End If
'the code continues to retrieve other info from the changes made, including the "reason"
Thanks for the help!
Try the next way, please:
Let us say that your text box where the comment will be written is named "txtComment".
Put this code in its Exit event:
Private Sub txtComment_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Me.txtComment.text <> "" Then
If ActiveSheet.Name <> "LogDetails" Then
Application.EnableEvents = False
Sheets("LogDetails").Range("A" & rows.count).End(xlUp).Offset(0, 5).Value = Me.txtComment.text
Application.EnableEvents = True
Unload Me
End If
End If
End Sub
Let the existing Worksheet_Change event as it is, only launching the form and maybe making a Public boolean variable (from a standard module) True (something boolStop) which will not allow changing anything in any worksheet until it is not False.
Then fill the text you need in the text box ("txtComment", or however you named it) and press Enter. If my above suggestion looks interesting for you, the last line of the text box event will be boolStop = False.
If you understand how to implement the above simple solution, you maybe will forget about a user form and use a simple InputBox, as in the next example:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address(0, 0) <> "E1" Then Exit Sub
Dim sLastAction As String, comValue As String
Dim Cell As Range
sLastAction = Application.CommandBars("Standard").Controls("&Undo").list(1)
For Each Cell In Target
If sLastAction = "Clear" Or sLastAction = "Delete" Or left(sLastAction, 9) = "Typing ''" Then
WritePlease:
comValue = InputBox("Please write the reason for cell """ & Cell.Address & """ (" & sLastAction & ").", "Reason, please")
If comValue = "" Then GoTo WritePlease
If ActiveSheet.Name <> "LogDetails" Then
Application.EnableEvents = False
'Stop
Sheets("LogDetails").Range("A" & rows.count).End(xlUp).Offset(0, 5).Value = comValue
Application.EnableEvents = True
End If
End If
Next
End Sub

How to detect if user select cancel InputBox VBA Excel

I have an input box asking user to enter a date. How do I let the program know to stop if the user click cancel or close the input dialog instead of press okay.
Something like
if str=vbCancel then exit sub
Currently, user can hit OK or Cancel but the program still runs
str = InputBox(Prompt:="Enter Date MM/DD/YYY", _
Title:="Date Confirmation", Default:=Date)
If the user clicks Cancel, a zero-length string is returned. You can't differentiate this from entering an empty string. You can however make your own custom InputBox class...
EDIT to properly differentiate between empty string and cancel, according to this answer.
Your example
Private Sub test()
Dim result As String
result = InputBox("Enter Date MM/DD/YYY", "Date Confirmation", Now)
If StrPtr(result) = 0 Then
MsgBox ("User canceled!")
ElseIf result = vbNullString Then
MsgBox ("User didn't enter anything!")
Else
MsgBox ("User entered " & result)
End If
End Sub
Would tell the user they canceled when they delete the default string, or they click cancel.
See http://msdn.microsoft.com/en-us/library/6z0ak68w(v=vs.90).aspx
Following example uses InputBox method to validate user entry to unhide sheets:
Important thing here is to use wrap InputBox variable inside StrPtr so it could be compared to '0' when user chose to click 'x' icon on the InputBox.
Sub unhidesheet()
Dim ws As Worksheet
Dim pw As String
pw = InputBox("Enter Password to Unhide Sheets:", "Unhide Data Sheets")
If StrPtr(pw) = 0 Then
Exit Sub
ElseIf pw = NullString Then
Exit Sub
ElseIf pw = 123456 Then
For Each ws In ThisWorkbook.Worksheets
ws.Visible = xlSheetVisible
Next
End If
End Sub
The solution above does not work in all InputBox-Cancel cases. Most notably, it does not work if you have to InputBox a Range.
For example, try the following InputBox for defining a custom range ('sRange', type:=8, requires Set + Application.InputBox) and you will get an error upon pressing Cancel:
Sub Cancel_Handler_WRONG()
Set sRange = Application.InputBox("Input custom range", _
"Cancel-press test", Selection.Address, Type:=8)
If StrPtr(sRange) = 0 Then 'I also tried with sRange.address and vbNullString
MsgBox ("Cancel pressed!")
Exit Sub
End If
MsgBox ("Your custom range is " & sRange.Address)
End Sub
The only thing that works, in this case, is an "On Error GoTo ErrorHandler" statement before the InputBox + ErrorHandler at the end:
Sub Cancel_Handler_OK()
On Error GoTo ErrorHandler
Set sRange = Application.InputBox("Input custom range", _
"Cancel-press test", Selection.Address, Type:=8)
MsgBox ("Your custom range is " & sRange.Address)
Exit Sub
ErrorHandler:
MsgBox ("Cancel pressed")
End Sub
So, the question is how to detect either an error or StrPtr()=0 with an If statement?
If your input box is an array, it does not work. I have solved it by adding a check for if it is an array first.
Dim MyArrayCheck As String
Dim MyPlateMapArray as variant
MyPlateMapArray = Application.InputBox("Select ....", Type:=8)
MyArrayCheck = IsArray(MyPlateMapArray)
If MyArrayCheck = "False" Then
Exit Sub
End If
I have solved it with a False like below
MyLLOQ = Application.InputBox("Type the LLOQ number...", Title:="LLOQ to be inserted in colored cells.", Type:=1)
If MyLLOQ = False Then Exit Sub
If user click cancel the sub will exit.
Another suggestion.
Create a message box when inputbox return null value. Example:
Dim PrC as string = MsgBox( _
"No data provided, do you want to cancel?", vbYesNo+vbQuestion, "Cancel?")
Sub TestInputBox()
Dim text As String
text = InputBox("Type some text")
If text = "" Then
MsgBox "button cancel pressed or nothing typed"
Else
MsgBox text
End If
End Sub
Inputbox send a boolean False value when Cancel is pressed.
contenidoy = Application.InputBox("Cantidad = ", titulox, contenidox, , , , , Type:=1)
'ESC or CANCEL
If contenidoy = False Then
MsgBox "Cancelado"
Else
MsgBox "EdiciĆ³n aceptada"
'End If

Resources