VBA Excel: Limit the textboxes to a value between 60 to 100 - excel

I'm trying to validate textboxes in a UserForm. I'm using this solution on my worksheet.
How can I add validation to my textboxes to only accept numbers between 60 to 100 using the given solution? Should I add something after the If KeyAscii >= 48 And KeyAscii <= 57 Then or it should be elsewhere?
UserForm:
Class code:
Private WithEvents tb As MSForms.TextBox 'note the "WithEvents"
Sub Init(tbox As Object)
Set tb = tbox 'assigns the textbox to the "tb" global
End Sub
'Event handler works as in a form (you should get choices for "tb" in the
' drop-downs at the top of the class module)
Private Sub tb_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If KeyAscii >= 48 And KeyAscii <= 57 Then
Debug.Print tb.Name, "number"
Else
MsgBox "The value should be in number only!", vbOKOnly + vbCritical, "Error"
Debug.Print tb.Name, "other"
KeyAscii = 0
End If
End Sub
Code on UserForm:
Private colTB As Collection 'holds your class instances
' and keeps them in scope
'This performs the setup
Private Sub UserForm_Activate()
Dim c As Object
Set colTB = New Collection
'loop all controls in the frame
For Each c In Me.Frame3.Controls
'look for text boxes
If TypeName(c) = "TextBox" Then
Debug.Print "setting up " & c.Name
colTB.Add TbHandler(c) ' create and store an instance of your class
End If
Next c
End Sub
' "factory" method
Private Function TbHandler(tb As Object) As clsTxt
Dim o As New clsTxt
o.Init tb
Set TbHandler = o
End Function

I don't think you can achieve that easily using a Class. The solution you are using will help you monitor each keystroke, but it looks as though you are wanting to validate input after the user has finished with the field and then you need to verify that what he has input is between 60 and 100. For that you would probably be looking at the AfterUpdate event but sadly that is not available within a class.
I think you will either need to create a stub for each textbox_AfterUpdate to do the validation.

Try this:
Private Sub tb_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Not IsNumeric(tb.Value) Then
'MsgBox "only numbers between 60 and 100 are allowed"
tb.Value = ""
ElseIf tb.Value >= 60 And tb.Value <= 100 Then
'MsgBox "OK!"
Else
'MsgBox "only numbers between 60 and 100 are allowed"
tb.Value = ""
End If
End Sub

Related

Refer to ComboBox that is just created after user input

i am trying to have VBA create a user form and based off of what selection you choose populate more selections.
the following code is my initial user form and i have it adding Comboboxes Based on whatever selection is chosen.
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Selection1"
ComboBox1.AddItem "Selection2"
ComboBox1.AddItem "Selection3"
ComboBox1.FontSize = 13
End Sub
But i have it going to comboboxchange to do so
Private Sub ComboBox1_Change()
'Here i have some Working Code That Adds another ComboBox
Dim MsgType As Control
Set MsgType = UserForm2.Controls.Add("Forms.ComboBox.1")
With MsgType
.Height = 25
.Width = 300
.Top = 75
.Left = 20
.FontSize = 13
.Name = "vmtype"
.AddItem "Selection1"
.AddItem "Selection2"
Debug.Print .Value
End With
EndSub
I now need to have a private sub refer to this combo box just as "Private Sub ComboBox1_Change()" had. that way i can add more items depending on that selection.
What i have so far is the following.
Private Sub ComboBox2_Change()
Dim Notetype As String
Notetype = ComboBox1.Value
Debug.Print Notetype
End Sub
But it is not actually refering to the newly created Combo Box any idea how i can Fix this?
Use WithEvents to listen for dynamically added controls.
Here is a simple example where you are just adding a single control:
Private WithEvents vmtype As MSForms.ComboBox
Private Sub vmtype_Change()
Debug.Print MsgType
End Sub
Private Sub ComboBox1_Change()
Set vmtype = UserForm2.Controls.Add("Forms.ComboBox.1")
With vmtype
.Height = 25
.Width = 300
.Top = 75
.Left = 20
.FontSize = 13
.Name = "vmtype"
.AddItem "Selection1"
.AddItem "Selection2"
End With
End Sub
Consider using a custom class when adding many control. See my post: Responding to Events of Dynamically added Controls

