Excel VBA IF statement being skipped - excel

I have two If statements that follow each other down below. The first checks if the previous step is marked as complete with an "X", and exits the macro as appropriate. The second If statement checks if that step has already been run. This displays the "Proceed?" question, but choosing "no" does not end the macro.
If Range("D4").Value = "" Then
Dim response As VbMsgBoxResult
response = MsgBox("Previous step is not marked as complete. Proceed?", vbYesNo)
If response = vbNo Then
Exit Sub
End If
End If
If Range("D4").Value = "X" Then
Dim response2 As VbMsgBoxResult
response2 = MsgBox("Current step is already marked as complete, proceed?", vbYesNo)
If response = vbNo Then
Exit Sub
End If
End If
Set Range1 = Sheets("Latest Open QNs Report Data").ListObjects("OpenQns").DataBodyRange.Offset(0, 1)
Set Range1 = Range1.Resize(Range1.Rows.Count, Range1.Columns.Count - 1)
Range1.ClearContents
Sheets("Instructions").Select
Range("D5", "D5").Value = "X"

You have a typo, you want:
If response2 = vbNo Then ...
Or rename response2 = MsgBox(...) to response = ...

Related

VBA Code: How would you partial out a user input and then select a sheet from there

I am having trouble finding a way that would look at a user input if the user input is = 10-1 then it brings up the worksheet 10-1. If the user inputs is = 10 then if brings another input box that would then ask the user to enter 1,2 and if the user enters 1 it will bring up 10-1 sheet if he enters 2 then it will bring up 10-2 sheet. Another example is if the user enters 100 it will bring an input saying "enter a load" from 1,2,3 if the user inputs a 3 it will bring up 100-3 sheet. If the user input 4 then it will return a message box saying sheet does not exist.
Code:
Private Function SheetExists(name As String) As Boolean
SheetExists = False
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.name = name Then SheetExists = True: Exit Function
Next
End Function
Private Function ConfirmEndSub()
ConfirmEndSub = MsgBox("Do you really want to QUIT", vbYesNo + vbQuestion)
If ConfirmEndSub = vbYes Then
MsgBox "Thank You Goodbye"
End If
End Function
Sub InputValidation()
Dim str As String
Dim inp As String
Dim ws As Worksheet
Dim reply As Long
str = MsgBox("Do you want to select a dataset (Yes) or a Graph (No)", vbQuestion + vbYesNo)
If str = vbYes Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
reply = ConfirmEndSub
If reply = vbYes Then Exit Sub
ElseIf SheetExists(inp) Then
Worksheets(inp).Activate
Else
MsgBox "This load and test cannot be found"
End If
ElseIf str = vbNo Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
reply = ConfirmEndSub
If reply = vbYes Then
Exit Sub
End If
End If
End Sub
Hoping to get my program to work

How to select a sheet from a user input box

