Professional Documents
Culture Documents
Prior to VB6 and the introduction of ADO (ActiveX Data Objects), VB programmers
would generally use DAO (Data Access Objects) to interact with local databases s
uch as MS Access and use RDO (Remote Data Objects) to interact with client/serve
r databases such as Oracle and SQL Server. The concept behind Visual Basic ADO w
as Universal Data Access (UDA), where one database access method could be used f
or any data source; it was designed to replace both DAO and RDO. DAO remains a v
iable technology for interacting with MS Access databases as it is faster than A
DO for that purpose; however, ADO is more flexible – using ADO, one could develop
a prototype database application using MS Access in the back-end, and with a "fl
ick of the wrist" (i.e., with very little coding changes) "upsize" that same app
lication to use Oracle or SQL Server. As far as RDO is concerned, no new version
s of it have been developed beyond the version that shipped with Visual Basic, a
nd there are no future plans for it.
In the VB4 and VB5 worlds, RDO was the main method used to interact with client/
server databases. RDO works perfectly fine with VB6, so when folks migrated thei
r VB5 applications over to VB6, little or no coding changes were required. Howev
er, ADO is the preferred method of database access for new VB6 applications .
This tutorial presents three small sample applications using ADO. All three appl
ications use a local MS Access database.
The first sample application introduces the ADO Data Control (ADODC) which demon
strates a "quick and dirty" way to connect to a remote database. The second and
third applications use ADO code: the second allows navigation and searching of a
database table; the third allows navigation and updating on a database table. A
ll three connect to an ODBC Data Source, which must be set up through the Window
s Control Panel. How to do this is described below.
Note: If you have previously set up a DSN for the Biblio database as described i
n the previous topic on RDO, you can skip the section on setting up an ODBC data
source and resume here.
· Click the Add button. The Create New Data Source dialog box will appear.
Select Microsoft Access Driver (*.mdb) from the list and click the Finish butto
n.
· The ODBC Microsoft Access Setup dialog box will appear. For Data Source
Name, type Biblio. If desired, you can type an entry for Description, but this i
s not required.
· Click the Select button. The Select Database dialog box appears. On a de
fault installation of VB6 or Visual Studio 6, the BIBLIO.MDB sample database sho
uld reside in the folder C:\Program Files\Microsoft Visual Studio\VB98. Navigate
to that folder, select BIBLIO.MDB from the file list, and click OK.
· When you are returned to the ODBC Microsoft Access Setup screen, the dat
abase you selected should be reflected as shown below. Click OK to dismiss this
screen.
· When you are returned to the ODBC Data Source Administrator screen, the
new DSN should appear as shown below. Click OK to dismiss this screen.
At this point, the Biblio database is ready to be used with RDO in the sample ap
plication.
· Start a new VB project, and from the Components dialog box (invoked from
the Project -> Components menu), select Microsoft ADO Data Control 6.0 (SPx) as
shown below and click OK.
The ADO Data Control should appear in your toolbox as shown below:
· Put an ADO Data Control on your form, and set the properties as follows:
Property
Value
Name
adoBiblio
DataSourceName
Biblio
SQL
Name
DataSource
DataField
txtAuthor
adoBiblio
Author
txtAuID
adoBiblio
Au_ID
txtYearBorn
adoBiblio
Year Born
· Save and run the program. Notice how it works just like the other data c
ontrol.
· Now change the SQL property of the data control to select * from authors
order by author and run the program again. Notice the difference.
· Change the SQL property back to what it was and add three command button
s to the form, and set their Name and Caption properties as follows:
Name
Caption
cmdNameOrder
Order by Name
cmdYearOrder
Order by Year
cmdIDOrder
Order by ID
· Save and run the program and see what happens when you click the buttons
.
Sample applications 2 and 3 use a database called PROPERTY.MDB and can be downlo
aded here.
The Property database contains just one table called "Property". The columns of
this table are defined as follows:
Column Name
Data Type
Notes
PROPNO
A number that uniquely identifies the property in the table. Should be treated a
s the Primary Key (although it is not defined as such in the sample database).
EMPNO
A number that identifies the real estate agent selling the property. In a real s
ystem, this would be the foreign key to the employee number in an Employee table
(such a table is not present in the sample database).
ADDRESS
Text (20)
Text (15)
Text (2)
Text (5)
Text (15)
Age in years of the home. (A better table design choice would be to have this fi
eld be the date in which the property was built and have the application compute
the age based on the current date.)
BEDS
Number (Single)
Number of bathrooms in the property (allows for a decimal value such as 2.5, ind
icating 2 ½ bathrooms – i.e. 2 full bathrooms and 1 "powder room").
FOOTAGE
Sale price (amount the property actually sold for) in whole dollars.
Before coding or running sample application 2 or 3, you must set up an ODBC data
source as was done for the previous sample application.
After downloading the file, move it to the folder of your choice. Then follow th
e exact same steps as before to set up the DSN, with these two exceptions:
(1) On the ODBC Microsoft Access Setup dialog box, type PropDB for the Data Sour
ce Name.
(2) In the Select Database dialog box, navigate to the location where you have p
laced the PROPERTY.MDB file.
Sample Application 2
To build Sample Application 2, start a new VB project and perform the following
steps.
· From the Project -> References menu, check Microsoft ActiveX Data Object
s 2.x (where x is the highest version that you have on your system) and click OK
.
· This project uses the StatusBar control, so include the Microsoft Window
s Common Controls 6.0 (SP6) from the Components dialog box, accessed from the Pr
oject -> Components menu.
· Create the form shown below. The names of the text boxes in the top fram
e are shown in the form. Set the Enabled property of the frame to False, which w
ill automatically disable all of the textboxes within it, which is desired becau
se this application does not allow updating of the data. The settings for the ot
her controls are given below.
Name
Caption
cmdMoveFirst
<<
cmdMovePrevious
<
cmdMoveNext
>
cmdMoveLast
>>
The text box in the middle of the form has the following properties:
Name
txtCurrentQuery
MultiLine
True
Locked
True
Name
Caption
Enabled
cmdAllData
True
cmdGetData
False
Caption
chkCriteria(0)
EmpNo
chkCriteria(1)
City
chkCriteria(2)
State
Caption
Enabled
lblCriteria(0)
False
lblCriteria(1)
Like
False
lblCriteria(2)
Like
False
Caption
Enabled
txtCriteria(0)
EmpNo
False
txtCriteria(1)
City
False
txtCriteria(2)
State
False
Place the StatusBar on the form and set its Style property to 1 – sbrSimple.
2. Code the General Declarations section as shown below. Here, two ADO objects,
ADODB.Connection and ADODB.Recordset, are defined at the form level.
The ADODB.Recordset object represents the rows that result from running a query,
Option Explicit
3. Code the Form_Load event. Here, the connection object variable mobjADOConn is
made available for use by setting it to a new instance of ADODB.Connection. The
n, the ConnectionString property and the Open method of the ADODB.Connection obj
ect are used.
The ConnectionString property takes a string with various arguments delimited by
semicolons. When using a DSN as we are in this sample application, you typicall
y need just the DSN name, the user id, and the password. The Open method then op
ens the connection to the database.
'-----------------------------------------------------------------------------
Private Sub Form_Load()
'-----------------------------------------------------------------------------
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
4. Code the cmdAllData_Click event, which sets or resets the ADODB.Recordset obj
ect with a query to display all the rows in the table. The opening of the record
set takes place in the OpenNewRecordset subprocedure, called from this event pro
cedure.
'-----------------------------------------------------------------------------
Private Sub cmdAllData_Click()
'-----------------------------------------------------------------------------
End Sub
Here, the recordset object mobjADORst is made available for use by setting (or r
esetting) it to a new instance of ADODB.Recordset.
The Open method of the recordset is then executed. The Open method has the follo
wing syntax:
The Source argument is an optional variant that evaluates to a valid Command obj
ect, SQL statement, table name, stored procedure call, or filename of a persiste
d recordset.
The CursorType argument is an optional value that determines the type of cursor
that the provider should use when opening the recordset. The possible values and
their descriptions are given below:
Value
Description
adOpenForwardOnly
Used to open a static cursor. A static cursor is a static copy of the data in th
e data source. Once created, no changes made by other users propagate to the rec
ordset; the recordset never changes. Note: Client side cursors (like the one use
d in this sample application) use only adOpenStatic for CursorTypes regardless o
f which CursorType you select.
adOpenDynamic
Used to open a dynamic cursor. A dynamic cursor is a "live" recordset, meaning t
hat any and all additions, changes, and deletions by other users affect the reco
rdset. Dynamic-cursor recordsets support all types of navigation, including book
marks (if bookmarks are supported by the provider). Dynamic cursors offer the mo
st features of any cursor type, but at the expense of increased overhead.
adOpenKeyset
Used to open a keyset cursor. Keyset cursors are like dynamic cursors, except ad
ditions made by other users are not visible in the recordset. The recordset is a
ffected by changes and deletions, however.
The LockType argument is an optional value that determines the type of locking t
hat the provider should use when opening the recordset. The possible values and
their descriptions are given below:
Value
Description
adLockReadOnly
(default) Specifies read-only locking. Records can be read, but data cannot be a
dded, changed, or deleted. This is the locking method used with static cursors a
nd forward-only cursors.
adLockPessimistic
Specifies pessimistic locking. The provider does what is necessary to ensure suc
cessful editing of records, usually by locking records at the data source immedi
ately upon editing.
adLockOptimistic
Specifies optimistic locking. The provider locks records only when you call the
Update method, not when you start editing.
adLockBatchOptimistic
Specifies optimistic batch locking. Records are locked in batch update mode, as
opposed to immediate update mode. This option is required for client-side cursor
s.
The Options argument is an optional Long value that indicates how the Source sho
uld be evaluated. The possible values and their descriptions are given below:
Value
Description
adCmdText
Indicates that the type of command in the CommandText argument is not known and
that the provider should attempt to interpret it. Typically results in poor perf
ormance.
adExecuteAsync
Indicates that the remaining rows after the initial quantity specified in the Ca
cheSize property should be fetched asynchronously.
'-----------------------------------------------------------------------------
Private Sub OpenNewRecordset()
'-----------------------------------------------------------------------------
Set mobjADORst = New ADODB.Recordset
mobjADORst.CursorLocation = adUseClient
mobjADORst.Open mstrSQL, mobjADOConn, adOpenStatic, , adCmdText
End Sub
6. Create the user-defined subprocedure DataLoad. This subprocedure gets the dat
a from the recordset and puts each field into a text box. Data from the recordse
t is accessed via the Fields collection.
The Fields collection in ADO works identically to the Fields collection in DAO.
A field can be referenced with or without specifying Fields, either by the field
name in quotes or by its ordinal position in the resultset. The field can also
be referenced with the bang (!) operator. All of the following would be valid wa
ys of referencing the field "propno":
mobjADORst.Fields("propno")
mobjADORst ("propno")
mobjADORst.Fields(0)
mobjADORst(0)
mobjADORst!propno
'-----------------------------------------------------------------------------
Private Sub DataLoad()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
7. Create the user-defined subprocedure SetRecNum. This sub displays the number
of the current record at the bottom of the screen. The AbsolutePosition and Reco
rdCount properties of the Recordset are used here.
The RecordCount property the total number of rows in the recordset. Note: Record
Count will not return a valid value with all cursor types (for example, RecordCo
unt will return -1 with a forward-only cursor.) To ensure a valid RecordCount va
lue, use either adOpenKeyset or adOpenStatic as the CursorType for server side c
ursors or use a client side cursor.
'-----------------------------------------------------------------------------
Private Sub SetRecNum()
'-----------------------------------------------------------------------------
StatusBar1.SimpleText = "row " & mobjADORst.AbsolutePosition _
& " of " & mobjADORst.RecordCount
End Sub
8. Code the events for the navigation buttons as shown below, using the recordse
t "Move" methods to move to the first, last, next, or previous record, respectiv
ely.
'-----------------------------------------------------------------------------
Private Sub cmdMoveFirst_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MoveFirst
Call DataLoad
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
'-----------------------------------------------------------------------------
Private Sub cmdMoveLast_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MoveLast
Call DataLoad
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
'-----------------------------------------------------------------------------
Private Sub cmdMoveNext_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MoveNext
If mobjADORst.EOF Then
Beep
mobjADORst.MoveLast
End If
Call DataLoad
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
'-----------------------------------------------------------------------------
Private Sub cmdMovePrevious_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MovePrevious
If mobjADORst.BOF Then
Beep
mobjADORst.MoveFirst
End If
Call DataLoad
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
9. When one of the check boxes is clicked, the label and text box next to it sho
uld be enabled (or disabled, if clicking the check box unchecks it). Note also t
hat the cmdGetData button (the one with the "Run Query Now" caption) should only
be enabled if one of the checkboxes is checked.
'-----------------------------------------------------------------------------
Private Sub chkCriteria_Click(Index As Integer)
'-----------------------------------------------------------------------------
'when the user clicks on a check box, enable the label and text
'box that go with it.
If chkCriteria(Index).Value = vbChecked Then
txtCriteria(Index).Enabled = True
lblCriteria(Index).Enabled = True
txtCriteria(Index).SetFocus
txtCriteria(Index).SelStart = 0
txtCriteria(Index).SelLength = Len(txtCriteria(Index).Text)
' enable the 'Run Query Now' button only if a box is checked.
cmdGetData.Enabled = True
Else
txtCriteria(Index).Enabled = False
lblCriteria(Index).Enabled = False
End If
End Sub
10. After the user has selected which fields to use and entered values in the te
xt boxes, they click the cmdGetData button to create a new recordset with new da
ta. Note that if the user selects (checks) a field, but does not enter search cr
iteria in the corresponding textbox, an error message is generated and the query
is not run.
'-----------------------------------------------------------------------------
Private Sub cmdGetData_Click()
'-----------------------------------------------------------------------------
End Sub
11. Save and run. Note: When entering the "Like" criteria for City and/or State,
you can use the wildcard character % to represent any number of characters and
the wildcard character _ (underscore) the represent a single character. For exam
ple, entering "M%" for the City criteria would return all rows where the city fi
eld begins with the letter "M".
Download the project files for this sample application here.
Sample Application 3
Sample Application 3 demonstrates how to add, update, and delete records with AD
O.
When the application is first run, the user is prompted to enter a minimum askin
g price to possibly limit the number of records they want to work with (i.e., "I
only want to work with properties that are selling for $200,000 or more). If th
e user wants to work with all properties, they would simply accept the default o
f 0 from the prompt. If the user clicks the Cancel button, the application will
end.
Once the user has entered the minimum asking price, the main screen of the appli
cation is displayed. Initially, the screen is in "browse" mode, where the user c
an use the navigation buttons to move to the first, previous, next or last recor
d. The data cannot be edited in this mode. If they want to initiate an add or an
update, delete a record, or exit the application, they may do so via the approp
riate button. Saving or cancelling is not applicable in this mode, so those butt
ons are disabled.
If the user clicks the Add button, the fields on the screen are enabled and clea
red, and the user can enter the information for the new property. All buttons ex
cept Save and Cancel are now disabled. After the user has made entries in the fi
elds, he or she would click Save to add the new record to the database table, or
, if they changed their mind, would click Cancel to discard the new record. In e
ither case (clicking Save or Cancel) the user is returned to browse mode. When S
ave is clicked, the application validates the entries and will only save the rec
ord if all fields pass edit (otherwise, a message will appear indicating the pro
blem entry and focus will be set to the problem field).
If the user clicks the Update button, the fields on the screen are enabled and t
he user can modify any or all of the fields (except for the Property Number, whi
ch is the primary key of the table). All buttons except Save and Cancel are now
disabled. After the user has made modifications in the desired fields, he or she
would click Save to update the record to the database table, or, if they change
d their mind, would click Cancel to discard the changes. In either case (clickin
g Save or Cancel) the user is returned to browse mode. When Save is clicked, the
application validates the entries and will only save the record if all fields p
ass edit (otherwise, a message will appear indicating the problem entry and focu
s will be set to the problem field).
If the user clicks the Delete button, the user is asked to confirm that they wan
t to delete the current record. If they respond Yes, the record is deleted from
the database table, and the main screen shows the next record in the table.
To build Sample Application 3, start a new VB project and perform the following
steps.
· From the Project -> References menu, check Microsoft ActiveX Data Object
s 2.x Library and click OK.
· This project uses the StatusBar control, so include the Microsoft Window
s Common Controls 6.0 (SP6) from the Components dialog box, accessed from the Pr
oject -> Components menu. Check this item and click OK.
· Create the form shown below. The settings for the various controls are g
iven below.
· There are nine textboxes in the main frame of the form. The names and Ma
xLength settings for these are given below:
Name
Properties
txtPropNo
MaxLength: 5
txtEmpNo
MaxLength: 4
txtAddress
MaxLength: 20
txtCity
MaxLength: 15
txtState
MaxLength: 2
txtZip
MaxLength: 5
txtBeds
MaxLength: 1
txtBaths
Name
Caption
cmdMoveFirst
<<
cmdMovePrevious
<
cmdMoveNext
>
cmdMoveLast
>>
cmdAdd
Add
cmdUpdate
Update
cmdDelete
Delete
cmdSave
Save
cmdCancel
Cancel
cmdExit
Exit
· All controls on your form should have their TabIndex property set such t
hat the tabbing order is correct.
· Add a Module to the project, name it modCommon, and enter the code shown
below. The code contains procedures described as follows:
CenterForm
Sub to highlight the text of a textbox when it receives focus. Used in the GotFo
cus event of a textbox.
TabToNextTextBox
Sub to "autotab" from one textbox to another when maximum number of characters t
hat can be entered into the first textbox has been reached.
UnFormatNumber
Function to strip out non-numeric characters (dollar signs, commas, etc.) from a
formatted number.
Option Explicit
'------------------------------------------------------------------------
Public Sub CenterForm(pobjForm As Form)
'------------------------------------------------------------------------
With pobjForm
.Top = (Screen.Height - .Height) / 2
.Left = (Screen.Width - .Width) / 2
End With
End Sub
'------------------------------------------------------------------------
Public Function ValidKey(pintKeyValue As Integer, _
pstrSearchString As String) As Integer
'------------------------------------------------------------------------
If pintKeyValue < 32 _
Or InStr(pstrSearchString, Chr$(pintKeyValue)) > 0 Then
'Do nothing - i.e., accept the control character or any key
' in the search string passed to this function ...
Else
'cancel (do not accept) any other key ...
pintKeyValue = 0
End If
ValidKey = pintKeyValue
End Function
'------------------------------------------------------------------------
Public Function ConvertUpper(pintKeyValue As Integer) As Integer
'------------------------------------------------------------------------
ConvertUpper = pintKeyValue
End Function
'-----------------------------------------------------------------------------
Public Sub SelectTextBoxText(pobjTextbox As TextBox)
'-----------------------------------------------------------------------------
With pobjTextbox
.SelStart = 0
.SelLength = Len(.Text)
End With
End Sub
'-----------------------------------------------------------------------------
Public Sub TabToNextTextBox(pobjTextBox1 As TextBox, pobjTextBox2 As TextBox)
'-----------------------------------------------------------------------------
End Sub
'-----------------------------------------------------------------------------
Public Function UnFormatNumber(pstrNumberIn As String) As String
'-----------------------------------------------------------------------------
End Function
'-----------------------------------------------------------------------------
Private Sub Form_Load()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
' obtain the minimum asking price for the properties to be worked with
GetMinimumAsking
' load the array of states to be used for validation
mavntUSStates = Array("AK", "AL", "AR", "AZ", "CA", "CO", "CT", "DC", _
"DE", "FL", "GA", "HI", "IA", "ID", "IL", "IN", _
"KS", "KY", "LA", "MA", "MD", "ME", "MI", "MN", _
"MO", "MS", "MT", "NC", "ND", "NE", "NH", "NJ", _
"NM", "NV", "NY", "OH", "OK", "OR", "PA", "RI", _
"SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", _
"WI", "WV", "WY")
'center the form:
CenterForm Me
' Connect to the Property database:
Set mobjADOConn = New ADODB.Connection
mobjADOConn.ConnectionString = "DSN=PropDB;Uid=admin;Pwd=;"
mobjADOConn.Open
Call GetPropertyData
SetFormState False
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
Code the GetMinimumAsking Sub, which uses the InputBox function to prompt to the
user to enter the minimum asking price of the properties they want to work with
. The resulting value is then stored in the form-level variable mdblMinAsking.
'-----------------------------------------------------------------------------
Private Sub GetMinimumAsking()
'-----------------------------------------------------------------------------
Dim strInputBoxPrompt As String
Dim strAsking As String
strInputBoxPrompt = "Enter the minimum asking price (for example, 200000) " _
& "for the properties that you want to work with this session." _
& vbNewLine _
& "To work with ALL properties, leave the default of zero."
strAsking = InputBox(strInputBoxPrompt, "Minimum Asking Price", "0")
If strAsking = "" Then
' user clicked Cancel button on the input box, so end the app
End
End If
mdblMinAsking = Val(strAsking)
End Sub
Code the GetPropertyData Sub, which builds the SQL to get the property records m
eeting the minimum asking price condition. The Recordset object is then instanti
ated, its CursorLocation property is set, and its Open method is invoked to exec
ute the SQL and return the resultset. This is done in a loop in case the results
et does not return any records due to the fact no records in the table met the a
sking price condition. In that situation, the user is given the opportunity to s
pecify a different asking price value. Following this, the programmer-defined Su
b PopulateFormFields is called (which displays the fields from the current recor
d in their corresponding textboxes on the form).
'-----------------------------------------------------------------------------
Private Sub GetPropertyData()
'-----------------------------------------------------------------------------
End Sub
Code the PopulateFormFields Sub, which assigns the fields from the current recor
d to their corresponding textboxes on the form. Note that the gblnPopulating Boo
lean variable is set to True prior to the assignments and set to False after the
assignments. This value is used to control whether or not certain code executes
in the event procedures for some of these textboxes. The Sub SetRecNum is then
called.
'-----------------------------------------------------------------------------
Private Sub PopulateFormFields()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
gblnPopulating = True
Call SetRecNum
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
Code the SetRecNum Sub. This sub is identical to the one used in Sample Applicat
ion 2. It displays the number of the current record at the bottom of the screen
using the AbsolutePosition and RowCount properties of the Recordset object.
'-----------------------------------------------------------------------------
Private Sub SetRecNum()
'-----------------------------------------------------------------------------
StatusBar1.SimpleText = "row " & mobjADORst.AbsolutePosition _
& " of " & mobjADORst.RecordCount
End Sub
Code the SetFormState Sub, which takes in a Boolean argument used to set the Ena
bled property of the controls on the form. Based on whether the value True or Fa
lse is passed to this sub, this sub ensures that the textboxes are enabled for a
dds and updates and disabled for browsing; it also ensures that the various comm
and buttons are enabled or disabled at the appropriate time. This Sub also sets
the form-level Boolean variable mblnUpdatePending.
'-----------------------------------------------------------------------------
Private Sub SetFormState(pblnEnabled As Boolean)
'-----------------------------------------------------------------------------
txtPropNo.Enabled = pblnEnabled
txtEmpNo.Enabled = pblnEnabled
txtAddress.Enabled = pblnEnabled
txtCity.Enabled = pblnEnabled
txtState.Enabled = pblnEnabled
txtZip.Enabled = pblnEnabled
txtBeds.Enabled = pblnEnabled
txtBaths.Enabled = pblnEnabled
txtAsking.Enabled = pblnEnabled
cmdSave.Enabled = pblnEnabled
cmdCancel.Enabled = pblnEnabled
cmdAdd.Enabled = Not pblnEnabled
cmdUpdate.Enabled = Not pblnEnabled
cmdDelete.Enabled = Not pblnEnabled
cmdExit.Enabled = Not pblnEnabled
cmdMoveFirst.Enabled = Not pblnEnabled
cmdMoveNext.Enabled = Not pblnEnabled
cmdMovePrevious.Enabled = Not pblnEnabled
cmdMoveLast.Enabled = Not pblnEnabled
mblnUpdatePending = pblnEnabled
End Sub
Code the Form_Unload event. In it, the form-level Boolean variable mblnUpdatePen
ding is tested to see if (well, an update is pending – i.e., whether an add or upd
ate is in progress). If the user is in the middle of an add or update and then c
licks the "X" button on the upper-right corner of the form, they will receive th
e message that they must save or cancel prior to exiting the application, and th
e form will NOT be unloaded (because we are assigning a non-zero value to the Ca
ncel argument in that situation). Provided that an add or update is not in progr
ess, we set the database objects to Nothing and the Unload will complete.
'-----------------------------------------------------------------------------
Private Sub Form_Unload(Cancel As Integer)
'-----------------------------------------------------------------------------
If mblnUpdatePending Then
MsgBox "You must save or cancel the current operation prior to exiting.", _
vbExclamation, _
"Exit"
Cancel = 1
Else
Set mobjADORst = Nothing
Set mobjADOConn = Nothing
End If
End Sub
Code the events for the various Textboxes as shown below. The code in these even
ts ensure the following:
· For all, highlight the text in the textbox when it receives focus.
· For all but the last textbox, if the maximum number of characters typed
into the textbox is reached, auto-tab to the next textbox.
· Only numeric digits should be entered into the property number, employee
number, zip codes, and beds textboxes.
· Only numeric digits and optionally one decimal point should be entered i
nto the baths and asking textboxes.
· Force uppercase on the state textbox.
· When the asking textbox receives focus, the value in there should be unf
ormatted. When the asking textbox loses focus, its value should be formatted as
currency.
'-----------------------------------------------------------------------------
' Textbox events
'-----------------------------------------------------------------------------
' property #
Private Sub txtPropNo_GotFocus()
SelectTextBoxText txtPropNo
End Sub
Private Sub txtPropNo_KeyPress(KeyAscii As Integer)
KeyAscii = ValidKey(KeyAscii, gstrNUMERIC_DIGITS)
End Sub
Private Sub txtPropNo_Change()
TabToNextTextBox txtPropNo, txtEmpNo
End Sub
' emp #
Private Sub txtEmpNo_GotFocus()
SelectTextBoxText txtEmpNo
End Sub
Private Sub txtEmpNo_KeyPress(KeyAscii As Integer)
KeyAscii = ValidKey(KeyAscii, gstrNUMERIC_DIGITS)
End Sub
Private Sub txtEmpNo_Change()
TabToNextTextBox txtEmpNo, txtAddress
End Sub
' address
Private Sub txtAddress_GotFocus()
SelectTextBoxText txtAddress
End Sub
Private Sub txtAddress_Change()
TabToNextTextBox txtAddress, txtCity
End Sub
' city
Private Sub txtCity_GotFocus()
SelectTextBoxText txtCity
End Sub
Private Sub txtCity_Change()
TabToNextTextBox txtCity, txtState
End Sub
' state
Private Sub txtState_GotFocus()
SelectTextBoxText txtState
End Sub
Private Sub txtState_KeyPress(KeyAscii As Integer)
KeyAscii = ConvertUpper(KeyAscii)
End Sub
Private Sub txtState_Change()
TabToNextTextBox txtState, txtZip
End Sub
' zip
Private Sub txtZip_GotFocus()
SelectTextBoxText txtZip
End Sub
Private Sub txtZip_KeyPress(KeyAscii As Integer)
KeyAscii = ValidKey(KeyAscii, gstrNUMERIC_DIGITS)
End Sub
Private Sub txtZip_Change()
TabToNextTextBox txtZip, txtBeds
End Sub
' beds
Private Sub txtBeds_GotFocus()
SelectTextBoxText txtBeds
End Sub
Private Sub txtBeds_KeyPress(KeyAscii As Integer)
KeyAscii = ValidKey(KeyAscii, gstrNUMERIC_DIGITS)
End Sub
Private Sub txtBeds_Change()
TabToNextTextBox txtBeds, txtBaths
End Sub
' baths
Private Sub txtBaths_GotFocus()
SelectTextBoxText txtBaths
End Sub
Private Sub txtBaths_KeyPress(KeyAscii As Integer)
KeyAscii = ValidKey(KeyAscii, gstrNUMERIC_DIGITS & ".")
' if text already has a decimal point, do not allow another ...
If Chr$(KeyAscii) = "." And InStr(txtBaths.Text, ".") > 0 Then
KeyAscii = 0
End If
End Sub
Private Sub txtBaths_Change()
TabToNextTextBox txtBaths, txtAsking
End Sub
Code the events for the navigation buttons as shown below, using the resultset "
Move" methods to move to the first, last, next, or previous record, respectively
.
'-----------------------------------------------------------------------------
Private Sub cmdMoveFirst_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MoveFirst
Call PopulateFormFields
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
'-----------------------------------------------------------------------------
Private Sub cmdMoveLast_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MoveLast
Call PopulateFormFields
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
'-----------------------------------------------------------------------------
Private Sub cmdMoveNext_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MoveNext
If mobjADORst.EOF Then
Beep
mobjADORst.MoveLast
End If
Call PopulateFormFields
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
'-----------------------------------------------------------------------------
Private Sub cmdMovePrevious_Click()
'-----------------------------------------------------------------------------
On Error GoTo LocalError
mobjADORst.MovePrevious
If mobjADORst.BOF Then
Beep
mobjADORst.MoveFirst
End If
Call PopulateFormFields
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
Code the Click event for the cmdAdd button. In it, the textboxes are cleared, th
e SetFormState sub is called (passing it a parameter of True, which will enable
the textboxes and the Save and Cancel buttons and disable all the other buttons)
, set the form-level variable mstrUpdateType to "A" (indicating that an add is p
ending) and sets focus to the Property Number field.
'-----------------------------------------------------------------------------
Private Sub cmdAdd_Click()
'-----------------------------------------------------------------------------
'-----------------------------------------------------------------------------
Private Sub cmdUpdate_Click()
'-----------------------------------------------------------------------------
SetFormState True
mstrUpdateType = "U"
' being that propno is the primary key, it should not be updatable
txtPropNo.Enabled = False
txtEmpNo.SetFocus
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
Code the Click event for the cmdSave button. The user would click this button af
ter they have completed entries for an add or update. This sub first invokes the
ValidateAllFields function, which returns a Boolean indicating whether or not a
ll entries passed their edit checks. If not, we exit the sub and the record is n
ot saved; the user remains in "update pending" mode and has the opportunity to c
orrect the entries. Provided that validation is successful, the sub proceeds. Th
e mstrUpdateType variable is checked to see whether we are dealing with an add o
r an update.
If we are dealing with an add, we invoke the AddNew method of the Recordset obje
ct. The AddNew method prepares a new row you can edit and subsequently add to th
e Recordset object using the Update method. After you modify the new row, you mu
st use the Update method to save the changes and add the row to the result set.
No changes are made to the database until you use the Update method. (The Update
method is invoked after the content of the textboxes has been assigned to the d
atabase fields.)
If we are dealing with an update, we can just start modifying the fields (provid
ed an appropriate cursor type has been selected) – unlike DAO and RDO, ADO does no
t use an Edit method. Changes made to the current row’s columns are copied to the
copy buffer. After you make the desired changes to the row, use the Update metho
d to save your changes or the CancelUpdate method to discard them. (If you move
on to another record without invoking Update, your changes will be lost.)
The content of the textboxes is assigned to the database fields, then the Update
method is invoked. The Update method saves the contents of the copy buffer row
to a specified updatable Recordset object and discards the copy buffer.
The mstrUpdateType variable is checked once again, and if we are dealing with an
add, there is some extra work to do. Although the new record has been added, th
e original resultset still does not contain the new record. The Requery method m
ust be invoked, which updates the data in a Recordset object by re-executing the
query on which the object is based. The Find method is then used to position to
the new record. The ADO Find method has the following syntax:
Code the Click event for the cmdDelete button. The user is first asked to confir
m that they want to delete the record, and if so, the Delete method of the resul
tset object is invoked, which deletes the current row in an updatable resultset
object. The Requery method is then invoked so that the record is removed from th
e resultset that the user is working with. The Find method is then invoked to po
sition the next record after the deleted one. If it was the last record that was
deleted, then we position to the "new" last record using the MoveLast property.
PopulateFormFields must then be called to display the contents of the new curre
nt record.
-----------------------------------------------------------------------------
Private Sub cmdDelete_Click()
-----------------------------------------------------------------------------
Exit Sub
LocalError:
MsgBox Err.Number & " - " & Err.Description
End Sub
-------------------------------------------------------------------------------
-
Private Function ValidState() As Boolean
-------------------------------------------------------------------------------
-
-----------------------------------------------------------------------------
Private Function PropertyExists() As Boolean
-----------------------------------------------------------------------------
End Function
Code the Click event for the cmdCancel button. The user would click this button
if, during an add or update, they decide to abandon the operation. Here, Populat
eFormFields is called to reset the textboxes to their content prior to the user
clicking the Add or Update button, and SetFormState is called with a parameter o
f False, which causes the textboxes and the Save and Cancel buttons to be disabl
ed and all other buttons to be enabled.
-----------------------------------------------------------------------------
Private Sub cmdCancel_Click()
-----------------------------------------------------------------------------
PopulateFormFields
SetFormState False
End Sub
Code the Click event for the cmdExit button, which issues the Unload Me statemen
t to fire the Form_Unload event, which will unload the form and end the applicat
ion.
-----------------------------------------------------------------------------
Private Sub cmdExit_Click()
-----------------------------------------------------------------------------
Unload Me
End Sub
Download the project files for this sample application here.