dcsimg
December 4, 2016
Hot Topics:

Book Review: Beginning Visual Basic 6 Objects

  • November 19, 2002
  • By James Limm
  • Send Email »
  • More Articles »

Now we've designed our interface, let's go ahead and translate all of these ideas into some real code with some real functionality behind it. Once we've created our class, we'll build a test framework to see it in action.

Try It Out – Creating a Class for DataDamage Inc

1 Start up a new project and, when it appears, add a new class module in the usual way. If you can't remember how to do that, then now might be a good time to re-read Chapter 1, or consult my other book, Beginning Visual Basic 6.

2 The next step is to start adding code into our new class module to implement all the methods and properties that we've just discussed. For now, just key in the following code so that your class module looks like mine. By typing this lot in you're sure to come up with some questions of your own as to how things work, and I can go ahead and start answering them when the code is done.

There is a lot of code here, but the interface is real simple, and the bulk of it is quite repetitive and easy to follow. We'll take a closer look at how it works once you've typed it in.

Option Explicit

' clsTitles - wraps up the Biblio Titles table. By keeping the
' interface consistent it should be possible to move the class 
' to point at some other data source, such as an RDO Resultset, 
' or flat file, without users of the class ever noticing.

Public Event DataChanged()

' Public members to implement properties
Public strTitle As String
Public intYear_Published As Integer
Public strISBN As String
Public lngPubID As Long
Public strDescription As String
Public strNotes As String
Public strSubject As String
Public strComments As String

' Private members to hold connection to database, 
' and to the recordset itself 

Private m_recTitles As Recordset
Private m_dbDatabase As Database

' Class event handlers

Private Sub Class_Initialize()
' When an instance of the class is created, we want to
' connect to the database and open up the Titles table.

On Error GoTo Class_Initialize_Error

Set m_dbDatabase = Workspaces(0).OpenDatabase _
(App.Path & "Biblio.mdb")

Set m_recTitles = m_dbDatabase.OpenRecordset("Titles", _
dbOpenTable)

Exit Sub

Class_Initialize_Error:
MsgBox "There was a problem opening either the Biblio " & _
"database, or the Titles table.", vbExclamation, "Problem"
Exit Sub

End Sub

Private Sub Class_Terminate()

' When the instance of the class is destroyed, we need to 
' close down the recordset, and also the connection to the 
' database. Error handling is needed since there could have 
' been a problem in the Initialize routine making these 
' connections invalid


On Error Resume Next

m_recTitles.Close
m_dbDatabase.Close

End Sub

' Generic Data management methods

Private Sub Reload_Members()
' Reloads the member variables (properties) with the field 
' values of the current record

On Error GoTo Reload_Members_Error

With m_recTitles

strTitle = "" & .Fields("title")
intYear_Published = .Fields("Year Published")
strISBN = "" & .Fields("ISBN")
lngPubID = .Fields("PubID")
strDescription = "" & .Fields("description")
strNotes = "" & .Fields("Notes")
strSubject = "" & .Fields("subject")
strComments = "" & .Fields("Comments")

End With

RaiseEvent DataChanged

Reload_Members_Error:
Exit Sub

End Sub

' Class methods 

Public Sub MoveNext()

If Not m_recTitles.EOF Then
m_recTitles.MoveNext
Reload_Members
End If

End Sub

Public Sub MovePrevious()
If Not m_recTitles.BOF Then
m_recTitles.MovePrevious
Reload_Members
End If

End Sub

Public Sub MoveLast()
m_recTitles.MoveLast
Reload_Members
End Sub

Public Sub MoveFirst()
m_recTitles.MoveFirst
Reload_Members
End Sub

3 Don't forget to give the class a name when you are done typing. In order for your code to work the same as mine, it makes sense that you set the name property for your new class to clsTitles (reminding us that this is a class related to Titles).

4 You've probably noticed that there's quite a lot of database code in there. In order for this code to compile properly, we need to let Visual Basic know that we intend to use a database, and that it's going to involve setting a reference to VB6's Data Access Objects (DAO).

You may recall, from Chapter 1, that DAO in Visual Basic 6 is an ActiveX component. As such, the DAO doesn't reside within Visual Basic itself, which is why we have to build a reference to it now.

From the Project menu in Visual Basic, select References, and the references dialog will appear. This provides us with a way to show Visual Basic which external objects (objects that live in DLLs or separate EXE files from your own app) that we intend to use. Scroll down the list of items until you see Microsoft DAO 3.51 Object Library and select it, just as in the screenshot below. Then close the dialog down by clicking the OK button:

Now that everything is in place for our new clsTitles class to work, we'll take a look at the code and how it works.

How It Works

