Dialog Boxes
Formatting Functions
Formatting Date and Time
Procedures
Code which runs in response to a click or other event is an event procedure, or sometimes called a routine. If you have code segments, which you want to run in more than one event, it's a good idea to store them in general procedures. You can then run these procedures when needed with one line of code.
General procedures will...
- ...save keystroke time.
- ...reduce the size of your program.
...make debugging easier.
Most programmers create their own library of general procedures, which can be used in any of their applications.
The only difference between event procedures and general procedures is the way they are called. Codes in event procedures are called by internal Windows messages; codes in general procedures are called specifically by you, the programmer.
Private and Public Subs
You may have noticed that event procedures always start with Private Sub. Private means that code in other modules cannot call the procedure. On the other hand, a Public Sub can be called from anywhere in the project. When creating procedures, Public is the default and the actual Public keyword is not required.
Tip: If needed, you can convert your event procedures to Public and call them from other Forms or Modules.
Public Sub cmdOK_Click()
'Code segment
End Sub
Call the event procedure:
cmdOK_Click
Add Procedure Window
Open the module where the procedure will be located, then select Tools/Add Procedure to bring up the Add Procedure window, where you can name your new procedure, decide between Public and Private, Sub or Function, and whether to use all Static variables. Two more choices (Property and Event procedures) are advanced procedures used with Class Modules.
If you have a procedure which would only be associated with one Form, then writing it in the form (.FRM file) would be OK, but most of the time you'll write it in a .BAS file (code module) which is part of your project. You never know when you might want to reuse the procedure.
Follow the variable naming rules when naming procedures.
Once you click OK, you are whisked to the code window for your new procedure where End Sub (or Function) and some empty parentheses have been added automatically.
So what are the empty parentheses for? You can optionally send data to the procedure in the form of arguments. Arguments are the additional information that a procedure needs to complete itself. Like variables, arguments are of a certain data type and must be written into the procedure as such.
Public Sub FindReplace(ByRef sSearchString$, _ByVal sFindWhat$, ByVal sReplaceWith$)
Dim iPos As Integer, iStart As Integer
iStart% = 1
Do
'Find beginning position
iPos% = InStr(iStart%, sSearchString$, sFindWhat$)
'If not there, then get out
If iPos% = 0 Then Exit Do
'Combine left portion, new string, and right portion
sSearchString$ = Left(sSearchString, iPos% - 1) & sReplaceWith$ & _
Right(sSearchString$, Len(sSearchString$) - iPos% - Len(sFindWhat$) + 1)
'Calculate where to begin next search
iStart% = iPos% + Len(sReplaceWith$)
Loop
End Sub
This Find and Replace procedure requires three strings to be sent to it in order to run properly. This is called passing arguments. You then use the arguments in the code just like variables.
ByVal and ByRef
Arguments are passed "by value", or "by reference". ByRef is the default and can be omitted.
It's popular opinion that ByVal should be the default because most of the time you just want to use the value of the variable in the procedure, rather than the actual variable. If you specifically want the procedure to change the value of an argument (as the above procedure did), then use ByRef, otherwise stick the ByVal keyword in front of your arguments.
Call the procedure by simply writing its name and its arguments in the correct order. Separate the arguments with commas. Parentheses are not required with a Sub procedure.
FindReplace myOriginalString$, myStringToReplace$, myNewString$
Be sure to send the right data types for the arguments. Once the procedure has run, program execution is returned to the very next line in the procedure that called it.
Call statement
The Call statement is optional and is used less and less all the time. If you want a visual clue to indicate that this line of code is calling a separate procedure, then by all means include it. If you do use Call, you must enclose the arguments in parentheses.
Call FindReplace(myOriginalString$, myStringToReplace$, myNewString$)
By now, you know that Visual Basic has many built-in methods such as the AddItem method of a ListBox. A VB method simply performs an action by running a built-in code segment. Sub procedures are methods which you define, thereby expanding VB's capability. Hold on, don't methods have to be associated with an object? Yes, the Sub procedures you write are methods of the object you place them in, whether a Form or Module.
Assuming you've written the above Sub procedure in a Form named frmMain, you could actually call the procedure like this:
frmMain.FindReplace myOriginalString$, myStringToReplace$, myNewString$
On the other hand, VB has many built-in numeric, string and boolean functions. You can further expand this collection of functions by writing your own Function procedures, which are also considered to be Methods.
Function Procedures
You know that a function produces a result and when using one of VB's functions you put the result in a variable or property of an object. The same is true of Function procedures.
Create your Function procedure in the Add Procedure Window, write in any arguments and then declare what data type the result of the function will be.
Public Function GetERA(ByVal iIP As Single, ByVal iER As Integer) As Single
GetERA = Format(iER% * 9 / iIP!, "##.00")
End Function
This is a simple function which takes two arguments to produce a baseball pitcher's Earned Run Average and returns the result to the procedure that called it. Somewhere in the code (usually the last line) you have to assign a value to your function. This function could be called like this:
Dim sinERA As Single
sinERA! = GetERA(123.333, 54)
You may decide to use a Function even if the only value you need returned is whether the function was successful or not.
Public Function FolderToFloppy(sFolder As String) As Boolean
On Error GoTo FunctionFailed
Dim sFile As String
If Right(sFolder$, 1) <> "\" Then sFolder$ = sFolder$ & "\"
sFile$ = Dir(sFolder$ & "*.*")
Do While sFile$ <> ""
FileCopy sFolder & sFile$, "A:\" & sFile$
sFile = Dir
Loop
FolderToFloppy = True
Exit Function
FunctionFailed:
End Function
'Note: some computers may not use A:
as the floppy drive letter. Look into
the GetDriveType API 'function.
This function takes a folder as an argument and copies all it's files to the floppy drive. The argument is passed by reference because we check for a trailing backslash. If an error occurs, the function terminates.
Calling this function might be done like this:
If Not FolderToFloppy(App.Path) Then
MsgBox "Error copying files to floppy"
End If
Note: Creating a new general procedure can also be done by going to the general declarations section of the form or code module and typing Sub (procedure name) and pressing enter. End Sub and some empty parentheses are added automatically. This new procedure doesn't actually exist in general declarations, it can just be initially written there.
Passing arrays to procedures
Note: VB 6.0 can now return an array from a function. Personally, I haven't found a use for this new trick yet
A Function procedure returns just one value, it cannot return an array of values. The work-around to this is to pass an entire array to a procedure as an argument. An array is passed with empty parentheses and always ByRef.
'A simple procedure which doubles
'the arguments passed to it
Public Sub DoubleThem(myArray() As Integer)
Dim i As Integer
For i% = LBound(myArray) To UBound(myArray)
myArray(i%) = myArray(i%) * 2
Next i%
End Sub
'Passing an array to this procedure
Dim myArray(1 To 3) As Integer
myArray(1) = 34
myArray(2) = 57
myArray(3) = 123
DoubleThem myArray()
The values in the variable array change to 68, 114, and 246.
Passing objects to procedures
Forms, controls, and other objects can also be passed to procedures as arguments. The type of the object is written into the procedure rather than a standard data type. The following Sub procedure adds an item to a ListBox only if the item doesn't already exist.
Public Sub AddItemNoDuplicates(ByVal lst As ListBox, ByVal sItem As String)
Dim i As Integer
For i% = 1 To lst.ListCount - 1
If sItem$ = lst.List(i%) Then
MsgBox "This item already exists in the list", _
vbInformation, "Duplicate found"
Exit Sub
End If
Next i%
lst.AddItem sItem$
End Sub
'Using the procedure
AddItemNoDuplicates lstItems, "New Item"
You could make this procedure work with both ListBoxes and ComboBoxes by specifying the generic type Control instead of a specific control type.
Public Sub AddItemNoDuplicates(ByVal ctl As Control, ByVal sItem As String)
Parent and Container properties
When passing a control as an argument, you can access that control's Form or Container with these properties. The procedure below frames a control when it gets the focus.
Public Sub FrameOnFocus(ctl As Control)
Dim l As Integer, t As Integer, w As Integer, h As Integer
l% = ctl.Left - 4
t% = ctl.Top - 4
w% = ctl.Left + ctl.Width + 8
h% = ctl.Top + ctl.Height + 8
With ctl.Parent
.DrawWidth = 4
.Cls
End With
'Can't use Line method in a With block
ctl.Parent.Line (l%, t%)-(w%, h%), 0&, B
End Sub
'Call FrameOnFocus in each control's GotFocus event
Private Sub txtCity_GotFocus()
FrameOnFocus txtCity
End Sub
The Container property would be used to access the control's PictureBox or Frame container. If the control is not contained by a container control, this property returns the Form.
Here's a goofy little procedure which takes a Form as an argument and shrinks it just before unloading.
Public Sub DissolveForm(ByVal frm As Form)
With frm
Do Until .ScaleHeight < 2
.Height = .Height - 100
.Width = .Width - 100
.Left = .Left + 50
.Top = .Top + 50
DoEvents
Loop
End With
End Sub
'Best called from QueryUnload
DissolveForm Me
The Me keyword is a built-in global variable which is used to pass the current instance of a Form to a procedure. Me is intended to be used when you have multiple Form instances, but you will see programmers using it as shortcut to writing a Form's name.
Dialog Boxes
Formatting Functions
Formatting Date and Time