I am having trouble coding this VBA code. I need the code to ask the user if they want data or a graph. If the user selects Yes From there, I need to the code to look at the selected input and see if that input is a valid sheet name. If not, the input box will display again until valid sheet name. If the sheet is valid, then I need the sheet to be selected or show up whenever the user enters a valid value. I hope that makes sense.
For example, if the user enters (10-1) that is a valid sheet or (1-1) valid sheet but if it is (14-1) or (a-a) that is not a valid sheet.
Note I have not gotten to the graphing part yet, so do not worry about if the user selects no yet. Can someone get me in the correct direction?
Sub InputValidation()
Dim str As String
Dim inp As String
Dim ws As Worksheet
str = MsgBox("Do you want to select a dataset (Yes) or a Graph (No)", vbQuestion + vbYesNo)
If str = vbYes Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
If MsgBox("Do you really want to QUIT", vbYesNo + vbQuestion) = vbYes Then MsgBox "Thank You Goodbye"
Exit Sub
End If
ElseIf inp = "#-#" Or "##-#" Then
If Sheets(ws).Name = inp Then
Worksheets(inp).Activate
End If
Else
MsgBox "This load and test cannot be found"
If str = vbNo Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
If MsgBox("Do you really want to QUIT", vbYesNo + vbQuestion) = vbYes Then MsgBox "Thank You Goodbye"
Exit Sub
End If
End If
End If
End Sub
Please make sure you close all you if statements when using indentation?
The way you have now set it implies that the last End if is covering the entire str = vbYes scope, i.e. if str = vbNo nothing happens?
Sub InputValidation()
Dim str As String
Dim inp As String
Dim ws As Worksheet
str = MsgBox("Do you want to select a dataset (Yes) or a Graph (No)", vbQuestion + vbYesNo)
If str = vbYes Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
If MsgBox("Do you really want to QUIT", vbYesNo + vbQuestion) = vbYes Then MsgBox "Thank You Goodbye"
Exit Sub
'End If
ElseIf inp = "#-#" Or "##-#" Then
If Sheets(ws).Name = inp Then
Worksheets(inp).Activate
End If
Else
MsgBox "This load and test cannot be found"
End If '=> added this End If as it will otherwise skip to end of sequence
ElseIf str = vbNo Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
If MsgBox("Do you really want to QUIT", vbYesNo + vbQuestion) = vbYes Then MsgBox "Thank You Goodbye"
Exit Sub
End If
End If
End Sub
I also think your below line is incorrect?
ElseIf inp = "#-#" Or "##-#" Then
It will give a Type Mismatch error? (Error 13)
You could contemplate using a regex for this assessment or simply use something like the below?
ElseIf inp like "*-*" Then
Which would also do the trick?
The subsequent statement tries to select the Worksheet but that won't work as you have not set the ws object anywhere? So the below line is incorrect in many ways:
If Sheets(ws).Name = inp Then
Please see below code that will give you a good base to start from?
This would also get rid of the unnecessary inp = "#-#" comparison
Private Function SheetExists(name As String) As Boolean
SheetExists = False
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.name = name Then SheetExists = True: Exit Function
Next
End Function
Private Function ConfirmEndSub()
ConfirmEndSub = MsgBox("Do you really want to QUIT", vbYesNo + vbQuestion)
If ConfirmEndSub = vbYes Then
MsgBox "Thank You Goodbye"
End If
End Function
Sub InputValidation()
Dim str As String
Dim inp As String
Dim ws As Worksheet
str = MsgBox("Do you want to select a dataset (Yes) or a Graph (No)", vbQuestion + vbYesNo)
If str = vbYes Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
Reply = ConfirmEndSub
If Reply = vbYes Then Exit Sub
ElseIf SheetExists(inp) Then
Worksheets(inp).Activate
Else
MsgBox "This load and test cannot be found"
End If
ElseIf str = vbNo Then
inp = InputBox("Please enter a load value (10 or a load and trial (10-1)")
If StrPtr(inp) = 0 Then
Reply = ConfirmEndSub
If Reply = vbYes Then Exit Sub
End If
End If
End Sub
This leaves entirely out of consideration that depsite the initial vbYesNo answer the user will always get the input box? Not sure if that is the intention, but alas that is how it was written.
One other consideration is that if the user selects not to Quit, the call is not returning to the request for input? => I.e. it is still ending the routine...

For each code not making check box value true

