VBA : InputBox wrongly used previous User Input without prompting for new input - vba

This is the VBA code I am learning to write (got some reference from the Internet)
Public whatyousay As String
Sub testing()
b14
b15
End Sub
Function WorksheetExists(WSName As String) As Boolean
On Error Resume Next
WorksheetExists = Worksheets(WSName).Name = WSName
On Error GoTo 0
End Function
Sub b14()
Dim sh As Worksheet
Do Until WorksheetExists(whatyousay)
whatyousay = InputBox("Enter sheet name")
If Not WorksheetExists(whatyousay) Then MsgBox whatyousay & " doesn't exist.", vbExclamation
Loop
If WorksheetExists(whatyousay) Then Sheets(whatyousay).Activate
End Sub
Sub b15()
ThisWorkbook.Worksheets(whatyousay).Range("A1").Value = xxxx
End Sub
I must have wrongly adjust the code, as I can't find anyone having the same problem on the Internet.
When the button is clicked, it is supposed to prompt user input for the sheet name, then perform some actions.
Now, the problem I am facing is that the button only prompt user input for one time. If it was clicked the second time, it will used the previous user input without prompting.
Can anyone of you please point me to the right direction?

You are not erasing what was left in whatyousay during the last loop.
Sub b15()
ThisWorkbook.Worksheets(whatyousay).Range("A1").Value = xxxx
whatyousay = vbnullstring '<~~ remove the string from last time
End Sub
Personally, I avoid public vars. You can do the same thing by passing the string var into the secondary sub as a parameter.

Related

xlDialogSaveAs - End ALL code if "cancel" is selected