Sub _change reference of added comobox to userform VBA

The following code will open a userform (examples) in which I have a commmandbutton which adds a new Combobox. I can name the combobox and can retrive the name in the immediate window, but I am unable to accecs the change command of the added combobox(es) or retrive the acces to their input.
In would like to do things upon change of this added combobox. I am able to do it for 1 box using the set "newgene1" = .... but than it on reclickit this first box will get lost.
Option Explicit
Dim Counter As Integer
Private WithEvents newgene1 As MSForms.ComboBox
Private WithEvents newgene2 As MSForms.ComboBox
Dim Generanger As Range
Private Sub UserForm_Initialize()
Set Generanger = ThisWorkbook.ActiveSheet.Range("A1", Range("A1").End(xlDown)) 'list of data
Generanger.Select
Counter = 1
cboGenelist.RowSource = Generanger.Address
End Sub
--------------------------------------------------------------------
Private Sub cboGenelist_Change()
MsgBox (cboGenelist.Text)
End Sub
--------------------------------------------------------------------
Private Sub cmdAddgene_Click()
UserForm1.Height = UserForm1.Height + 20
UserForm1.Controls.Add("Forms.comboBox.1", "newgene" & Counter) = "select"
With Me.Controls("newgene" & Counter)
.Left = 20
.Top = UserForm1.Height - 50
.RowSource = Generanger.Address
.Font.Name = "Trebuchet MS"
.Font.Size = 12
End With
Debug.Print Me.Controls("newgene" & Counter).Name
Counter = Counter + 1
End Sub
--------------------------------------------------------------------
Private Sub newgene1_Change()
MsgBox (newgene.Text)
End Sub
--------------------------------------------------------------------
Private Sub newgene2_Change()
MsgBox (newgene2.Text)
End Sub

VBA Excel - Working with multiple textboxes with the same code