I am trying to create code that runs through a list of user ID's (B Numbers) and then when it finds the corresponding ID it checks to see if there's an X in the column directly next to it for a certain subject named SBB005 See image. If there is an X, I want the check box value to be true. The for each loop ends when it reaches a blank cell.
I have declared the 'RowYear2' and 'Year2CourseRange' ranges as public variables, and when running the code, nothing happens and the check box remains unticked! Any idea why the checkbox isn't being ticked as expected?
I am planning on setting up multiple checkboxes once this is working for all the subjects in each column:
See image
Hoping that someone can help me to get this working or may even introduce an easier way to do so for another 20 checkboxes!
Many thanks :)
Private Sub UserForm_Initialize()
Set Year2CourseRange = Sheets("Year2").Range("A:A")
For Each RowYear2 In Year2CourseRange.Cells
If RowYear2.Value = BNumberTxt Then
If RowYear2.Offset(0, 1) = "x" Then
Me.CHKSBB005.value = True
Else
Me.CHKSBB005.value = False
End If
ElseIf IsEmpty(RowYear2) Then
Exit For
End If
Next RowYear2
LoggedInTxt = Row.Offset(0, -3)
BNumberTxt = Row.Offset(0, -7)
CourseTxt = Row.Offset(0, -1)
CourseNumTxt = Row.Offset(0, -2)
End Sub
Private Sub EnterBtn_Click()
Dim LIMatch As Boolean
Dim Win As Boolean
Email = Me.EmailTxt
Password = Me.PasswordTxt
Set UserRange = Sheets("StudentInformation").Range("H:H")
For Each Row In UserRange.Cells
If Me.EmailTxt = "" And Me.PasswordTxt = "" Then
MsgBox ("Please enter an email and password")
LIMatch = False
Win = True
Exit For
ElseIf Me.EmailTxt = "" Then
MsgBox ("Please enter an email address")
LIMatch = False
Win = True
Exit For
ElseIf Me.PasswordTxt = "" Then
MsgBox ("Please enter a password")
LIMatch = False
Win = True
Exit For
Else
If UCase(Row.Value) = UCase(Email) Then
If UCase(Row.Offset(0, -6)) = UCase(Password) Then
MsgBox "Welcome"
LIMatch = True
Win = True
Attempts = 0
Exit For
ElseIf IsEmpty(Row) Then
Exit For
Win = False
Else
LIMatch = False
Win = False
Exit For
End If
Else
LIMatch = False
Win = False
End If
End If
Next Row
If LIMatch = True And Win = True Then
Unload Me
NewForm.Show
ElseIf LIMatch = False And Win = False Then
MsgBox ("Incorrect login")
Attempts = Attempts + 1
Else
End If
If Attempts >= 3 Then
MsgBox ("You have entered the incorrect login 3 times")
Unload Me
End If
End Sub
Once you fix your problem with the Row global, you can do something like this:
Private Sub UserForm_Initialize()
Dim shtData As Worksheet
Dim Year2CourseRange As Range, HeaderRange As Range, m, c As Range
Set shtData = ThisWorkbook.Sheets("Year2")
With shtData
Set Year2CourseRange = .Range("A:A")
Set HeaderRange = .Range(.Range("B2"), .Cells(2, 500).End(xlToLeft))
End With
'you'll need to fix this part....
BNumberTxt = Row.Offset(0, -7)
'etc
'find a matching row: Match() is a good approach here
m = Application.Match(BNumberTxt, Year2CourseRange, 0)
'loop over all the column headers
For Each c In HeaderRange.Cells
'Assumes all checkboxes are named "CHK[ColumnHeaderHere]"
With Me.Controls("CHK" & c.Value)
If IsError(m) Then
.Value = False 'clear all if no match
Else
.Value = (UCase(shtData.Cells(m, c.Column)) = "X") 'set if "x"
End If
End With
End If
End Sub
Ranges and Ranges
This is your code squashed a little bit and below is your data:
Private Sub UserForm_Initialize()
Set Year2CourseRange = Sheets("Year2").Range("A:A")
For Each RowYear2 In Year2CourseRange.Cells
If RowYear2.Value = BNumberTxt Then
If RowYear2.Offset(0, 1) = "x" Then
Me.CHKSBB005.value = True
Else: Me.CHKSBB005.value = False: End If
ElseIf IsEmpty(RowYear2) Then
Exit For: End If: Next RowYear2
LoggedInTxt = Row.Offset(0, -3): BNumberTxt = Row.Offset(0, -7)
CourseTxt = Row.Offset(0, -1): CourseNumTxt = Row.Offset(0, -2): End Sub
Take a look for a while, you might see the error yourself.
The CheckBox Tick Mystery
When you write Range("A:A") that refers to the whole column including Range("A1") which appears to be EMPTY. The code never even enters the If RowYear2.Offset... line but exits via the ElseIf line.
The Row Variable
I hate the idea of declaring a variable Row. But it is valid. Since there is an Offset involved, Row should be a range, probably a cell. As in the comments indicated, it has to 'survive' from another UserForm let's say UserFormX. If it has 'survived' you have to refer to it like this:
UserFormX.Row
or you have to declare it in a 'not-object' module to use only Row.
Another EnterBtn_Click
Probably useless now but here is the code I worked on the other day:
Option Explicit
Public intAttempts As Integer
Private Sub CancelBtn_Click()
Unload Me
End Sub
Private Sub EnterBtn_Click()
Const strEmail = "Please enter email address." ' Email Input Message
Const strPassword = "Please enter a password." ' Password Input Message
Const strLoginCorrect = "Welcome" ' Correct Login Message
Const strLoginIncorrect = "Incorrect Login." ' Incorrect Login Message
Const strAttempts = "Too many login attempts." ' Login Attempts Message
' Use worksheet name or index e.g. "SInfo" or 1.
Const vntWsName As String = "StudentInformation" ' Worksheet
' Use column letter or column number e.g. "F" or 6.
Const vntEmailColumn As Variant = "F" ' Email Column
Const intFirstRow As Integer = 2 ' Email Column First Row
Const intPasswordColumnOffset As Integer = -4 ' Password Column Offset
Const intMaxAttempts As Integer = 3 ' Maximum Login Attempts
Dim lngCounter As Long ' Email Column Row Counter
Dim lngLastrow As Long ' Email Column Last Row
' Check number of login attempts.
If intAttempts >= intMaxAttempts Then
MsgBox strAttempts
Exit Sub
End If
' Show annoying text messages if nothing was entered.
If Me.EmailTxt.Text = "" Then
Me.EmailTxt.Text = strEmail: Exit Sub
ElseIf Me.EmailTxt.Text = strEmail Then Exit Sub
End If
If Me.PasswordTxt.Text = "" Then
Me.PasswordTxt.Text = strPassword: Exit Sub
ElseIf Me.PasswordTxt.Text = strPassword Then Exit Sub
End If
' Check for data in specified worksheet.
With ThisWorkbook.Worksheets(vntWsName)
' Determine last row of data in Email Column.
lngLastrow = .Cells(Rows.Count, vntEmailColumn).End(xlUp).Row
For lngCounter = intFirstRow To lngLastrow
' Ceck for email in Email Column.
If UCase(.Cells(lngCounter, vntEmailColumn).Value) _
= UCase(EmailTxt.Text) Then ' Correct email.
' Check if correct password in Password Column
If UCase(.Cells(lngCounter, vntEmailColumn) _
.Offset(0, intPasswordColumnOffset).Value) _
= UCase(PasswordTxt.Text) Then ' Correct password.
Exit For
Else ' Wrong password. Set "counter" to "end".
' Faking that the loop was not interrupted.
lngCounter = lngLastrow
End If
' Else ' Wrong Email. Do nothing. Not necessary.
End If
Next
' When the loop wasn't interrupted, "lngcounter = lnglastrow + 1".
End With
' Check if loop was NOT interrupted.
If lngCounter = lngLastrow + 1 Then ' Loop was NOT interrupted.
intAttempts = intAttempts + 1
MsgBox strLoginIncorrect
Else ' Loop was interrupted. Correct email and password.
MsgBox strLoginCorrect
Unload Me
NewForm.Show
End If
End Sub

