Excel VBA Textbox time validation to [h]:mm - excel

I am developing a VBA Excel Userform and need to enter a time in the [h]:mm format. This means that the hours can be unlimited and does not cycle back to 0 after 23:59 like the hh:mm format does. I have searched the web to no avail.
Here is the code I'm currently using:
Private Sub Txtbx_TimeAvailable_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Me.Txtbx_TimeAvailable.Value <> Format(Me.Txtbx_TimeAvailable.Value, "[h]:mm") Then
MsgBox "Please enter correct time format in hh:mm"
Cancel = True
Me.Txtbx_TimeAvailable.Value = vbNullString
Else
ThisWorkbook.Sheets(SELECTEDWORKSHEET).Range("C60").Value = Txtbx_TimeAvailable.Text
Call UpdateDentistMainForm
End If
End Sub
However, when using this code if I enter 25:53 it converts it to 01:53. I'd appreciate any help I could get on this.

You will need to parse the validity manually, here is one way:
Var = "59:59"
Dim IsValid As Boolean
Dim tok() As String: tok = Split(Var, ":")
If (UBound(tok) = 1) Then
'// `like` to prevent lead +/-
IsValid = tok(0) Like "#*" And IsNumeric(tok(0)) And tok(1) Like "#*" And IsNumeric(tok(1)) And tok(1) < 60
'// optionally normalize by removing any lead 0
Var = Val(tok(0)) & ":" & Val(tok(1))
End If
Debug.Print Var, IsValid

Related

Workbook reference via VBA doesn't accept variable

I am trying to set up references to other workbooks, whereby the location is static: G:\XY\XY\[Workbook2019.xlsx]2019-04'!C1
Since these references change depending on what month it is, I want, for ease of use, set up an input-box where one can type in a number like 01 or 04 and it would exchange the month part in the reference.
My code looks like this so far:
Sub MonthRef()
Dim strMonth As String
strMonth = InputBox("Enter month as interger (e.g. 01 for Jan; 02 for Feb.)", "Month")
Range("B4").Formula = "='G:\XY\[XY.xlsx]2019-" & strMonth & " '!C1"
End Sub
weirdly enough, I seem to get the correct reference, but the cell wont accept the number for some reason and prompts me to select one of the sheets from a workbook.
I cannot seem to find the problem.
Any help is greatly appreciated!
Personally I'd flesh this out a little further to avoid other mistakes from user input as well. This can be done by using a function to test the user input is the correct criteria and looping until either it is, or the user cancels
Private Function TestUserInput(v As String) As Boolean
TestUserInput = False
If IsNumeric(v) And Len(v) <= 2 Then
If CLng(v) > 0 And CLng(v) <= 12 Then
TestUserInput = True
End If
End If
End Function
Public Sub MonthRef()
Dim strMonth As String
Dim IsUserInputValid As Boolean
Dim InputBoxPrompt As String
InputBoxPrompt = "Enter month as integer (e.g. 01 for Jan; 02 for Feb.)"
Do
strMonth = Trim(InputBox(InputBoxPrompt, "Month"))
' Test if strMonth is valid
IsUserInputValid = TestUserInput(strMonth)
' Handle User cancelled
If strMonth = vbNullString Then
Exit Sub
' If input is not valid then prompt user
ElseIf IsUserInputValid = False Then
MsgBox prompt:="Input not valid. " & InputBoxPrompt, Title:="Error"
End If
' Loop until input is valid or User cancels
Loop Until IsUserInputValid
Range("B4").Formula= "='G:\XY\[XY.xlsx]2019-" & Format(strMonth, "00") & "'!C1"
End Sub

Restrict Userform Textbox input to [H]:MM