So I'm new to this area. I just want to ask if how can I minimize the use of the code below since I do have 13 textboxes with the same code. Is there a short way to do this?
Here's the UserForm that I'm using ->
Here's the code
Private Sub tb_mtb_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If Not IsNumeric(tb_mtb.Value) Then
MsgBox "Only numbers allowed!", vbOKOnly + vbCritical, "Title"
tb_mtb.Value = ""
End If
End Sub
Private Sub tb_fil_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If Not IsNumeric(tb_fil.Value) Then
MsgBox "Only numbers allowed!", vbOKOnly + vbCritical, "Title"
tb_fil.Value = ""
End If
End Sub
I tried this solution but I can't make it work.
The "normal" way to avoid writing the same event handler code over and over (or to avoid having to write even a "stub" handler for each like control) is to use a "control array".
Here's a basic example.
First a small custom class clsTxt which can be used to capture events from a text box:
Private WithEvents tb As MSForms.TextBox 'note the "WithEvents"
Sub Init(tbox As Object)
Set tb = tbox 'assigns the textbox to the "tb" global
End Sub
'Event handler works as in a form (you should get choices for "tb" in the
' drop-downs at the top of the class module)
Private Sub tb_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If KeyAscii >= 48 And KeyAscii <= 57 Then
Debug.Print tb.Name, "number"
Else
Debug.Print tb.Name, "other"
KeyAscii = 0
End If
End Sub
Then in your userform you can (for example) grab all textboxes inside the frame frmTest and create an instance of clsTxt for each one, storing it in a Collection (which is Global and so does not go out of scope when the Activate event completes.
Private colTB As Collection 'holds your class instances
' and keeps them in scope
'This performs the setup
Private Sub UserForm_Activate()
Dim c As Object
Set colTB = New Collection
'loop all controls in the frame
For Each c In Me.frmTest.Controls
'look for text boxes
If TypeName(c) = "TextBox" Then
Debug.Print "setting up " & c.Name
colTB.Add TbHandler(c) ' create and store an instance of your class
End If
Next c
End Sub
' "factory" method
Private Function TbHandler(tb As Object) As clsTxt
Dim o As New clsTxt
o.Init tb
Set TbHandler = o
End Function
Once the setup is complete then events for each "wired up" textbox are handled by the class instances (you can add more events to the class if you need to manage different things like Change etc) and any new textbox added to the frame will automatically get handled without the need to write a handler for it.
Make it a subroutine and pass the control as an argument
(Make it Public if you want to put it into a module to make it re-usable for any form):
Public Sub CheckNumeric(ctl as Control)
If Not IsNumeric(ctl.Value) Then
MsgBox "Only numbers allowed!", vbOKOnly Or vbCritical, "Title"
ctl.Value = ""
End If
End Sub
And then for each control on the form:
Private Sub tb_fil_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
CheckNumeric tb_fil
End Sub
Although, a better way might be to check the KeyAscii value in the KeyPress event, and not allow non-numeric characters at all.
Making VBA Form TextBox accept Numbers only

Excel VBA: Highlight textbox value after error occurs

I am trying to highlight entered value in TextBox. TextBox value is representing date value in date forma DD-MM-YYYY. I wrote some code to validate if inserted date is ok (in example 31 of April).
Hightlight itself is not a problem, however I want to do this right after an error occurs. So when I insert 31-04-2014, I should get the message "You have inserted wrong date" and the date value should hightlighted. For now it shows me message, highlights value and focus is set to another CommandButton
So far I made something like this:
Private Sub data_faktury_AfterUpdate()
Dim dzien As Byte, miesiac As Byte
Dim rok As Integer
On Error GoTo blad:
dzien = Mid(data_faktury.Value, 1, 2)
miesiac = Mid(data_faktury.Value, 4, 2)
rok = Right(data_faktury.Value, 4)
Call spr_date(dzien, miesiac, rok)
Exit Sub
blad:
If Err.Number = 13 Then
If data_faktury <> "" Then
If Len(data_faktury) < 10 Then: MsgBox ("Źle wpisana data faktury.")
End If
End If
End Sub
And code for 2nd procedure:
Sub zle()
MsgBox ("Wybrałeś zły dzień")
With Faktura.data_faktury
.SetFocus
.SelStart = 0
.SelLength = Len(.Text)
End With
End Sub
This is a bit long for a comment so here goes. The basic principle is to use the exit event and cancel when necessary. To prevent this being fired when you close the form, you need to use a flag variable - example userform code:
Private bSkipEvents As Boolean
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If bSkipEvents Then Exit Sub
With TextBox1
If Not IsValidDate(.Text) Then
Cancel = True
MsgBox "Invalid date"
.SelStart = 0
.SelLength = Len(.Text)
End If
End With
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
bSkipEvents = True
End Sub

numeric up down control in vba

Is there an in-built numeric updown control in vba or do we need to create a control like that?
If there is such a control then what are the events that we may use.
Pls suggest.
You can use the SpinButton1 control for that
SNAPSHOT
CODE
You can either set the min and max of the SpinButton1 in design time or at runtime as shown below.
Private Sub UserForm_Initialize()
SpinButton1.Min = 0
SpinButton1.Max = 100
End Sub
Private Sub SpinButton1_Change()
TextBox1.Text = SpinButton1.Value
End Sub
FOLLOWUP
If you want to increase or decrease the value of the textbox based on what user has input in the textbox then use this. This also makes the textbox a "Number Only" textbox which just fulfills your other request ;)
Private Sub SpinButton1_SpinDown()
TextBox1.Text = Val(TextBox1.Text) - 1
End Sub
Private Sub SpinButton1_SpinUp()
TextBox1.Text = Val(TextBox1.Text) + 1
End Sub
Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case vbKey0 To vbKey9, 8
Case Else
KeyAscii = 0
Beep
End Select
End Sub

Resources