The first thing that any class needs is a way for its users to get at the important elements of the underlying data. We do this by declaring properties for the class.

Designing an interface for a class involves declaring a set of properties in very much the same way as how we interact with a set of properties when we design a user interface for our applications.

Since this class is supposed to wrap up a lot of functionality to deal with the Titles table in the Biblio database, it makes sense for us to have some properties in there to represent the fields in the underlying database. Then, no matter what format of database we use in the future, programmers using our clsTitles class will know that they can use these field properties to get at the underlying data.

Rather than spend ages typing in Property Let and Property Get routines, we've gone for a simpler approach this time:

' Public members to implement properties

Public strTitle As String
Public intYear_Published As Integer
Public strISBN As String
Public lngPubID As Long
Public strDescription As String
Public strNotes As String
Public strSubject As String
Public strComments As String

You don't need to key all this in again - we're reviewing the code we just entered for our clsTitles class.

As you can see here, what we're doing here is declaring a set of Public variables within our clsTitles class. Public variables declared in a class in this way are, as far as Visual Basic is concerned, read and write properties. At runtime, a user of our clsTitles class can get directly at the Title property of the object, and at that point they will be reading from, or writing to, these Public variables.

We still have scope though to expand and write full-blown property handlers later, should the need arise.

Having variables acting as properties is great, but we still need code to get data from the database into those variables in the first place. That's where the Reload_Members routine comes in, reading data from the underlying recordset and storing it in our property variables:

Private Sub Reload_Members()
' Reloads the member variables (properties) with the field 
' values of the current record On Error GoTo Reload_Members_Error With m_recTitles strTitle = "" & .Fields("title") intYear_Published = .Fields("Year Published") strISBN = "" & .Fields("ISBN") lngPubID = .Fields("PubID") strDescription = "" & .Fields("description") strNotes = "" & .Fields("Notes") strSubject = "" & .Fields("subject") strComments = "" & .Fields("Comments") End With RaiseEvent DataChanged Reload_Members_Error: Exit Sub End Sub

All we're doing here is pulling values from the fields in the m_recTitles recordset and putting them into our member variables. At the end of this, we raise a custom event, which we've called DataChanged, since the user interface needs some way of knowing when these member variables have changed and it needs to update itself.

The m_recTitles recordset itself is opened up when the class is first turned into an object. Take a look at the class initializer: first

Private Sub Class_Initialize()

' When an instance of the class is created, we want to
' connect to the database and open up the Titles table.

On Error GoTo Class_Initialize_Error

Set m_dbDatabase = Workspaces(0).OpenDatabase _
(App.Path & "Biblio.mdb")

Set m_recTitles = m_dbDatabase.OpenRecordset("Titles", _
dbOpenTable)

Exit Sub

Class_Initialize_Error:
MsgBox "There was a problem opening either the Biblio " & _
"database, or the Titles table.", vbExclamation, "Problem"

Exit Sub
End Sub

This is pretty neat. Our clsTitles class is designed to deal with one specific table in a very specific database, Biblio.mdb. We therefore code the Class_Initialize event to make the class automatically connect to that database:

Set m_dbDatabase = Workspaces(0).OpenDatabase _
(App.Path & "Biblio.mdb")

Set m_recTitles = m_dbDatabase.OpenRecordset("Titles", _
dbOpenTable)

This, in turn, reduces the workload for a user of the class: how many of us have written a class, for example, where we require a user of that class to pass in the pre-connected database object ready to use?

A point worth noting, though, is that the code prefixes the name of the database with App.Path. What this means, in English, is that the clsTitles class will expect to find a copy of the Biblio database in the directory the project lives in, or where the compiled program lives when we're finished.

So now might be a good time to run up the Windows Explorer and make sure that there's a copy of the Biblio.mdb database in the same directory that you intend to save this project.

For any programs you write in the future that access databases, if you know the location of those databases then you can specify a particular path within your code, instead of using the App.Path method. In some circumstances, it may even be appropriate to ask the user to enter a pathname for any databases they want your program to work with.

The rest of our code for clsTitles provides an interface to support the common Move commands that we'd find on a recordset; in our case, this means just passing the call down to the recordset itself, before updating the member variables with the new information. Take a look at the MoveNext method, for example:

Public Sub MoveNext()

If Not m_recTitles.EOF Then
m_recTitles.MoveNext
Reload_Members
End If

End Sub

This code first makes a quick check to see if the end of the table has been reached. If we haven't reached the end of the table, we can move on to the next record - by calling the MoveNext method on the recordset itself. After that, our old friend the Reload_Members method is run, which will move the information from the underlying fields in the new recordset to our clsTitles member properties.





Page 5 of 9



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date
Rocket Fuel