EDIT: I figured it out myself. I feel pretty silly, but replacing "Exit Sub" with "End" works perfectly.
Background: I have a Sub that uses the "Call" function to run multiple subs within one Sub (see Code #1 below).
Option Explicit
Sub MIUL_Run_All()
Dim StartTime As Double
Dim SecondsElapsed As String
'Remember time when macro starts
StartTime = Timer
Call OptimizeCode_Begin
Call Format_MIUL
Call Custom_Sort_MIUL
Call Insert_Process_List
Call Format_Process_List
Call OptimizeCode_End
'Determine how many seconds code took to run
SecondsElapsed = Format((Timer - StartTime) / 86400, "ss")
'Notify user in seconds
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub
My first code that is called out, "Format_MIUL", prompts the user to save the file, using the following line of code (see Code #2 below). This code works, but the problem is that if the user presses the "Cancel" button, the rest of the code called out in the main sub (Code #1 above) will continue to run. I want ALL code to stop if the user presses the cancel button. I just can't seem to figure out how to do that.
'Save file as .xlsm
MsgBox " Save as Excel Workbook (.xlsx)!"
Dim userResponse As Boolean
On Error Resume Next
userResponse = Application.Dialogs(xlDialogSaveAs).Show(, 51)
On Error GoTo 0
If userResponse = False Then
Exit Sub
Else
End If
Any help is greatly appreciated.
The Call keyword has been obsolete for 20 years, you can remove it.
The End keyword will effectively end execution, but it's pretty much a big red "self-destruct" button that you effectively never need to use, given properly structured code.
Looks like Format_MIUL is a Sub procedure. Make it a Function and return a Boolean value that tells the caller whether it's ok to proceed, or if the rest of the operations should be cancelled:
Private Function Format_MUIL() As Boolean
'...
'Save file as .xlsm
MsgBox " Save as Excel Workbook (.xlsx)!"
Dim userResponse As Boolean
On Error Resume Next
userResponse = Application.Dialogs(xlDialogSaveAs).Show(, 51)
On Error GoTo 0
'return False if userResponse isn't a filename, True otherwise:
Format_MUIL = Not VarType(userResponse) = vbBoolean
End Function
And now instead of this:
Call Format_MIUL
The caller can do this:
If Not Format_MIUL Then Exit Sub
And there you go, graceful exit without any self-destruct buttons pressed.

VBA User form gives warning if duplicate is found

I think I need to try and make this question easier. So here goes;
I am creating a User form in Excel that will act as a data capture form.
In this form I have a Textbox called PolBX In this a is placed and at submission data in PolBX is copied into the "G" column using this code
Cells(emptyRow, 7).Value = PolBX.Value. This works great.
I discovered that there may be instances where the User may accidently use the same Unique Id number twice. so I am trying to find out how to code it that after the User has entered the Unique Id number it would check for that string (Consists of letters and numbers). if it finds the string already in the 7th column(G) it must say something like
"Policy number already Used, please try again"
I am thinking I will need to use the following subroutine
Private Sub PolBX_AfterUpdate()
End Sub
Can some please assist with creating this code...
Also can you please explain what you are doing as I started VBA about a week ago
You can add the following code to search for your policy number, and if nothing found then PolLookup = Nothing.
Option Explicit
Sub Test()
On Error GoTo ErrHandler
Dim ws As Worksheet, PolLookup As Range, LookupRng As Range
Set ws = ThisWorkbook.Worksheets(1)
'This is the range you want to search, it can be a long range
'or it can be a single cell.
Set LookupRng = ws.Range("A:A")
'Range.Find is looking for your value in the range you specified above
Set PolLookup = LookupRng.Find("YourLookupValue")
'PolLookup = Nothing if it didn't find a match, so we want to use
'If <NOT> Nothing, because this suggests .Find found your value
If Not PolLookup Is Nothing Then
Err.Raise vbObjectError + 0 'Whatever error you want to throw for finding a match
End If
'Exit before you reach the ErrHandler
Exit Sub
ErrHandler:
If Err.Number = vbObjectError + 0 Then
'Handle your error. Do you want to stop completely? Or have the
'User enter a new value?
End If
End Sub
Basically, after your user enters their value in your UserForm, just make a call to this Sub to do a quick lookup.
Playing around I discovered a Much easier way! I included a Button with he following code attached
Private Sub CommandButton8_Click()
Search = PolBX.Text
Set FoundCell = Worksheets("sheet1").Columns(7).Find(Search,LookIn:=xlValues, lookat:=xlWhole)
If FoundCell Is Nothing Then
MsgBox "No duplicates found"
Else
MsgBox "This policy has already been Assessed" & "Please assess a different case"
PolBX.Value = ""
End If

VBA excel printing to printer with user form

I have a userform, that when filled out, has a command button at the bottom. When the button is clicked, it copies the data to worksheet2, and then copies the row information into worksheet 4, which is a form, closes the userform.and opens up the welcome userform then i want it to print worksheet4.
Here is the code I have. The print function will not work.
Private Sub SavePrintButton_Click()
EditAdd
Sheet4.Activate
Dim myValue As Variant
myValue = TextBox1.Value
Range("b2").Value = myValue
Unload Me
Function PrintOneSheet()
Sheets("Sheet4").PrintOut
End Function
WelcomeUserForm.Show
End Sub
Your "PrintOneSheet" function is embedded in SavePrintButton_Click. Move the "end sub" after "unload me" and insert "call PrintOneSheet" above "unload me". I've taken the liberty of adding a "Me.Hide" line since you apparently want the current form to go away before you show WelcomeUserForm. It still gets unloaded once it's not needed. Meantime if for any reason you want to go back to it to correct something, you can do so by simply showing it again.
Private Sub SavePrintButton_Click()
Dim myValue As Variant
EditAdd
Sheet4.Activate
myValue = TextBox1.Value
Sheet4.Range("b2").Value = myValue
Call PrintOneSheet
Me.Hide
WelcomeUserForm.Show
Unload Me
End Sub
Function PrintOneSheet()
Sheets("Sheet4").PrintOut
End Function
On another note, is Sheet4 always going to be called "Sheet4"? Sheet4 is a direct call to the object id, "Sheet4" is a call to one of its properties (its name). You should be consistent in your references or someday you'll change something apparently minor and chaos will break loose.
I have reworked the code a bit. Does this look more like it should? I got rid of all unload.me in my vba.
Private Sub SavePrintButton_Click()
EditAdd
Sheet6.Activate
Dim myValue As Variant
myValue = TextBox1.Value
Range("b2").Value = myValue
ClearForm
Me.Hide
Sheet6.PrintOut
WelcomeUserForm.Show
MsgBox "New Run Added"
MsgBox "Run Sent to Printer"
End Sub

Excel VBA UserForm 'OK'

Does anyone know how to make a userform function in the same way as the Message Box 'ok' button? I'll explain.
I'm detecting errors in a column in a spreadsheet. When an error is found, a message box pops up as follows:
MsgBox "Please enter valid data"
When I select "OK" it goes to the next error in the column. This is great, except of course a message box is modal, which freezes the application. I want the user to be able to edit the data and then move to the next error. So, I designed a userform, which can be non-modal. Great, except I want the macro to advance to the next error. It will do that IF the user corrects the error. If they do not, it just stays at that error cell.
I know WHY this happens. My userform 'Next' button just calls the macro which finds the first error. But what I want to know is if there is a way around this.
Error checking starts at row 19 because that is where user input data starts.
I'm including a link to the spreadsheet here. Module 1 'NextValidationError' works great and proceeds to the next error. Module 14 just hangs at the error until it is resolved. I'd like it to be able to skip.
https://www.dropbox.com/s/yqko5kj19pnauc9/Transparency%20Data%20Input%20Sheet%20for%20Indirect%20Spend%20V7%2009212016%20v2%200.xlsm?dl=0
Can anyone give me advice on how to make module 14 proceed as module 1?
Something like this:
Dim r_start As Long
Sub CheckNames()
Dim r As Long
'Dim emptyRow As Boolean
If r_start = 0 Then r_start = 19
With ActiveSheet
For r = r_start To 5000
'Checks entire row for data. User may skip rows when entering data.
If WorksheetFunction.CountA(.Range(.Cells(r, 1), .Cells(r, 33))) > 0 Then
If ((.Cells(r, 2) = "") <> (.Cells(r, 3) = "")) Or _
((.Cells(r, 2) = "") = (.Cells(r, 4) = "")) Then
MsgBox "Please fill in First and Last Name or HCO in Row " & r & "."
End If
End If
Next
End With
End Sub
Unless I'm mis-reading your code you can combine your two checks with Or.
You will need some method to reset r_start when the user is done checking (if the form stays open after that).
EDIT: here's a very basic example.
UserForm1 has two buttons - "Next" and "Close"
Code for "next" is just:
Private Sub CommandButton1_Click()
ShowErrors
End Sub
In a regular module:
Dim r_start As Long
'this kicks off the checking process
Sub StartChecking()
r_start = 0
UserForm1.Show vbModeless
ShowErrors
End Sub
'a simple example validation...
Sub ShowErrors()
Dim c As Range, r As Long
If r_start = 0 Then r_start = 9
For r = r_start To 200
With ActiveSheet.Rows(r)
If Not IsNumeric(.Cells(1).Value) Then
UserForm1.lblMsg.Caption = "Cell " & .Cells(1).Address() & " is not numeric!"
r_start = r + 1
Exit Sub
End If
End With
Next r
r_start = 0
UserForm1.lblMsg.Caption = "No more errors"
End Sub

VBA Error 1004 When Calling A Module with an Argument

This is my first post so bear with me.
I get a run-time error 1004 when I try calling a module from my user form and passing on an argument. I'm sure the answer is pretty obvious but I'm new to passing on arguments.
From User Form when clicking submit button:
Sub SubmitButton_Click()
Dim addRowValue As Integer
addRowValue = LineBox.Value
MsgBox "Add " & addRowValue & " rows."
Call Sheet1.ResizeTable(addRowValue)
End Sub
From Sheet1:
Sub ResizeTable(addRowValue As Integer)
Dim rng As Range
Dim tbl As ListObject
Set tbl = ActiveSheet.ListObjects("DATA_INPUT")
Set rng = Range("DATA_INPUT[#All]").Resize(tbl.Range.Rows.Count + _
addRowValue, tbl.Range.Columns.Count)
tbl.Resize rng
End Sub
Call Sheet1.ResizeTable works fine but when I add the argument is when I get the error. Also, the module ResizeTable() works fine when I change the variable addRowValue to a set number and run it.
Thanks for any help!
Problem is you are assigning a string to variable of type integer.
Change
addRowValue = LineBox.Value
To
addRowValue = CInt(LineBox.Value)
EDIT: You might also want to ensure the user enters a numeric value so have something like:
If IsNumeric(LineBox.Value) Then
addRowValue = CInt(LineBox.Value)
Else
MsgBox "Please enter numeric value", vbCritical
LineBox.Value = ""
End If