Originally published December 2002 on DoItIn.net using VB7.0/2002. Updated for VB7.1 February 2005
Links for compiled demo versions, all required resources and source code are included at the end of this article.
Plus, get the complete eBook in Adobe Acrobat 7 format ... all here.
26) An integer-only textbox
Add a new usercontrol to your app project, name the file "svIntegerTextbox.vb" and save the file. When the designer is shown, right click to switch to codeview and replace all of the stock code with the following:
Public Class svIntegerTextbox
Inherits System.Windows.Forms.TextBox
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'UserControl overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<system.diagnostics.debuggerstepthrough> Private Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub
#End Region
#Region "Declarations"
Private m_MinValue As Integer = 0
Private m_MaxValue As Integer = Integer.MaxValue
Private m_DefaultValue As Integer = 0
#End Region
#Region "Public properties"
Public Property DefaultValue() As Integer
Get
Return m_DefaultValue
End Get
Set(ByVal Value As Integer)
If Value < m_MinValue OrElse Value > m_MaxValue Then
m_DefaultValue = (m_MaxValue - m_MinValue) \ 2
Else
m_DefaultValue = Value
End If
End Set
End Property
Public Overrides Property MaxLength() As Integer
Get
Return MyBase.MaxLength()
End Get
Set(ByVal Value As Integer)
Try
If Value > m_MaxValue.ToString.Length + 1 Then
Value = m_MaxValue.ToString.Length + 1
ElseIf Value < m_MaxValue.ToString.Length + 1 Then
Value = m_MaxValue.ToString.Length + 1
End If
Catch ex As Exception
End Try
MyBase.MaxLength = Value
End Set
End Property
Public Property MinValue() As Integer
Get
Return m_MinValue
End Get
Set(ByVal Value As Integer)
If Not Value > m_MaxValue Then
m_MinValue = Value
If m_DefaultValue < m_MinValue Then
m_DefaultValue = m_MinValue
End If
If CInt(Me.Text) < m_MinValue Then
'force a fix
Me.Text = FixEntry(Me.Text)
End If
End If
End Set
End Property
Public Property MaxValue() As Integer
Get
Return m_MaxValue
End Get
Set(ByVal Value As Integer)
If Not Value < m_MinValue Then
m_MaxValue = Value
MyBase.MaxLength = m_MaxValue.ToString.Length + 1
'security against changing maxlength/maxval after
'after a larger value has been entered in the textbox
If m_DefaultValue > m_MaxValue Then
m_DefaultValue = m_MaxValue
End If
If CInt(Me.Text) > m_MaxValue Then
'force a fix
Me.Text = FixEntry(Me.Text)
End If
End If
End Set
End Property
#End Region
#Region "Private methods"
Private Function FixEntry(ByVal Value As String) As String
Dim s As String = Value.Trim.Replace(" ", "")
Dim sVal As Long
Dim arc() As Char = s.ToCharArray
s = ""
For i As Integer = 0 To arc.GetUpperBound(0)
If IsNumeric(arc(i)) Then
s &= arc(i)
End If
Next
If s.Length = 0 Then
Return m_DefaultValue.ToString
Else
sVal = CLng(s)
If sVal > CLng(m_MaxValue) Then
Return m_MaxValue.ToString
ElseIf sVal < CLng(m_MinValue) Then
Return m_MinValue.ToString()
Else
Return CInt(sVal).ToString
End If
End If
End Function
#End Region
#Region "Base methods"
Protected Overrides Sub OnLayout(ByVal levent As System.Windows.Forms.LayoutEventArgs)
'called in the IDE at designtime
Me.Text = m_DefaultValue.ToString
Me.MaxLength = m_MaxValue.ToString.Length + 1
End Sub
Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
Static bFixing As Boolean
If bFixing Then Exit Sub
bFixing = True
Dim iCurPos As Integer = Me.SelectionStart
Dim sOrig As String = Me.Text
Dim sFixed As String = FixEntry(sOrig)
If sOrig <> sFixed Then
Me.Text = sFixed
End If
If Me.Text = "0" Then
Me.SelectAll()
ElseIf iCurPos > 0 Then
Me.SelectionStart = iCurPos
End If
bFixing = False
End Sub
Private Sub IntegerTextbox_LostFocus(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.LostFocus
If Me.Text = "" Then Me.Text = FixEntry(Me.Text)
End Sub
#End Region
End Class
Most of the work is done in the FixEntry function, where the text is analyzed character by character and compared against the min and max properties. The one little neat routine is the OnLayout event handler which sets the text when the dev-user drops an instance on a form at designtime; you have to force the text in this event because the base textbox default is the name of the instance plus an incremented counter and if you don't deal with it then each instance will be automatically set to the trimmed instance number which can be a bit confusing.
Rebuild the project so the usercontrol is usable then drop instances on the form as shown in the previous sample graphic,naming each to fit the specific usages.
One last thing on the save options form, the 'Aspect Correct By Max' needs a checkbox to specify whether the value is for the width or height. Add that defaulting to checked so the width will be used.
Next: Passing save options between forms
Robert Smith
Kirkland, WA
added to smithvoice march 2005