Way to not use goto loops in vba msgbox

I am trying to find a way to avoid using GoTo loops in VBA as i understand they can lead to serious confusion and issues. I have a user InputBox, where the user defines a variables, currently on the if statement there are 3 options, if = Y ElseIf = N and else GoTo Start.
However this works great for the case where the user mistypes the variable i.e Y# etc, but i currently run into issues when the user wants to close the input box i.e clicks cancel or the cross.
So i was wondering if there is a more elligent solution to this or am I stuck with this hicup?
My code is below, this is only a test set used to test this new feature i am adding to my main code.
Sub MsgBox_Test ()
Dim TestVariable As String
VariableEntrey: TestVariable = InputBox(" Y or N")
If TestVariable = "Y" Or TestVariable = "y" Then
MsgBox ("Yeyy")
ElseIf TestVariable = "N" Or TestVariable = "n" Then
MsgBox ("Awww")
Else: GoTo VariableEntrey
End If
End Sub
Thanks for any help you are able to provide
You can try a Do... Loop Until construct that just repeats until you get an acceptable answer. For example:
Sub GetAnswer()
Dim strAnswer As String
Do
strAnswer = InputBox("Y or N")
Loop Until strAnswer Like "[YyNn]"
MsgBox "Thanks for your answer of: " & strAnswer
End Sub
See the docs on the Like operator to prevent having to check individually for y, Y, n and N.
Option Explicit
Sub MsgBox_Test()
Dim TestVariable As String
Dim done As Boolean
Do
TestVariable = InputBox(" Y or N")
done = True ' preload exit value
If LCase(TestVariable) = "y" Then
MsgBox ("Yeyy")
ElseIf LCase(TestVariable) = "n" Then
MsgBox ("Awww")
ElseIf Len(TestVariable) > 0 Then
done = False ' abort exit
End If
Loop Until done
End Sub
I would use a MsgBox instead of an InputBox.
Sub GetYesNo()
Dim answer As VbMsgBoxResult
answer = MsgBox("Yes or No?", vbYesNo)
If answer = vbYes Then
'do something
Else
'do something else
End If
End Sub
You could use Do >> Loop Until loop, to remove the GoTo.
Also, you can use UCase(TestVariable) to remove the Or from your Ifs.
Sub MsgBox_Test()
Dim TestVariable As String
Do
TestVariable = InputBox(" Y or N")
If UCase(TestVariable) = "Y" Then
MsgBox ("Yeyy")
ElseIf UCase(TestVariable) = "N" Then
MsgBox ("Awww")
End If
Loop Until UCase(TestVariable) Like "[YN]"
End Sub
You could try with Do .... Loop here:
Edit: plus limitation for single character or empty input
Dim TestVariable As String
TestVariable = InputBox(" Y or N")
Do While (TestVariable = "N" Or TestVariable = "n" or Len(TestVariable) > 1)
MsgBox ("Awww")
TestVariable = InputBox(" Y or N")
Loop
If TestVariable = "Y" Or TestVariable = "y" Then
MsgBox ("Yeyy")
End if

