I am adding TextBoxes dynamically in a userform and want to make them a date format to ensure correct date entry. I am unable to find any examples.
Here is my code for the userform activation:
Private Sub TextBox3_Exit(ByVal Cancel As MSForms.ReturnBoolean)
fltDays = TextBox3.Value If TextBox3.Value = 0 Then Exit Sub
For i = 1 To fltDays
n = i - 1
Dim TextBox As Control
Set theLbl = FloatDayFrm.Controls.add("Forms.Label.1", "lbl_" & i, True)
With theLbl
.Caption = "Day " & i
.Left = 20
.Width = 60
.Top = n * 24 + 100
.Font.Size = 10
End With
Set TextBox = FloatDayFrm.Controls.add("Forms.TextBox.1", "TextBox_" & n, True)
With TextBox
.Top = 100 + (n * 24)
.Left = 90
.Height = 18
.Width = 50
.Name = "txtBox" & i
.Font.Size = 10
.TabIndex = n + 4
.TabStop = True
End With Next i
FloatDayFrm.Height = 150 + fltDays * 24 With btnOK .Top = 102 + fltDays * 24 .TabStop = True .TabIndex = n + 5 End With
With btnCancel .Top = 102 + fltDays * 24 '.TabStop = True .TabIndex = n + 6 End With
End Sub
This is my code for the Command button:
Private Sub btnOK_Click()
n = TextBox3.Value
For j = 1 To n
Set varFloatDay = FloatDayFrm.Controls("txtBox" & j)
Select Case varFloatDay
Case ""
MsgBox "Day " & j & " can't be blank", vbOKOnly, "Incorrect Value"
Exit Sub
Case Is > TextBox2.Value
MsgBox "Date is after end date", vbOKOnly, "Incorrect Value"
Exit Sub
Case Is < TextBox1.Value
MsgBox "Date is BEFORE end date", vbOKOnly, "Incorrect Value"
Exit Sub
End Select
Next j
End Sub
Any help would be appreciated.
You have to convert text to date format. You can use multiple approach.
Add a label beside textbox to display the format user has to specify the date. Parse the text specified by user as per the format. Do validation and conversion as shown in code below.
Use a calendar control instead of textbox as user input.
Have separate textboxes or cells for year, month and day. Do validation and conversion as shown in code below.
If you are sure date is in the specified format as per regional setting. Do validation and conversion as shown in code below.
Try below
Private Sub TestDate()
Dim yr As Integer
Dim mnth As Integer
Dim day As Integer
Dim dt As Date
Dim strDate As String
'''''3rd approach''''''
yr = ActiveSheet.Range("A1")
mnth = ActiveSheet.Range("B1")
day = ActiveSheet.Range("C1")
If IsNumeric(yr) And IsNumeric(mnth) And IsNumeric(day) Then
If yr < 0 Or mnth < 0 Or day < 0 Then
MsgBox "Year, Month and Day must be greater than 0."
Exit Sub
End If
Else
MsgBox "Year, Month and Day must be an integer."
Exit Sub
End If
'convert to Date
dt = DateSerial(yr, mnth, day)
'''''4th approach''''''
'Display a date according to your system's short date format
'i.e. regional settings in control panel
strDate = Format(ActiveSheet.Range("D1"), "Short Date")
If Not IsDate(strDate) Then
MsgBox "Incorrect Date Format"
Exit Sub
End If
dt = CDate(strDate)
End Sub
Any input in a text box is a text string. If you want it to be a date you can use IsDate(TextBox1.Value) to determine if VBA is able to convert the string to a date (which is a number of Double type). VBA will not execute this test 100% correctly, however. For example, it may not recognised 3/2/17 as a date if your regional settings have the date separator as a period. It may convert 3.2.17 to March 2 if your regional settings are mm.dd.yy. While working on your own PC you may be able to control the regional settings. But if your project will be released into the wild it is better to use a calendar control to get a correct date.
Related
I need my VBA user form to display the total price of the number of products selected.
Sorry guys this is my first time asking a question on SO, I am trying to build the userform as shown above.
I achieve almost everything except this TextBox total(Accessories total). Before I click the confirm booking button, if I add values in Accessories frame is it possible to update the total in TextBox (Accessories total)?
Below is my peace of code
'Column F(Racket Count) Enter No of rackets Taken
If IsNumeric(RacketCount) Then
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 5) = CInt(RacketCount)
Else
MsgBox "Please enter valid Number"
End If
'Column G(Shuttle Count) Enter No of Shuttle's Taken
If IsNumeric(ShuttleCount) Then
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 6) = CInt(ShuttleCount)
Else
MsgBox "Please enter valid Number"
End If
'Column H(Shoes Count) Enter No of Shoe's Taken
If IsNumeric(ShoesCount) Then
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 7) = CInt(ShoesCount)
Else
MsgBox "Please enter valid Number"
End If
'Column I(Socks Count) Enter No of Sock's Taken
If IsNumeric(SocksCount) Then
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 8) = CInt(SocksCount)
Else
MsgBox "Please enter valid Number"
End If
'Column J(Advance) Advance ON/OFF
If AdvanceOnOff = True Then
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 9) = "yes"
Else
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 9) = "No"
End If
'Column K(Racket Total *50) Total Amt for Rackest taken
Dim RacketsTotal As Integer
RacketsTotal = CInt(RacketCount) * Sheets("Inventory").Range("c2")
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 10) = RacketsTotal
'Column L(Shuttle total* 160) Total Amt for Shuttle's taken
Dim ShuttleTotal As Integer
ShuttleTotal = CInt(ShuttleCount) * Sheets("Inventory").Range("c3")
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 11) = ShuttleTotal
'Column M(Shoes Total * 50) Total Amt for Shoes's taken
Dim ShoesTotal As Integer
ShoesTotal = CInt(ShoesCount) * Sheets("Inventory").Range("c4")
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 12) = ShoesTotal
'Column N(Socks Total * 30) Total Amt for Socks's taken
Dim SocksTotal As Integer
SocksTotal = CInt(SocksCount) * Sheets("Inventory").Range("c5")
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 13) = SocksTotal
'Column O(Accessories Total) Total Accessories Amt
Dim AccTol As Long
AccTol = RacketsTotal + ShuttleTotal + ShoesTotal + SocksTotal
Sheets("DataEntry").Range("S.No").Offset(RowCountOffset, 14) = AccTol
AccessoriesTotalDisplay.Value = AccTol
Unload CourtBooking
MsgBox "Booking Entered Sucessfully"
End Sub
The idea is to make a function that counts the total accessories from the 4 Textbox and then assign AccessoriesTotalDisplay.Value to the function by using AccessoriesTotalDisplay.Value = GetTotalAccessories.
To make the calculation "real-time", you can insert that line into the 4 accessories' Change event as the code below shows:
Function GetTotalAccessories() As Long
Dim totalRacket As Long
Dim totalShuttle As Long
Dim totalShoes As Long
Dim totalSocks As Long
If IsNumeric(RacketsCount) Then
totalRacket = CLng(RacketsCount.Value)
Else
totalRacket = 0
End If
If IsNumeric(ShuttleCount) Then
totalShuttle = CLng(ShuttleCount.Value)
Else
totalShuttle = 0
End If
If IsNumeric(ShoesCount) Then
totalShoes = CLng(ShoesCount.Value)
Else
totalShoes = 0
End If
If IsNumeric(SocksCount) Then
totalSocks = CLng(SocksCount.Value)
Else
totalSocks = 0
End If
Dim AccTol As Long
AccTol = totalRacket + totalShuttle + totalShoes + totalSocks
GetTotalAccessories = AccTol
End Function
Private Sub RacketsCount_Change()
AccessoriesTotalDisplay.Value = GetTotalAccessories
End Sub
Private Sub ShoesCount_Change()
AccessoriesTotalDisplay.Value = GetTotalAccessories
End Sub
Private Sub ShuttleCount_Change()
AccessoriesTotalDisplay.Value = GetTotalAccessories
End Sub
Private Sub SocksCount_Change()
AccessoriesTotalDisplay.Value = GetTotalAccessories
End Sub
I'm new here but hope you all can help with a solution I'm working towards. I'm working on an excel document and setting up a macro. It works until I try to add some logic to pad a number with zero's.
I'm trying to pad zero's in a select cell where the labels are less than 10, then add my integer. If the labels are greater than 9, I want to pad one less zero, likewise when they are greater than 99, one less from those with 10 or more.
My program asks the user how many labels they wish to print (1-999).
I've tried to add an IF statement within my For I = 1 To LabelCount:
For I = 1 To LabelCount
If I < 10 Then
ActiveSheet.Range("C20").Value = "C906BGM0880000" & I
ActiveSheet.PrintPreview
Else
ActiveSheet.Range("C20").Value = "C906BGM088000T" & I
ActiveSheet.PrintPreview
End If
Next
The above did not work.
Sub IncrementPrint()
'updateby Tyler Garretson
Dim LabelCount As Variant
Dim xScreen As Boolean
Dim I As Long
On Error Resume Next
LInput:
LabelCount = Application.InputBox("Please enter the number of copies you want to print:")
If TypeName(LabelCount) = "Boolean" Then Exit Sub
If (ActiveSheet.Range("F11").Value = "") Or (ActiveSheet.Range("F14").Value = "") Or (ActiveSheet.Range("C18").Value = "") Then
MsgBox "Error Occurred. Please enter values for Route, Stop, and Destination Name", vbExclamation
ElseIf (LabelCount = "") Or (Not IsNumeric(LabelCount)) Or (LabelCount < 1) Or (LabelCount > 999) Then
MsgBox "Error Occurred. Please enter 1 - 999", vbExclamation
ElseIf LabelCount < 10 Then
xScreen = Application.ScreenUpdating
Application.ScreenUpdating = False
For I = 1 To LabelCount
ActiveSheet.Range("C20").Value = "C906BGM0880000" & I
ActiveSheet.PrintPreview
Next
ActiveSheet.Range("C20").ClearContents
Application.ScreenUpdating = xScreen
End If
End Sub
User enters 11 labels that he or she wishes to print, the program prints out the following:
Label1: ABC00001
Label2: ABC00002
Label3: ABC00003
Label4: ABC00004
Label5: ABC00005
Label6: ABC00006
Label7: ABC00007
Label8: ABC00008
Label9: ABC00009
Label10: ABC00010
Label11: ABC00011
You want the Format command - Format(1, "00000") = 00001
Format(123,"00000") = 00123
' This might be the basis of what you need
for a = 1 to 1000
b = right("0000000000" & a,8) ' B will always be 8 long and paaded left with 0's
next a
This works well with a text prefix too
for a = 1 to 1000
c = "XYZ" & right("0000000000" & a,8)
next a
I have a worksheet change event.
Original Code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("J12") < Range("G12") Then
MsgBox "Oppps. Your system is not working!"
End If
End Sub
I am trying to expand upon the code to:
a. Increase the range from single cells (J12 and G12) to an extended cell range (J12:42, G12:42).
b. Instead of having the change event triggered by less than (J12 < G12), have it triggered by a % difference between J12 < G12.
Here is the updated code.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim diffPercent
'Check that the data is changed between row 12 and 42 and it is even row. eg 12,14,16...42.
If (Target.Row > 10 And Target.Row < 44) And ((Target.Row Mod 2) = 0) Then 'And _
'(Target.Column = 7 Or Target.Column = 10) Then
'Get the values in J ang G columns of that particular row.
number1 = Range("G" & Target.Row).Value
number2 = Range("J" & Target.Row).Value
'Check for presence of both the inputs to calculate difference in percentage.
If Not chkInputs(number1, number2) Then
Exit Sub
End If
'Calculate the percentage difference.
diff = number2 - number1
diffPercent = (diff / number2) * 100
'Give alert if difference more than 10 percent
If diffPercent > 10 Then
MsgBox "Oppps. Your system is not working! The difference is :" & diff & "|" & diffPercent
End If
End If
End Sub
Function chkInputs(number1, number2)
chkInputs = False
If IsNumeric(number1) And IsNumeric(number2) Then
chkInputs = True
End If
End Function
I have a drop down box, the items are depending on the regional settings:
Private Sub UserForm_Initialize()
Select Case Application.International(XlApplicationInternational.xlCountryCode)
Case 1: 'English
With ComboBox1
.AddItem "January"
...etc
End With
Case 36: 'Hungarian
With ComboBox1
.AddItem "Január"
...etc
End with
Case 49: 'German
With ComboBox1
.AddItem "Januar"
...etc
End with
End Select
End Sub
Later I use the selected value in this code:
Year_1 = 2017 'integer
Day_1 = 1 'integer
Date_from_userform = CDate(Year_1 & "-" & UserForm1.ComboBox1.Value & "-" & Day_1) 'date
In German environment, it works perfect, but I tested in Hungarian environment, and I get every time type mismatch.
The Cdate does not accept the 2017-Január-1. (Th excel was Hungarian)Why?
If the month depends on the regional settings, it should work...
(Or should I convert the Values from the dropdownbox into numbers?)
I would use the Format function, the DateSerial function and the ComboBox1.ListIndex property.
Private Sub CommandButton1_Click()
Year_1 = 2017 'integer
Day_1 = 1 'integer
Date_from_userform = DateSerial(Year_1, ComboBox1.ListIndex + 1, Day_1)
End Sub
Private Sub UserForm_Initialize()
For i = 1 To 12
ComboBox1.AddItem Format(DateSerial(Year(Date), i, 1), "mmmm")
Next
End Sub
Instead of writing all the months yourself (and possible risk a misspelling) I'd use the following approach to write the months "names" for you:
Public Sub getMonthNamesWrittenOutInDifferentLanguages()
Dim i As Integer
'Hungarian:
For i = 1 To 12
Debug.Print Application.WorksheetFunction.Text(DateSerial(2017, i, 1), "[$-40e]MMMM")
Next i
'English:
For i = 1 To 12
Debug.Print Application.WorksheetFunction.Text(DateSerial(2017, i, 1), "[$-809]MMMM")
Next i
'German:
For i = 1 To 12
Debug.Print Application.WorksheetFunction.Text(DateSerial(2017, i, 1), "[$-de-DE]MMMM")
Next i
End Sub
Afterwards, you can use the same code to easily go through all the possible month names and convert them back to dates:
strDate = "2017-Januar-05"
For i = 1 To 12
strDate = Replace(strDate, Application.WorksheetFunction.Text(DateSerial(2017, i, 1), "[$-de-DE]MMMM"), i)
Next i
Debug.Print IsDate(strDate)
Debug.Print CDate(strDate)
How can I verify a specific format in a textbox? I am scanning a label into a textbox that contains a date which is formatted like:
mm.dd.yyyy.hh.mm.ss
I have tried things that do not work...
If Not Format(TextBox1, "mm.dd.yyyy.hh.mm.ss") Then
MsgBox "Wrong Format"
End If
You can use this simple function to check if is a date
Function checkFormatDate(str As String) As Boolean
Dim Y
Dim M
Dim D
Dim H
Dim I
Dim S
Dim theDate As Date
M = Mid(str, 1, 2)
D = Mid(str, 4, 2)
Y = Mid(str, 7, 4)
H = Mid(str, 12, 2)
I = Mid(str, 15, 2)
S = Mid(str, 18, 2)
theDate = DateSerial(Y, M, D) + TimeSerial(H, I, S)
If IsDate(theDate) Then
checkFormatDate = True
Else
checkFormatDate = False
End If
End Function
This returns TRUE (if is a date) or FALSE (if not)
Just care about the dates like: 02.05.2016.01.10.05 (where mm.dd.yyyy.hh.mm.ss), because, you need to trust that 02 is the month and not the day, as 05 is the day and not the month, always appears somebody with a great idea, and change the values just because.
Edit #2
Heres a better version of the code:
Tester:
Sub testDate()
Dim Check As Boolean
Check = checkFormatDate2(UserForm1.TextBox1.Text)
'the textbox is inside UserForm1
If Check Then
MsgBox "Is a Date"
Else
MsgBox "Not a Date"
End If
End Sub
Function:
Function checkFormatDate2(str As String) As Boolean
Dim ArrayD
Dim i
Dim m
ArrayD = Split(str, ".")
If UBound(ArrayD) <> 5 Then
checkFormatDate2 = False
Exit Function
End If
For i = 0 To 5
Select Case i
Case 0
If CInt(ArrayD(i)) < 1 Or CInt(ArrayD(i)) > 12 Then
checkFormatDate2 = False
Exit Function
End If
Case 1
If CInt(ArrayD(i + 1)) < 1900 Or CInt(ArrayD(i + 1)) > 2050 Then
'set the botton and limit year as you need
checkFormatDate2 = False
Exit Function
End If
Case 2
m = Day(DateSerial(CInt(ArrayD(2)), CInt(ArrayD(0)) + 1, 1) - 1)
'm = the last (num) day of the month
If CInt(ArrayD(i - 1)) < 1 Or CInt(ArrayD(i - 1)) > m Then
checkFormatDate2 = False
Exit Function
End If
Case 3
If CInt(ArrayD(i)) < 1 Or CInt(ArrayD(i)) > 23 Then
checkFormatDate2 = False
Exit Function
End If
Case 4
If CInt(ArrayD(i)) < 1 Or CInt(ArrayD(i)) > 59 Then
checkFormatDate2 = False
Exit Function
End If
Case 5
If CInt(ArrayD(i)) < 1 Or CInt(ArrayD(i)) > 59 Then
checkFormatDate2 = False
Exit Function
End If
Case Else
End Select
Next i
checkFormatDate2 = True
End Function
Use this function to validate if the text inside the TextBox is a date sending the TextBox.Value or TextBox.Text. Thanks MikeD for your advice. This way is better.
Edit #3
As you tell me in the comments you could use the AfterUpdate on the Textbox, like this:
Private Sub TextBox1_AfterUpdate()
Dim a As Boolean
a = checkFormatDate2(Me.TextBox1.Value)
If a Then
MsgBox "is date"
Else
MsgBox "no date"
End If
End Sub
Where the UserForm1 has a TextBox named TextBox1 inside, and the function checkFormatDate2 is in a regular module. In my case I just send a MsgBox saying that is not a date.
Edit #4
The same way you can validate the text inside the TextBox when Exit the UserForm this way:
1) Add a button and set the Cancel Property to TRUE:
2)And inside the code you put this:
Private Sub CommandButton1_Click()
Dim a As Boolean
a = checkFormatDate2(Me.TextBox1.Value)
If a Then
MsgBox "is date"
Else
MsgBox "no date"
End If
End Sub
This way, when you press ESC in the keyboard or press the button CommandButton1 you try to close the UserForm and fire the code inside, and test the text inside the TextBox and you could do whatever you want, as, don't let the user go away, go back to the TextBox after a message saying what is the right format, well whatever you want.
Try :
If textbox1 = Format(TextBox1, "mm.dd.yyyy.hh.mm.ss") Then
TextBox1 does not contain a date format, so you can't apply a Format() function using date/time format codes.
One solution would be to split your string into array elements and examine them one by one, e.g.
Sub Test()
Dim A() As String, Rslt As Boolean
A = Split(Me.TextBox1.Value, ".") ' load dot seperated elements into array
If UBound(A) <> 5 Then
MsgBox "not 6 numbers seperated by (5) dots"
Rslt = False
ElseIf Val(A(0)) < 1 Or Val(A(0)) > 12 Then
MsgBox "1st part not a valid month (01-12)"
Rslt = False
ElseIf Val(A(1)) < 1 Or Val(A(1)) > 31 Then
MsgBox "2nd part not a valid day (01-31)"
Rslt = False
ElseIf Val(A(2)) < 0 Or Val(A(1)) > 99 Then
MsgBox "3rd part not a valid year (00-99)"
Rslt = False
ElseIf Val(A(3)) < 0 Or Val(A(3)) > 23 Then
MsgBox "4th part not a valid hour (00-23)"
Rslt = False
ElseIf Val(A(4)) < 0 Or Val(A(4)) > 59 Then
MsgBox "5th part not a valid minute (00-59)"
Rslt = False
ElseIf Val(A(5)) < 0 Or Val(A(5)) > 59 Then
MsgBox "6th part not a valid second (00-59)"
Rslt = False
End If
If Not Rslt Then
'beat the user
End If
End Sub
This doesn't consider months with 28/29/30/31 days, but that's only 1 or 2 if's further away.