I have multiple textboxes on multiple userforms that are for time allocations. For simplicity say userform1 & userform2, with textbox1 & textbox2 on each.
Userform1 is for user input, which places values into a table and userform2 pulls the values from this table and displays in the relevant textbox. I need to restrict both the input of these boxes and the display to the [H]:mm format where minutes cannot exceed 59 but hours can be 25+ i.e 125:59 but not 4:67
I tried a combination of code from both of these threads as well as others but can't seem to get it to work.
Excel VBA Textbox time validation to [h]:mm
Time format of text box in excel user form
eventually i just tried to manipulate user input with message boxes but this still leaves entries open to error
Sub FormatHHMM(textbox As Object)
Dim timeStr As String
With textbox
'Check if user put in a colon or not
If InStr(1, .Value, ":", vbTextCompare) = 0 And Len(.Value) > 1 Then
MsgBox "Please use HH:mm Format"
textbox.Value = ""
textbox.SetFocus
Else
If Right(.Value, 2) > 60 Then
MsgBox "Minutes cannot be more than 59"
textbox.Value = ""
textbox.SetFocus
End If
End If
End With
End Sub
this allows users put alpha characters in and even if correctly input when called from the table is shows as a value instead i.e 5.234... instead of 125:59
How about you split hours and minutes into two seperate input fields on the same inputbox.
So the user has to type in hours and in the next field minutes. This way you can check the input for isnumeric and >60 for seconds.
I know this is not ideal, but it would be a way to evade the given problems.
Have you tried using the Like operator? That allows checking for numeric values in each character-position. I would do it like this:
Function FormatCheck(ByVal strEntered As String)
Dim correctformat As Boolean
If strEntered Like "*#:##" And IsNumeric(Mid(strEntered, 1, InStr(1, strEntered, ":", 1) - 1)) Then
If Mid(strEntered, InStr(1, strEntered, ":", 1) + 1, 999) <= 59 Then
correctformat = True
End If
End If
If Not correctformat Then FormatCheck = "Incorrect format"
End Function
This requires at least one number before the ":"
Edit: Below is a Sub version instead of using a Function. This will pop up a MsgBox like you were using originally. You could probably replace your whole FormatHHMM sub with this without any adverse effect.
Sub FormatCheck(ByVal strEntered As String)
Dim correctformat As Boolean
If strEntered Like "*#:##" And IsNumeric(Mid(strEntered, 1, InStr(1, strEntered, ":", 1) - 1)) Then
If Mid(strEntered, InStr(1, strEntered, ":", 1) + 1, 999) <= 59 Then
correctformat = True
End If
End If
If Not correctformat Then MsgBox "Incorrect format"
End Sub
i think this may be helpful:
Option Explicit
Sub test()
Dim str As String
str = TextBox.Value
'Test string lenght. Maximun lenght number 4
If Len(str) <> 4 Then
MsgBox "Enter a valid time. Proper number of digits are 4."
Exit Sub
End If
'Test if string includes only one ":"
If (Len(str) - Len(Replace(str, ":", ""))) / Len(":") <> 1 Then
MsgBox "Use only one "":"" to separate time."
Exit Sub
End If
'Test how many digits are before and after ":"
If InStr(1, str, ":") <> 2 Then
MsgBox """:"" position should be place 2."
Exit Sub
End If
'Test if number 1,3 & 4 are number
If IsNumeric(Mid(str, 1, 1)) = False Or IsNumeric(Mid(str, 1, 1)) = False Or IsNumeric(Mid(str, 1, 1)) = False Then
MsgBox "Enter number in position 1,3 and 4."
Exit Sub
End If
'Test 2 last to digits
If Right(str, 2) <= 60 Then
MsgBox "Second limit is 60."
Exit Sub
End If
End Sub
You could use regular expressions :
Sub inputTimeFormat()
Dim userInput As String
Dim strPattern As String
Dim msgBoxText As String
Dim regEx As New RegExp
Dim objRegex As Object
strPattern = "(^[0-9]+):([0-5])([0-9])$"
msgBoxText = "Insert time in HH:mm, or hit Cancel to escape"
Set objRegex = CreateObject("vbscript.regexp")
With regEx
.ignorecase = True
.Pattern = strPattern
Do
If userInput <> vbNullString Then msgBoxText = "PLEASE RETRY" & Chr(13) & msgBoxText
userInput = Application.InputBox(msgBoxText, Default:="17:01")
If userInput = "False" Then
MsgBox "User hit cancel, exiting code", vbCritical
Exit Sub
End If
Loop Until .Test(userInput)
End With
MsgBox "Format OK"
End Sub
(you need to activate regular expressions : in VBA, "Tools" > "References" > Check the box "Microsoft VBScript Regular Expressions 5.5" > "OK")
More details on How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops

Stop changing date value in VBA

Excel keeps changing my date to US format. I have a user form where the user inputs a date. As an example, I enter 01/11/2018 (1st November 2018). I then put this value into a cell however it changes automatically to 11/01/2018 or 11th January 2018.
I've so far tried using the following code to force it to use UK format;
SHT_data_TASKS.Cells(1 + tableRows, 8).NumberFormat = "dd/mm/yyyy;#"
SHT_data_TASKS.Cells(1 + tableRows, 8) = form_addTask_Date.Value
But it does not help. I've also tried using CDate function but still no luck. I've checked my computer regional settings and they are all correct for the UK.
If I right click on the cell where the date is placed and chose format it shows as already being formatted to UK date! I'm not sure what is causing it to change.
This is the date code I use on control containing UK dates:
Private Sub UserForm_Initialize()
Me.txtDate = Format(Date, "dd-mmm-yyyy")
End Sub
On the AfterUpdate event for the date control:
Private Sub txtDate_AfterUpdate()
With Me
FormatDate .txtDate
End With
End Sub
In a normal module:
Public Sub FormatDate(ctrl As Control)
Dim dDate As Date
Dim IsDate As Boolean
If Replace(ctrl.Value, " ", "") <> "" Then
On Error Resume Next
dDate = CDate(ctrl.Value)
IsDate = (Err.Number = 0)
Err.Clear
On Error GoTo 0
If IsDate Then
ctrl.Value = Format(ctrl.Value, "dd-mmm-yyyy")
ctrl.BackColor = RGB(255, 255, 255)
Else
ctrl.BackColor = RGB(255, 0, 0)
End If
End If
End Sub
Then I transfer it to the worksheet (on a Save button) using the below code:
shtRawData.Cells(rLastCell.Row, CLng(lCol)) = CDate(ctrl.Value)
When you're about to write your date to the sheet:
Verify that it's being stored as a date (or date equivalent) with isdate()
Assign it via Range.FormulaLocal instead of value or value2.
Untested, but i.e.
Range("A1").FormulaLocal = #10/31/2018#

Compress multiple OR-conditions in VBA code

I use the following code to allow users to write a value into Cell A1.
Sub TestUsername()
If Environ("Username") = "firstname1.lastname1" Or Environ("Username") = "firstname2.lastname2" _
Or Environ("Username") = "firstname3.lastname3" Or Environ("Username") = "firstname4.lastname4" Then
Sheet1.Range("A1").Value = 1
Else
Sheet1.Range("A2").Value = 2
End If
End Sub
As you can see I list each user who is allowed to enter a value into Cell A1 with an OR-condition in my VBA code. All this works fine.
Now, I was wondering if there is an easier way to do this. Something like this:
Sub TestUsername()
If List of or-conditions: {"firstname1.lastname1", "firstname2.lastname2", _
"firstname3.lastname3", "firstname4.lastname4"} = True Then
Sheet1.Range("A1").Value = 1
Else
Sheet1.Range("A2").Value = 2
End If
End Sub
I just know in PHP you can compress multiple conditions like here. Therefore, I thought this might also be possible for VBA programming.
Maybe something like this
Sub TestUsername()
Select Case Environ("Username")
Case "firstname1.lastname1", "firstname2.lastname2", "firstname3.lastname3"
Sheet1.Range("A1").Value = 1
Case Else
Sheet1.Range("A2").Value = 2
End Select
End Sub
I suppose, if you had an atrocious amount of conditions, you could stick them in an array and then simply replace your conditional statement
If Environ("Username") = "firstname1.lastname1" Or Environ("Username") = "firstname2.lastname2" _
Or Environ("Username") = "firstname3.lastname3" Or Environ("Username") = "firstname4.lastname4" Then
with this
If IsInArray(Environ("Username"), arr) Then
This does require that you dimension an array with the conditions first and use this function, however:
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
Dim i
For i = LBound(arr) To UBound(arr)
If arr(i) = stringToBeFound Then
IsInArray = True
Exit Function
End If
Next i
IsInArray = False
End Function
This way, your code becomes much more readable and easy to maintain.
Since you're working in a cell, you might want to define the allowed usernames within the spreadsheet.
Here's how the spreadsheet table might look:
And here's the code you might use:
Sub TestUsername()
Dim username As String
Dim userInTable As Integer
Dim allowedUserRange As Excel.Range
username = Environ("username")
Set allowedUserRange = Excel.Range("tUsers")
userInTable = Excel.WorksheetFunction.CountIf(allowedUserRange, username)
If userInTable Then
Sheet1.Range("A1").Value = 1
Else
Sheet1.Range("A1").Value = 2
End If
End Sub
The Select Case provides a great solution to testing multiple conditions at the same time. I am using this to alert the user when they have not furnished all the required inputs. I am monitoring inputs from a number of Drop Down Boxes as well as some direct cell inputs.
Select Case True
Case Range("Customer_DD_Control_Cell") > 0 _
And Range("Dealer_DD_Control_Cell") > 0 _
And Range("Rep_DD_Control_Cell") > 0 _
And Range("Product_DD_Control_Cell") > 0 _
And Len(Range("Customer_State_Input")) > 0 _
And Len(Range("Contract_Date_Input")) > 0
Case Else
MsgBox "You have not completed the required inputs"
End Select

Excel VBA Textbox resets to 0 when i press a button

i have a userform with 2 textboxes, 2 labels and a log in button.
On my excel sheet i have a sort of database with id, name, pin and balance.
the problem is whenever i click the login button my ID textbox resets its value to 0, but my pin textbox works fine!
i will paste my complete code:
Dim ID As Integer
Dim PIN As Integer
Dim PINField As String
Dim Balance As Double
Dim Attempts As Integer
Dim BalanceField As String
Private Sub btnLogin_Click()
txtID.Text = ID
Call SetId
Call Authenticate
End Sub
Sub Authenticate()
If txtPin.Text = PIN Then
Call Welcome
ElseIf Attempts > 3 Then
Call Bye
Else
lblWelcome.Caption = "Wrong Pin"
lblWelcome.ForeColor = RGB(255, 0, 0)
Attempts = Attempts + 1
End If
End Sub
Sub SetId()
PINField = "C" & Str(ID)
PINField = Replace(PINField, " ", "")
MsgBox (PINField)
BalanceField = "D" & Str(ID)
BalanceField = Replace(BalanceField, " ", "")
MsgBox (BalanceField)
End Sub
Sub Welcome()
MsgBox ("Login Successful. Welcome")
End Sub
Sub Bye()
MsgBox ("Max Pin Attempts reached. Contact Your Bank")
Unload frmLogin
End Sub
The reason it does this is because you are using a variable which has no value. Since it is an Integer it returns 0.
I'm guessing you probably actually want to have ID = txtID.Text - that is, take the value of the txtID textbox and store the value in the ID variable.
This will probably error though because the Text property of a textbox is a String. You will need to use ID = CInt(txtID.Text). You should also do some checking to make sure that txtID.Text evaluates to an Integer before assignment.
Please make sure there's no reset for the txtID anywhere in the code that you have not shown here. Looking at your code, it doesn't say anything how you are setting values to either ID or PIN... You said it's working fine for PIN, so it makes me very curious...
It could be the case Nick pointed out given this is a Form with textboxes allowing people to enter ID and PIN.. And then you are comparing it against PIN. But what are you comparing against? As you said you have a database kind of a structure in the sheet. You need to assing ID and PIN using it.
Here is the visualization I have for your Sheet, which is my best blind guess:
User needs to enter a value via the Form into txtID. That number is infact the cell number for column C which contains the relevant PIN. Then you compare that PIN with the txtPIN value. Next return the balance from column D based on that PIN.
Try this:
Private Sub btnLogin_Click()
If txtID.Text <> "" Or txtID.value > 0 or txtPIN.Text <> "" Then
ID = CInt(txtID.Text)
Call SetID
Call Authentication
Else
MsgBox "ID and PIN" can't be empty!"
End If
End Sub
Sub Authenticate()
If CInt(txtPin.Text) = PIN Then '-- here
Call Welcome
'-- idealy Blance can be shown at this point...
ElseIf Attempts > 3 Then
Call Bye
Else
lblWelcome.Caption = "Wrong Pin"
lblWelcome.ForeColor = RGB(255, 0, 0)
Attempts = Attempts + 1
End If
End Sub
Sub SetId()
PIN = CInt(Trim(Sheets(1).Range("C" & ID).value))
'-- NOT sure why you are showing this PIN here since you want to authenticate...?
MsgBox PIN
BalanceField = Sheets(1).Range("D" & ID).value
BalanceField = Trim(BalanceField) '--here
'-- doesn't make sense to show Balance before authentication...
MsgBox BalanceField
End Sub
Trim is clearner and faster than Replace..

Resources