Using a formula in a sub

My original question was how to use a function's output in an if-->then statement, and Shai's help was very helpful (here: Using an output of aformula in another).
What I would like to do now, though, is to use this function in a sub. So I have this sub (which is not complete for now):
Private Sub CommandButto1_click()
Dim answer As Integer
Dim Response As VbMsgBoxResult
Dim late As VbMsgBoxResult
answer = MsgBox("Price for only one product?", vbYesNoCancel + vbQuestion, "Payment")
If answer = vbYes then
late = MsgBox("Is the customer late and has to be charged extra?", vbQuestion + vbYesNoCancel)
If late = vbYes then
MsgBox "mergesize function here"
End If
End If
End Sub
It works fine as it is, but where it says - MsgBox "mergesize function here" is where I would like to add my function that looks like this:
Public Function MergeSize(r As Range) As Long
MergeSize = r(1).MergeArea.Cells.Count
If MergeSize <= 10 Then
MergeSize = MergeSize * 70
Else
MergeSize = MergeSize * 65
End If
End Function
Another side question is can I send the output of the function to null and have it only displayed in a msgbox?
Try something like the code below.
Iv'e marked where I added the code that calls the Function MergeSize. I've used Range("B2") as the Merged Range.
Code
Private Sub CommandButto1_click()
Dim answer As Integer
Dim Response As VbMsgBoxResult
Dim late As VbMsgBoxResult
answer = MsgBox("Price for only one product?", vbYesNoCancel + vbQuestion, "Payment")
If answer = vbYes Then
late = MsgBox("Is the customer late and has to be charged extra?", vbQuestion + vbYesNoCancel)
If late = vbYes Then
'===== Added the 3 lines below =====
Dim ExtraCharge As Long
ExtraCharge = MergeSize(Range("B2")) '<-- Range("B2") is a Merged Cells
' === Ver 2.0 - to use with ActiveCell ===
ExtraCharge = MergeSize(ActiveCell) '<-- ActiveCell is a Merged Cells
MsgBox "Extra Charge is " & ExtraCharge
End If
End If
End Sub

Resources