Beruflich Dokumente
Kultur Dokumente
User Manual
Version 2.0
August 21, 1998
Introduction
Thank you for purchasing Datagrip™ from Integration New Media, Incorporated.
Datagrip is an extension Xtra for Macromedia Director and Authorware that provides a
powerful and simple interface to Microsoft Access-format databases1 . You can use Datagrip
to quickly store, retrieve, and sort all kinds of information for electronic catalogs, computer-
based training, and template-based presentations.
You can read and write data to Access databases, return sets of records based on an SQL
query, search for records, use stored queries, and perform most of the common database
operations that you can do through Microsoft Access. In addition, since Datagrip is fully
compatible with Microsoft Access version 1.0 through Access ‘97, you can use Access to
create, edit, and browse the databases you use with Datagrip. You can even share a single
database between multiple Director and Authorware programs.
1 Microsoft Access databases are usually stored in files with a .MDB extension. For example, the Datagrip tutorial
database is stored in the file named TUTOR.MDB in the Datagrip installation directory.
System Requirements
To use Datagrip you’ll need the following:
• Windows ’95, Windows ‘98 or NT 4.0 or later
• Macromedia Director version 5.0 (or later) or Macromedia Authorware 4.0 (or later)
• Internet connection for downloading
• At least 5 MB of free disk space
• Microsoft Access
Typographical Conventions
This manual uses several conventions designed to help clarify the text:
• Structured Query Language (SQL) statements are printed on a separate line or lines in a
bold font like this unless they are part of Macromedia Scripting Language code. For
example, the following is a simple SQL statement:
“SELECT * FROM CONTACTS WHERE COMPANY = ‘Integration New Media’”
• Datagrip function names used in the text are printed in bold type. For example,
DGRSFindNext is a Datagrip function.
• Macromedia Scripting Language code is printed a typewriter font like this:
set dbHandle = DGOpenDatabase(the moviePath & "Tutor.mdb")
if dbHandle = "#ERROR#" then
alert "Error: " & GetLastDGError()
alert "Now exiting the program."
ClearDGError()
quit
end if
• Macromedia Scripting Language handlers referred to in text blocks will use a typewriter
font. As an example, note the font difference when referencing a handler named
FillPhoneNumFields().
Note
The text in code blocks use the Macromedia Scripting Language syntax, so you
can copy them directly with one exception. On occasion, lines of code are split
when they are too long to fit on a single line in this manual. In those cases, the
last two characters of the line are “>>” These characters indicate that the next
line should be appended to the end of the current line. Do not include the “>>”
characters in the code.
If you have any questions about Datagrip's suitability for your application, we suggest you
download and try the evaluation version.
Installing Datagrip™
Datagrip™ is available for download from the Integration New Media web site:
http://www.INM.com/products/
Note
If you re-install Director in the future, you’ll need to re-install Datagrip as well
because parts of Datagrip are installed in an Xtras folder under the main
Director program folder.
Download the installer for the evaluation version and unzip it. Then double-click the installer,
named datagrip-demo-installer.exe and follow the instructions on screen. When installation
is complete, a new folder named DataGrip Xtra is created within Program Files > Integration
New Media. This DataGrip Xtra folder contains documentation and the following file:
- DGDemo.X32: Place this file in the Xtras folder within the Director/Authorware
application folder, for use during authoring time. (Note that in Director MX 2004,
the Xtras folder is in Program Files\Director MX 2004\Configuration\Xtras).
The evaluation version cannot be used in the "runime" environment, for playback of
projectors/packaged pieces.
After evaluating the demo version of DataGrip, you can purchase a license from INM's secure
online store: https://Store.INM.com
Once you have purchased your license you will be sent a Release version of the Xtra, which
you can test and distribute with your projects. Download the installer for the Release version
and unzip it. Then double-click the installer, named datagrip-release-installer.exe and
follow the instructions on screen. When installation is complete, the following Xtras will be
placed in the folder named Program Files > Integration New Media > DataGrip Xtra:
- DGDes.X32: Place this file in the Xtras folder within Director/Authorware, for use
during authoring time.
- DGRel.X32: Place this file beside your executable Director projector or Authorware
packaged piece, for playback and distribution.
This chapter will help get you started with using Datagrip™ by showing you step-by-step
how to build a simple Contact Manager application using Macromedia Director/Authorware
and Datagrip. This particular contact manager is used to organize a list of photographers or
artists and contains a bitmap field for showing a portfolio sample. Along the way, you’ll see
most of the key features of Datagrip in action, including segments of the code from the sample
application that illustrate the concepts. Following this overview chapter, there are detailed
chapters covering the use of Datagrip with Director and Authorware.
The complete application is included with Datagrip as a Director 6.0 file and as an
Authorware 4.0 file, so you can open it, run the application, and see how it all works together.
You can even copy code directly from the tutorial application as a starting point for your own
projects. You’ll find the Director file, called TUTOR.DIR and the Authorware file, called
TUTOR.A4P, in the Datagrip directory.
Figure 2a. A single database table with five phone number fields laid out in a row and column format.
A more efficient way to store the phone numbers and eliminate the restriction on the
maximum number of telephone fields is to use two related tables. Figure 3 shows a design
using related tables. In this design, the Contacts table stores information about the contact, but
it doesn’t store any phone numbers. A separate table called the Phone Number table, stores
only phone numbers and a description of each phone number. However, notice that each
record in the Phone Number table also has a “ContactID” field that identifies which contact in
the Contacts table this phone number belongs to. A single record in the Contacts table might
have dozens—even hundreds—of corresponding phone number entries in the Phone Number
Table. The entries in the two tables are linked together by ContactID field.
Contacts Table
ContactID FirstName LastName Address Company Title
Figure 3a. Row/column diagram of two tables related by the ContactID field make unlimited phone
number storage easy.
In this design, each contact can have as many phone numbers as needed, and the phone
number table doesn’t need any empty records if a contact only has one phone number.
The related tables might sound very complex to deal with. How would you go through the
two tables and find all the telephone numbers that belong to an individual contact? The
records for an individual contact might not even be all together in the Phone Number table!
Fortunately, you don’t have to do any sorting or any special work to find related records in the
two tables. Datagrip, working in concert with the Microsoft Access database system, does the
hard work for you. You simply write structured query language (SQL) queries to retrieve the
data you want. Datagrip does the rest.
Note
These tutorials assume some basic knowledge of database concepts, and of
Macromedia’s scripting language. While you should be able to follow the
tutorials with minimal database or scripting experience, if you need more help
we suggest looking through a couple of the books listed in Appendix B, More
Reading.
The tables in Figure 3 exist in the tutorial database file called TUTOR.MDB. You’ll find this
database in the Datagrip directory. If you have Microsoft Access, you can open the database
and examine the tables. You don’t need Microsoft Access to use Datagrip, but you’ll probably
find Access useful for designing and examining databases. In addition, Microsoft Access
makes it easy to import data into a database from a variety of other file formats.
With that background, let’s get started on developing the contact manager application.
Note
The TUTOR.MDB file is written in Access version 7.0 format (Microsoft Office
95) so that it will be compatible with all later versions of Access. If you are
using a later version of Access, you will probably see a message asking if you
want to convert the database to the newer format. Datagrip is compatible with
all database formats up to, and including Access ‘97, so it won't cause problems
to convert the database to the format for your version of Access.
This chapter will help get you started using Datagrip™ by showing you step-by-step how to build
a simple Contact Manager application using Macromedia Director. If you are using Authorware,
skip this chapter and refer to Chapter 4.
The tutorial has been re-written to take advantage of some of the new features of version 2.0. So
even if you are familiar with Datagrip, you may want to review this chapter.
Note
In the design environment the local directory is actually the directory that
Director is installed in. In the run-time environment, the local directory is the
directory where the projector is stored.
Otherwise, you may want to construct the full name of the path by combining the location of
the currently running movie with the name of the database. If, for example, the database is
located in the same directory as the currently playing movie, you can open the database like
this:
set dbHandle = DGOpenDatabase(the moviePath & "Tutor.mdb")
In this case Tutor.mdb was a local file, but Datagrip can also open databases on a networked
disk. This can be very useful when you need to share a database between multiple projectors.
Opening a database on a network drive is essentially the same as opening a local database,
except that you include the name of the computer that the database is stored on using the
Universal Naming Convention (UNC) format. For example, to open a database on the
computer named “FileServer” you would make the following call.
set dbHandle = DGOpenDatabase("\\FileServer\Tutor.mdb")
If the DGOpenDatabase function succeeds, it returns a number called a handle. You’ll want
to store this handle in a variable because you’ll use it in other Datagrip functions to refer to
the open database. In the example above, the handle is stored in the variable dbHandle.
2
An alternate form of the DGOpenDatabase command takes four parameters and allows for opening the database
exclusively, read-only, or with a specific connection string. Refer to the Language Reference section for details.
In the event that the DGOpenDatabase function fails, it will not return a number. Instead it
returns the special error string #ERROR#. The error might be caused by any number of
problems, such as a database file that is missing, or opened exclusively by another application
(such as Microsoft Access).
You should test the return value from DGOpenDatabase. If it is #ERROR#, you can use the
GetLastDGError function to get information on the cause of the problem.
Now let’s put what we’ve learned so far to practice. Following is the first part of the code
we’ll use to initialize the application in the InitDB function. This script is called from
startMovie.
In the first line, we open the database, which is located in the same directory as the movie file.
We store the handle that is returned in the global variable called dbHandle. Then we check to
see if an error occurred while opening by comparing dbHandle to #ERROR#. If
DGOpenDatabase returned #ERROR#, we call to GetLastDGError to find out what went
wrong and print out the error string that is returned.
After we’ve retrieved the error information, we call ClearDGError to reset the error
information. Since failing to open the database makes the program pretty useless, we exit at
this point.
Creating a Recordset
At this point, we have an open database, but we still haven’t retrieved any data. To read data
from the database, we need to create a recordset. A recordset, as the name implies, is a set of
records (rows) from one or more database tables. The recordset might contain all the records
in the table, or it might contain only a few records, based on some criteria we specify in an
SQL query.
To create a recordset, call the DGCreateRecordset function, which takes two parameters.
The first parameter is an SQL query string that defines which fields and records in the
database should be included in the recordset. The second parameter is the handle to the open
database, which was returned from DGOpenDatabase. Here’s what a typical call to
DGCreateRecordset looks like:
set rsHandle = DGCreateRecordset("SELECT * FROM Contacts", dbHandle)
returns only contacts where the company field contains the string “INM”.
Note
If you’re not familiar with SQL, we recommend you refer to one of the books on
Microsoft Access or SQL in the More Reading section.
The DGCreateRecordset function also returns a handle, much like the DGOpenDatabase
function. You’ll want to store this handle as well because you’ll use it to read and write data
from the recordset and perform other functions on the recordset. If DGCreateRecordset
encounters an error, it returns the standard error string, #ERROR#.
Now let’s put together the open database code from the previous example with the code
required to open the recordset.
-- Global data handles that will be used
–- for the database and recordset.
global dbHandle
global rsHandle
global qdHandle
--
-- Open the contacts database assuming
-- that it exists in the local directory.
-- If it doesn't we will get an error back
-- that we can use to communicate with the user.
--
set dbHandle = DGOpenDatabase(the moviePath & "Tutor.mdb")
if dbHandle = "#ERROR#" then
alert "Error: " & GetLastDGError()
alert "Now exiting the program."
ClearDGError()
quit
end if
--
--This SQL string will define our
--recordset. It essentially means
--Select everything that exists
--inside the Contacts table.
--
set sqlString = "SELECT * FROM Contacts"
--
--Open a recordset using our above created
--SQL string and our database handle
--
set rsHandle = DGCreateRecordset(sqlString, dbHandle)
if rsHandle = "#ERROR#" then
alert "Error: " & GetLastDGError()
alert "Now exiting the program."
Quit
end if
Typically, a recordset contains one or more records based on the criteria used to create the
recordset. In the above example, the recordset contains all of the records in the “Contacts”
table. Although the recordset can contain more than one record, there is a single record that is
considered the current record – the record that is “pointed to”. It is this current record that
many functions will operate on. For instance, deleting, editing, updating, etc all operate on the
current record. If a record is added to the recordset, the current record position will point to
the newly added record. This is an extremely important concept in understanding how
databases work.
At this point, the recordset contains all the information from our Contacts table. But what
about the PhoneNumber table? There are several ways we can gain access to the
PhoneNumber data. One simple method is to use a join in SQL. You simply replace the SQL
string with this:
SELECT Contacts.*, PhoneNumbers.*
FROM Contacts INNER JOIN PhoneNumbers ON Contacts.ContactID = PhoneNumbers.ContactID;
Now the recordset contains all the fields from the Contacts table and the PhoneNumbers table
(refer to Figure 4). Better still, the database has automatically matched up all the contacts with
their corresponding Phone Numbers. The only disadvantage to using this technique is that the
recordset actually contains one record for every contact and every phone number. This means
that if a contact has three phone numbers, the contact will exist three times in the recordset—
once with each of his or her phone numbers. For more information on SQL joins, refer to the
one of the books in Appendix B, More Reading.
Figure 4. The recordset returned from the SQL join of the Contacts table and the PhoneNumber table.
For our purposes, the SQL join probably isn’t the best way to retrieve the phone numbers.
Instead, for each contact, we’ll create a second recordset that contains all the phone numbers
for the current contact.
The query string (queryStr) says “get all the records in the PhoneNumbers table whose
ContactID is equal to CurContact. CurContact is the variable that contains the Contact ID for
the current contact. For example, if the current contact contained “2” in the ContactID field,
then the query above would return the recordset shown in Figure 5.
The advantage of stored queries is that they are faster than query strings in your code and they
improve the maintainability of your program. If you use a particular query several places in
your code, it’s also easier to maintain a single query in the database than defining it all the
places you need it in your code.
The first parameter to DGQDOpen is the name of the stored QueryDef. The second
parameter is the database handle returned from DGOpenDatabase.
By now, you recognize the error checking code. The DGQDOpen function returns a handle
just like the open database and create recordset functions we’ve used so far. You’ll use the
Notice that the DGQDCreateRS function takes only one parameter—a QueryDef handle.
That’s because the QueryDef handle refers to a stored query in the database, so you don’t
need an SQL string or database handle.
Parameterized Queries
You’ll often want to use a stored query, but change one of its parameters. In the case of our
contact manager, we’ll use the following query to find the phone numbers for the current
contact:
PARAMETERS pContactID Long;
SELECT *FROM PhoneNumbers WHERE (PhoneNumbers.ContactID=[pContactID]);
This query was created by using the Microsoft Access query designer. If you are comfortable
with SQL, you can simply type the SQL directly to create the query. In any event, this SQL is
saved as a query in Access.
Notice the use of the parameter “pContactID”. This is called a “parameterized query” and is
very useful in many applications where you want to create a recordset based on some set of
criteria, typically a field equal to some value. You can specify more than one parameter but
each parameter will have to be set before using the query.
Note
There are numerous advantages to using stored queries in Microsoft Access and
working with QueryDef objects to access them in Datagrip. In addition to better
performance, stored queries can improve the reliability and maintenance of
your program by eliminating the use of hard-coded SQL in your code. Once a
QueryDef has been defined, it can be modified to sort the records or join with
another table without having to make changes in Lingo.
In the first line we use a new Datagrip function to read the value of the ContactID field from
the Contacts table using a recordset we’ve previously created. As long as no error occurred in
reading the value, we use that value in a DGQDSetParameterValue function. This function
takes three parameters:
We won’t discuss the details of setting up a parameterized query in this tutorial. For more
information, refer to the reference section for the Datagrip QueryDef functions, which all
begin with DGQD. An example of using a parameterized query is included in the tutorial
example. Refer to the handler named FillPhoneNumFields in the tutorial to see an
example of using a parameterized QueryDef.
There are several different approaches to displaying the field information on the stage. Two
methods will be described – field binding and manually updating field values. The tutorial
actually uses both approaches in order to show exactly how each method is implemented.
Binding Fields
One very powerful feature of Datagrip is the ability to directly bind Director cast members to
database fields. Binding will result in the automatic update of the cast member whenever the
current record changes. Field binding is accomplished by using the function DGRSBindField
as shown in the following code:
--
-- Link each field to it's appropriate Database field
--
DGRSBindField("FirstName_Field", "FirstName", rsHandle)
DGRSBindField("LastName_Field", "LastName", rsHandle)
DGRSBindField("Company_Field", "Company", rsHandle)
DGRSBindField("Title_Field", "Title", rsHandle)
All of the code to this point in the tutorial can be found in the handler initDB, which is
included in the script cast member, “StartupScripts”.
Using DGRSGetFieldValue()
There are some situations where automatic field binding may not be the best choice. For
example, if the database stored codes in a particular field and you wanted to display the text
associated with the code, you may have to get the field value and convert the code to a string
using a property list or some other approach. In this case, you may want to use the function
DGRSGetFieldValue.
In the current tutorial, one field, the address field, is not bound and must be manually updated
whenever the position of the current record changes. You will see code similar to the
following code segment in a number of different functions (GoToNextRecord,
GoToPrevRecord, etc.)
Prior to the field binding feature being added to Datagrip, the tutorial included a handler
called FillFields that was called each time the record position was changed. The code
below shows how FillFields managed the display of the contact information.
on FillFields
global qdHandle
global rsHandle
--
-- Check to see if we have any records
--
if DGRSGetRecordCount(rsHandle) <= 0 then return
--
-- If so, fill the fields on the stage with the data
-- from the database.
--
SetFieldVal("FirstName_Field", "FirstName")
SetFieldVal("LastName_Field", "LastName")
SetFieldVal("Address_Field","Address")
SetFieldVal("Title_Field", "Title")
SetFieldVal("Company_Field", "Company")
. . .
Note
The current tutorial uses field binding for all but the Address field. This section
shows how field values where updated on stage in the Tutorial that
accompanied version 1.0 of Datagrip.
If there is at least one record in the recordset, we call another function called SetFieldVal
to transfer the data between the recordset and the corresponding field on the screen.
SetFieldVal takes two parameters. The first one is the name of the cast member where we
will put the text we get from the database. The second is the name of the field in the database
that contains the text. Here’s the SetFieldVal function:
on SetFieldVal fieldName, dbField
global rsHandle
set val = DGRSGetFieldValue(dbField, rsHandle)
if val = "#ERROR#" then
alert "Error while retrieving from " & fieldName & RETURN & GetLastDGError()
ClearDGError()
set the text of member fieldName = ""
else
set the text of member fieldName = val
end if
end
Notice that we declare the rsHandle variable as global again, since we use it throughout the
code. Next, we call a new Datagrip function called DGRSGetFieldValue that retrieves the
data from a specified field. The first parameter to DGRSGetFieldValue is the name of the
field we want to read data from. The second parameter is the recordset handle.
If you look back up at the FillFields functions above, you’ll see that the first call to
SetFieldVal passes a database field name of “FirstName” (the second parameter to
SetFieldVal). That name is stored in the dbField variable inside SetFieldVal, which is,
in turn, passed on to the DGRSGetFieldValue function. The other parameter to
SetFieldVal is the name of the cast member on the stage that will receive the data from the
database.
DGRSGetFieldValue checks for an error using the standard method. If an error occurs, it
clears the field on screen by setting it to the empty string. Otherwise, the field on the stage is
set to the text read from the database.
Once the FillFields function has called SetFieldVal for each of the fields in the contact
table, all the contact information is filled out. The next step is to get the phone numbers for the
current contact and display them.
global rsHandle
global qdHandle
--
-- First, get the value of the contact ID from the current
-- record of the contact recordset
--
set val = DGRSGetFieldValue("ContactID", rsHandle)
--
--Create a grid and add the needed fields
--
set gridHandle = DGCreateGrid("PhoneNum_Field", tmpRS)
DGGridAddField("Description", 13, gridHandle)
DGGridAddField("PhoneNumber", 14, gridHandle)
--
--Tell the grid to fill in all of the data
--
DGGridUpdate(gridHandle)
end if
end if
end
First, the global variables rsHandle and qdHandle are declared as usual. Remember, rsHandle
is the recordset handle for the Contacts table that was opened in the function InitDB.
Likewise, the QueryDef handle qdHandle is the parameterized query that was created in the
same function at startup time. It will be used to create a recordset of phone records that
corresponds to the current contact.
Next, the variable val is set to the value of the ContactID field of the current record of
Contacts recordset. Once again, you will want to check to make sure the function did not
return an error.
Setting the parameter value and opening the recordset using the QueryDef object is done
exactly as described earlier by calling DGQDSetParameterValue and DGQDCreateRS.
The first argument of DGCreateGrid is the name of the Director field cast member while the
second argument is the handle to a recordset. Following the creation of the grid, calling
DGGridAddField will add new fields to the grid object in a left to right fashion. The first
argument to DGGridAddField is the name of the field in the recordset. The second argument
is the character width of the grid column and the third argument is a handle to a Datagrip grid
object.
Note
If the contents of the field has more characters than the column width specified
in the DGGridAddField function, the contents will be truncated.
The recordset we created with the QueryDef in the previous section contains all the phone
numbers associated with the current contact. The following repeat loop reads the phone
number and description fields from each phone number record and fills a single large string
that has carriage returns between each phone number and description. Here’s the code:
repeat while not DGRSIsEOF(tmpRS)
set desc = DGRSGetFieldValue("Description", tmpRS)
if desc = "#ERROR#" then set desc = ""
set num = DGRSGetFieldValue("PhoneNumber", tmpRS)
if num = "#ERROR#" then set num = ""
set tmpStr1 = tmpStr1 & padText(desc) & num & RETURN
DGRSMoveNext(tmpRS)
end repeat
DGRSClose(tmpRS)
The loop begins with a call to DGRSIsEOF. This function returns a non-zero value if we’ve
gone past the end of the phone number recordset. Remember that tmpRS is the recordset
handle we created in the previous code segment. When we increment past the last record, the
loop stops.
For each pass through the loop (each phone number), we’ll read the value of the Description
and Phone Number fields by calling DGRSGetFieldValue for each field. We do the standard
error checking, and set the appropriate strings to empty if an error occurs. Once we’ve read
both the description and phone numbers from the database, we append them together with
The padText function is a little function that is used only to add enough white space to get
the phone number and description fields to line up on screen. We won’t take the time to go
through that function here. If you want to see how it works, it is included at the end of this
section.
At the bottom of the loop, we call DGRSMoveNext to move to the next record in the phone
numbers recordset. This process continues until we reach the last record in the recordset. The
DGRSClose function at the end of the loop closes the recordset we created to read the phone
numbers.
When the loop finishes, tmpStr1 will contain all the phone numbers and descriptions for the
selected contact, separated by carriage returns as shown in Figure 1.
Then it’s a simple matter to assign this string to the cast member that contains the list on
screen:
set the text of member "PhoneNum_Field" = tmpStr1
The PadText function is used to line up the two columns of the list box by adding white
space or truncating characters thus forcing it to appear as a multi-column grid. Here is the
code.
on PadText str
--
--Set the num of chars before the next column
--
set padLength = 20
return str
end
There are three major steps to follow whenever you want to add a new record to a database or
change an existing record in the database. Here are the steps:
1. Call DGRSAddNew to add a new empty record or call DGRSEdit to edit an existing record.
Now that you know the process, let’s look at how we would implement code to add a new
record to our contact database. The following script, which is placed under the “New” button
does just that:
on CreateNewRecord
global rsHandle
if DGRSGetEditMode(rsHandle)=2 then
SaveCurrentData()
end if
DGRSAddNew(rsHandle)
end
If this function returns a 2, it means that a new record has been added to the database but not
yet saved or that the recordset was opened for editing (DGRSEdit) but has not been updated
(DGRSUpdate). If that is the case, we’ll call the SaveCurrentData function to transfer
data on the screen to the database. Then we’ll call the DGRSUpdate function to save the data
in the database.
Now that the previous data, if any, has been saved, we call the DGRSAddNew function to
add a new empty record.
Let’s back up for a moment and look at what’s inside the SaveCurrentData function that
we called to save the data. Here’s the code:
on SaveCurrentData
global rsHandle
SaveDBField("FirstName")
SaveDBField("LastName")
SaveDBField("Address")
SaveDBField("Title")
SaveDBField("Company")
DGRSUpdate(rsHandle)
end
First you see the standard global declaration for the recordset handle. The main part of the
function makes five calls to SaveDBField and passes the name of the database field we want
to save. After we’ve saved all the fields, we call DGRSUpdate to store the results in the
database.
The DGRSSetFieldValue function takes three arguments. The first function is the name of
the field we want to store data in. That name is passed in to the function. The second
argument is the data we want to store. In this case, the data comes from the text of the cast
member whose name is the same as the field name with a “_Field” appended to the end. The
last parameter is the global recordset handle.
Moving through the database one record at a time is pretty easy. We’ll add two functions
called GoToNextRecord and GoToPrevRecord and we’ll tie these to the Next and
Previous buttons on screen. The two functions are so close to identical, that we’ll just show
you the GoToPrevRecord function and point out the differences between the two. You can
see the GoToNextRecord function in TUTOR.DIR.
on GoToPrevRecord
global rsHandle
if DGRSGetEditMode(rsHandle) = 2 then
SaveCurrentData()
end if
DGRSMovePrev(rsHandle)
if DGRSIsBOF(rsHandle) then
DGRSMoveNext(rsHandle)
end if
end
The first block of code should look familiar. It’s the same code we used in the
CreateNewRecord function. It calls DGRSGetEditMode function to find out if there’s
some unsaved data. We want to save the data before we move to a new record.
Once we’ve taken care of saving any unsaved data, we’re ready to move to the previous
record. We call the DGRSMovePrev function to make the move. The only problem with this
is that we might already be at the first record. To take care of that situation, we call
DGRSisBOF. This function returns a non-zero value (true) if we are past the beginning of the
recordset. It’s important to remember that it only returns true if we are past the beginning of
the data. It won’t do any good to call DGRSisBOF before you move, because it doesn’t
return true until you’ve moved past the beginning.
Each time the user clicks on the Next or Previous buttons, we call the corresponding function,
which moves to the next record in the contact recordset, until we reach the beginning or end
of the records. Each time we move to a new record, we’ll also need to call the code to get the
corresponding phone numbers from the phone number table. We saw this code when we
looked at QueryDefs. If field binding is used, the fields will automatically display the data
corresponding to the new record. Otherwise, call the FillFields handler to update the
screen.
Following is the code for a function that will be called when the user clicks the “Add Phone
Number” button.
The code begins in the usual way by declaring our global handles. The next block should also
be familiar. It checks for unsaved data and saves the data if necessary.
Now the real work begins. The next two lines copy the text from the cast members that store
the phone numbers and descriptions (tmpNum_Field and tmpDesc_Field) to temporary
variables. We need to check whether there are, in fact, any phone numbers or descriptions
entered, so the next line checks the number of words in the temporary variables. If they’re
both zero, we just quit. There’s no point in creating a new record to store empty strings.
If there is something to store, we read the ContactID field from the current contact record. As
long as there was no error in reading the ContactID value, we create a recordset from the
PhoneNumber table based on that contact ID. The query in the DGCreateRecordset function
says “get all the records in the PhoneNumbers table that have a ContactID of id. Id is the
variable that stores the ContactID we read from the Contacts table. The result is that the
tmpRS recordset contains all the phone numbers associated with the current contact.
Next, we add a new record to the recordset we just created. Then we call
DGRSSetFieldValue to store the ContactID, Description, and Phone Number fields for the
new record. Finally, we call DGRSUpdate to store the new record in the database and
DGRSClose to close the phone number recordset. Notice that we’re closing the phone
number recordset (tmpRS), not the contacts recordset (rsHandle).
When you open TUTOR.DIR, you’ll find that any functions that work directly with the
database are in the script titled “DB Scripts”. Any functions that deal with the stage or user
interface are in “Interface Scripts”. Functions that initialize the entire application are located
in “Startup Scripts”.
This tutorial is designed to provide a high-level overview of Datagrip and show some
examples of using it in code. The tutorial only covers a small part of Datagrip’s functionality.
You’ll want to look through the Language Reference chapter to see all the other things
Datagrip can do.
As a final exercise, you might consider adding search capability to the contact manager.
You’ll need to add a new button to invoke a search, and perhaps a dialog box to enter the
search text. You can use the DGFindFirst function to search the database for a match.
Thank you for choosing Datagrip from Integration New Media, Inc.
This chapter will help get you started using Datagrip™ by showing you step-by-step how to build
a simple Contact Manager application using Macromedia Authorware. If you are using Director,
refer to the previous chapter.
In this case Tutor.mdb was a local file, but Datagrip can also open databases on a networked
disk. This can be very useful when you need to share a database between multiple projectors.
Opening a database on a network drive is essentially the same as opening a local database,
except that you include the name of the computer that the database is stored on using the
Universal Naming Convention (UNC) format. For example, to open a database on the
computer named FileServer you would make the following call.
dbHandle := DGOpenDatabase(“\\\\FileServer\\Tutor.mdb”)
If the DGOpenDatabase function succeeds, it returns a number called a handle. You’ll want
to store this handle in a variable because you’ll use it in other Datagrip functions to refer to
the open database. In the example above, the handle is stored in the variable dbHandle.
Every database you open will have a unique handle, so you can simultaneously open as many
databases as you need. Remember to store the handle for each open database in a separate
variable so you’ll have a way to refer to the databases in other parts of your code.
In the event that the DGOpenDatabase function fails, it will not return a number. Instead it
returns the special error string #ERROR#. The error might be caused by any number of
problems, such as a database file that is missing, or opened exclusively by another application
(such as Microsoft Access).
You should test the return value from DGOpenDatabase. If it is #ERROR#, you can use the
GetLastDGError function to get information on the cause of the problem.
Now let’s put what we’ve learned so far to practice. Following is the first part of the code
we’ll use to initialize the application. This code is located in the OpenDatabase icon.
In the first line, we open the database, which is located in the same directory as the movie file.
We store the handle that is returned in the global variable called dbHandle. Then we check to
see if an error occurred while opening by comparing dbHandle to #ERROR#. If
DGOpenDatabase returned #ERROR#, we call to GetLastDGError to find out what went
wrong and print out the error string that is returned.
After we’ve retrieved the error information, we call ClearDGError to reset the error
information. Since failing to open the database makes the program pretty useless, we exit at
this point.
Creating a Recordset
At this point, we have an open database, but we still haven’t retrieved any data. To read data
from the database, we need to create a recordset. A recordset, as the name implies, is a set of
records (rows) from one or more database tables. The recordset might contain all the records
in the table, or it might contain only a few records, based on some criteria we specify in an
SQL query.
To create a recordset, call the DGCreateRecordset function, which takes two parameters.
The first parameter is an SQL query string that defines which fields and records in the
database should be included in the recordset. The second parameter is the handle to the open
database, which was returned from DGOpenDatabase. Here’s what a typical call to
DGCreateRecordset looks like:
rsHandle := DGCreateRecordset("SELECT * FROM Contacts", dbHandle)
The first parameter is the SQL string, which says, “create a recordset that contains all fields
and all records from the Contacts table”. The query string could also specify that only records
that meet a certain criteria be returned. For example, the SQL string:
“SELECT * FROM CONTACTS WHERE COMPANY = ‘Integration New Media’”
returns only contacts where the company field contains the string “Integration New Media”.
Note
If you’re not familiar with SQL, we recommend you refer to one of the books on
Microsoft Access or SQL in the More Reading section.
The DGCreateRecordset function also returns a handle, much like the DGOpenDatabase
function. You’ll want to store this handle as well because you’ll use it to read and write data
from the recordset and perform other functions on the recordset.
--
-- Create the recordset
--
QueryStr := "Select * from Contacts ORDER BY Contacts.LastName"
rsHandle := DGCreateRecordset(QueryStr, dbHandle)
if rsHandle = "#ERROR#" then
LastErrorTxt := LastErrorTxt^"\rError in icon Get Record Set ...: "^GetLastDGError()
ClearDGError()
quit
end if
You’ve already seen the first block of code that opens the database, so let’s start with opening
the recordset. We call the DGCreateRecordset with an SQL string that returns all the records
and fields from the Contacts table. We store the return value in rsHandle and check it for the
standard #ERROR# string. If an error occurs, we get the error information, print the error
string, and exit.
At this point, the recordset contains all the information from our Contacts table. But what
about the PhoneNumber table? There are several ways we can gain access to the
PhoneNumber data. One simple method is to use a join in SQL. You simply replace the SQL
string with this:
SELECT * From Contacts,PhoneNumbers Where Contacts.ContactID=PhoneNumber.ContactID
Or, alternatively:
SELECT Contacts.*, PhoneNumbers.* FROM Contacts INNER JOIN PhoneNumbers >>
ON Contacts.ContactID = PhoneNumbers.ContactID;
Now the recordset contains all the fields from the Contacts table and the PhoneNumbers table
(refer to Figure 5). Better still, the database has automatically matched up all the contacts with
their corresponding Phone Numbers. The only disadvantage to using this technique is that the
recordset actually contains one record for every contact and every phone number. This means
that if a contact has three phone numbers, the contact will exist three times in the recordset—
once with each of his or her phone numbers. For more information on SQL joins, refer to the
one of the books in Appendix B, More Reading.
For our purposes, the SQL join probably isn’t the best way to retrieve the phone numbers.
Instead, for each contact, we’ll create second recordset that contains all the phone numbers for
the current contact.
We could create the second record using another DGCreateRecordset call, much like the
first one. Assuming that we have the ContactID value for the contact whose phone numbers
we want to find, here’s what the code would look like:
queryStr := "SELECT * From PhoneNumbers Where ContactID=" ^CurContact
rsHandle := DGCreateRecordset(queryStr, dbHandle)
The query string (queryStr) says “get all the records in the PhoneNumbers table whose
ContactID is equal to CurContact. CurContact is the variable that contains the Contact ID for
the current contact.
The advantage of stored queries is that they are faster than query strings in your code- up to
25% faster than opening a recordset with an SQL string. If you use a particular query several
places in your code, it’s also easier to maintain a single query in the database than defining it
all the places you need it in your code.
The first parameter to DGQDOpen is the name of the stored QueryDef. The second
parameter is the database handle returned from DGOpenDatabase.
By now, you recognize the error checking code. The DGQDOpen function returns a handle
just like the open database and creates recordset functions we’ve used so far. You’ll use the
Notice that the DGQDCreateRS function takes only one parameter—a QueryDef handle.
That’s because the QueryDef handle refers to a stored query in the database, so you don’t
need an SQL string or database handle.
Parameterized Queries
You’ll often want to use a stored query, but change one of its parameters. In the case of our
contact manager, we’ll use the following query to find the phone numbers for the current
contact:
"SELECT * From PhoneNumbers Where ContactID = " ^CurContact
We’ll store this query in the database as a QueryDef. However, we need to supply a value for
the CurContact variable each time we use the query. This is called a “parameterized query”
because we store the query, but we can modify one or more of the query’s parameters in our
code.
In the first line we use a new Datagrip function to read the value of the ContactID field from
the Contacts table using a recordset we’ve previously created. As long as no error occurred in
reading the value, we use that value in a DGQDSetParameterValue function. This function
takes three parameters:
pContactID is the name of the parameter in the query that we want to set.
Val is the value that we’re setting for the parameter
qdHandle is a handle to a previously opened QueryDef.
We won’t discuss the details of setting up a parameterized query in this tutorial. For more
information, refer to the reference section for the Datagrip QueryDef functions, which all
begin with DGQD or refer to the Microsoft Access help.
Once the parameter values are set with DGSetParameterValue, we call DGCreateRS to
create a recordset based on the QueryDef with the parameter values we set. When this code
segment finishes executing, the tmpRS recordset should contain all the phone numbers for the
particular ContactID we read from the Contacts table.
There are several different approaches to displaying the field information on the screen. Two
methods will be described – field binding and manually updating field values. The tutorial
actually uses both approaches in order to show exactly how each method is implemented.
Binding Fields
One very powerful feature of Datagrip is the ability to directly bind Authorware variables to
database fields. Binding will result in the automatic update of the variable whenever the
current record changes. Field binding is accomplished by using the function DGRSBindField
as shown in the following code:
--
-- Link each variable to it's appropriate Database field
--
DGRSBindVar("FirstNameStr", "FirstName", rsHandle)
DGRSBindVar("LastNameStr", "LastName", rsHandle)
DGRSBindVar("TitleStr", "Title", rsHandle)
DGRSBindVar("CompanyStr", "Company", rsHandle)
The DGRSBindField function takes three parameters. The first parameter specifies the name
of the variable that will be bound. The second parameter is the name of the field in the
recordset, and the third parameter is a recordset handle.
All of the code to this point in the tutorial can be found in the “Setup Handlers & Fields” icon
in the source file.
Using DGRSGetFieldValue()
There are some situations where automatic field binding may not be the best choice. For
example, if the database stored codes in a particular field and you wanted to display the text
associated with the code, you may have to get the field value and convert the code to a string
using a property list or some other approach. In this case, you may want to use the function
DGRSGetFieldValue.
In the current tutorial, one field, the address field, is not bound and must be manually updated
whenever the position of the current record changes. You will see code similar to the
following code segment in a number of different icons (Next >, Prev <, etc.)
AddressStr := DGRSGetFieldValue("Address", rsHandle)
Prior to the field binding feature being added to Datagrip, the tutorial was designed so that any
time the recordset changed a series of calls would be made to DGRSGetFieldValue. This
DGRSGetFieldValue checks for an error using the standard method. If an error occurs, it
clears the field on screen by setting it to the empty string.
--
--Create a grid object and tie the phone number fields to it
--
gridHandle := DGCreateGrid("PhoneGrid", phHandle)
DGGridAddField("Description", 7, gridHandle)
DGGridAddField("PhoneNumber" ,15, gridHandle)
DGGridUpdate(gridHandle)
--
--Close the recordset since it will change
--every time we change records.
--
DGRSClose(phHandle)
Here is how the handler works. First, the variable CurContact is set to the value of the
ContactID field of the current record of Contacts recordset. Once again, you will want to
check to make sure the function did not return an error.
Setting the parameter value and opening the recordset using the QueryDef object is done
exactly as described earlier by calling DGQDSetParameterValue and DGQDCreateRS.
The next step is to make a call to DGCreateGrid to create a grid object and call
DGGridAddField for each of the columns that we want to display. Then, we call
DGGridUpdate to automatically fill the grid with the field values specified for all of the
records in the recordset. No looping required and much faster!
The first argument of DGCreateGrid is the name of the Authorware variable while the
second argument is the handle to a recordset. Following the creation of the grid, calling
Note
If the contents of the field has more characters than the column width specified
in the DGGridAddField function, the contents will be truncated.
The recordset we created with the QueryDef in the previous section contains all the phone
numbers associated with the current contact. The following repeat loop reads the phone
number and description fields from each phone number record and fills a single large string
that has carriage returns between each phone number and description. Here’s the code:
repeat while not DGRSIsEOF(tmpRS)
desc := DGRSGetFieldValue("Description", tmpRS)
if desc = "#ERROR#" then desc := ""
num := DGRSGetFieldValue("PhoneNumber", tmpRS)
if num = "#ERROR#" then num := ""
tmpStr1 := tmpStr1^” “^num^”\r”
DGRSMoveNext(tmpRS)
end repeat
DGRSClose(tmpRS)
The loop begins with a call to DGRSIsEOF. This function returns a non-zero value if we’ve
gone past the end of the phone number recordset. Remember that tmpRS is the recordset
handle we created in the previous code segment. When we increment past the last record, the
loop stops.
For each pass through the loop (each phone number), we’ll read the value of the Description
and Phone Number fields by calling DGRSGetFieldValue for each field. We do the standard
error checking, and set the appropriate strings to empty if an error occurs. Once we’ve read
both the description and phone numbers from the database, we append them together with
some white space between them and a carriage return on the end. The results are appended to
tmpStr1.
At the bottom of the loop, we call DGRSMoveNext to move to the next record in the phone
numbers recordset. This process continues until we reach the last record in the recordset. The
DGRSClose function at the end of the loop closes the recordset we created to read the phone
numbers.
Then it’s a simple matter to assign this string to the variable that will display the text on
screen.
OnScreenVar := tmpStr1
There are three major steps to follow whenever you want to add a new record to a database or
change an existing record in the database. Here are the steps:
1. Call DGRSAddNew to add a new empty record or call DGRSEdit to edit an existing record.
2. Add data to the new record or change data in the existing record. If you’re modifying an
existing record, you can call DGRSGetFieldValue to read the current value of a field. Call
DGRSSetFieldValue function to put data into a field.
3. Call DGRSUpdate to save the new record or changes to the database.
You must repeat this process for every record you want to add or change.
Now that you know the process, let’s look at how we would implement code to add a new
record to our contact database. The following script, which is in the “NewRecord” subroutine,
does just that:
DGRSAddNew(rsHandle) -- Add a new record
CanWeEdit := DGRSGetEditMode(rsHandle)
if CanWeEdit = 2 then
DGRSSetFieldValue("FirstName", FirstNameStr, rsHandle)
DGRSSetFieldValue("LastName", LastNameStr, rsHandle)
DGRSSetFieldValue("Address", AddressStr, rsHandle)
DGRSSetFieldValue("Title", TitleStr, rsHandle)
DGRSSetFieldValue("Company", CompanyStr, rsHandle)
DGRSUpDate(rsHandle)
end if
If this function returns a 2, it means that a new record has been added to the database but not
yet saved. Each of the field values is saved by calling the DGRSSetFieldValue function. This
function takes three arguments. The first argument is the name of the field we want to store
data in. The second argument is the data we want to store. The last parameter is the global
recordset handle.
Once the field values have been saved, we’ll call the DGRSUpdate function to save the data
in the database.
Moving through the database one record at a time is pretty easy. We’ll add two subroutines
called Next and Prev and we’ll tie these to the Next and Previous buttons on screen.
If the current button is the last record in the recordset, the “Next” button is disabled. Likewise,
if we are positioned on the first record, the “Prevous” button is disabled. This behavior is
accomplished in the “Active If” property of the button.
--
-- Next Record Icon
--
DGRSMoveNext(rsHandle)
NoCurrentEntry := NoCurrentEntry + 1
--
--Previous Record Icon
--
DGRSMovePrev(rsHandle)
NoCurrentEntry := NoCurrentEntry –1
Each time the user clicks on the Next or Previous buttons, we call the corresponding
subroutines, which moves to the next record in the contact recordset, until we reach the
beginning or end of the records. Each time we move to a new record, we’ll also need to call
the code to get the corresponding phone numbers from the phone number table. We saw this
code when we looked at QueryDefs.
Following is the code for a function that will be called when the user clicks the
AddPhoneNumber button.
Now the real work begins. The next two lines copy the text from the cast members that store
the phone numbers and descriptions (tmpNum_Field and tmpDesc_Field) to temporary
variables. We need to check whether there are, in fact, any phone numbers or descriptions
entered, so the next line checks the number of words in the temporary variables. If they’re
both zero, we just quit. There’s no point in creating a new record to store empty strings.
If there is something to store, we read the ContactID field from the current contact record. As
long as there was no error in reading the ContactID value, we create a recordset from the
PhoneNumber table based on that contact ID. The query in the DGCreateRS function says
“get all the records in the PhoneNumbers table that have a ContactID of id. Id is the variable
that stores the ContactID we read from the Contacts table. The result is that the tmpRS
recordset contains all the phone numbers associated with the current contact.
Next, we add a new record to the recordset we just created. Then we call
DGRSSetFieldValue to store the ContactID, Description, and Phone Number fields for the
new record. Finally, we call DGRSUpdate to store the new record in the database and
DGRSClose to close the phone number recordset. Notice that we’re closing the phone
number recordset (tmpRS), not the contacts recordset (rsHandle).
Summary
We’ve created all the core functionality of a useful little contact management program. We
haven’t covered every detail of the code, and there are certainly a number of areas for
improvement in our program. Now would be a good time to look through the tutorial file or
refer to Appendix D to see how the scripts have been organized.
As a final exercise, you might consider adding search capability to the contact manager.
You’ll need to add a new button to invoke a search, and perhaps a dialog box to enter the
search text. You can use the DGRSFindFirst function to search the database for a match.
Thank you for choosing Datagrip from Integration New Media, Inc.
ClearDGError
Description: Clears the error buffer. When an error occurs a string buffer is filled with
a detailed message explaining the error. If you want to test and see if an
error occurred you could call GetLastDGError(), and then clear it with
this function.
Syntax: ClearDGError()
Example: The example below checks to see if an error occurred and then clears the
error buffer. It’s a good idea to clear the error buffer after handling an
error so that it will always represent the most recent error, if any.
on exitFrame
if not voidP(GetLastDGError())
put GetLastDGError()
ClearDGError()
end if
end
Syntax: DGClose(dbHandle)
dbHandle: A handle to a valid open database object.
Returns: Nothing is returned unless an error occurs, in which case the standard
error string is returned.
Example:
Returns: Upon success this function returns a handle to a newly created grid
object. This handle will be used in later functions to format the grid. If
the function fails the standard error string will be returned.
Example: The following example will create a new grid in the My_Field cast
member .
The following example will create a new grid in the My_Var variable.
Example: The example below opens a database and creates a recordset object that
will hold all of the fields in the 'Family' table. Finally it prints the handle
of the recordset object to the message window.
on exitFrame
set db = DGOpenDatabase("C:\MyDb.mdb")
set rs = DGCreateRecordset("SELECT * FROM Family", db)
put rs
end
Returns: Nothing if the function is successful. If an error occurs the standard error
string, #ERROR#, will be returned.
Example: The following example deletes all the records in the Family table.
on exitFrame
set db = DGOpenDatabase("C:\MyDb.mdb")
DGExecute("Delete * from Family",db)
end
Syntax: DGGetVersion()
Returns: A string will be returned specifying the version of the currently installed
Datagrip Xtra.
fieldName: The name of the field in the database to add to the grid list.
Example: The following example will add the ID, Name, and PhoneNum fields
which exist in the open recordset. The results will be stored in the
My_Field cast member.
fieldName: The name of the database field that you want to terminate a
connection with.
Returns: If this function is successful then nothing is returned. On the other hand
if an error occurs then the standard error string is returned.
Example: The following example will add two database fields to the grid and then
delete the initial one.
Syntax: DGGridUpdate(gridHandle)
Returns: Nothing is returned unless an error occurs. In this case the standard error
string is returned.
Example: The following example will fill out the My_Field cast member with all of
the contents of two fields in the recordset. When the data transfer is done
all of the columns should line up.
Syntax: DGIsDAORegistered()
Example: The following example checks to see if the engine is registered. If not
then a call to regsvr32 is made.
if not DGIsDAORegistered()
open “DAO350.DLL” with “C:\windows\system\regsvr32.exe”
end if
Syntax: DGOpenDatabase(dbName)
DGOpendatabase(dbName, bExclusive, bReadOnly, connectionString)
Example: This example opens the first database using the simple form and then
opens another database using the extended form. The extended form
example will open the database in a read only mode.
on StartMovie
set dbHandle1 = DGOpenDatabase("C:\MyDB.mdb")
set dbHandle2 = DGOpendatabase(“DB1.mdb”, 0, 1, “”)
end
Syntax: DGQDClose(qdHandle)
qdHandle: A handle to an open QueryDef object that was created using
DGCreateQueryDef.
Returns: If the function was successful, it returns 1. If the function was not
successful, the standard error string is returned.
if DGQDIsOpen(qd) then
DGQDClose(qd)
end if
Example: The example will create a QueryDef and store it in the database.
set db = DGOpenDatabase("C:\MyDB.mdb")
set qd = DGQDCreate("MSQuery", "SELECT * FROM Family", db)
DGQDSetSQL("SELECT * FROM Family", qd)
Syntax: DGQDCreateRS(qdHandle)
qdHandle: A handle to an open QueryDef object
Returns: If the function was successful it will return a handle to a Recordset that
can be used in all of the other recordset functions. If the functions fails
the standard error string, #ERROR#, is returned.
Example: The following example will take a QueryDef, which was stored in the
database, create a recordset from it, and then check to see how many
fields are in the recordset.
DGQDOpen("MSQuery", qd)
rs = DGQDCreateRS(qd)
if rs <> "#ERROR#" then
put DGRSGetFieldCount(rs)
else
put GetLastDGError()
end if
Syntax: DGQDGetName(qdHandle)
qdHandle: A handle to an open QueryDef.
Returns: If the function is successful the name of the QueryDef will be returned as
a string. If the QueryDef has not been named, it is a new QueryDef and
is called a temporary query. If this is the case you will get a #Temporary
QueryDef# back. If the function fails it will return the standard error
string, #ERROR#.
Example: The example will print the name of the opened QueryDef to the message
window.
put DGQDGetName(qd)
Syntax: DGQDGetParameterCount(qdHandle)
qdHandle: A handle to an open QueryDef object.
Example: The example prints out the number of parameters to the message
window.
on exitFrame
global qd
ret = DGQDGetParameterCount(qd)
if ret <> "#ERROR#" then
put ret
else
put GetLastDGError()
end if
end
Returns: If the function was successful it returns the value of the parameter, which
could be a number or a string. If the function fails, the standard error
string is returned.
Example: The example below reads the value of a parameter called "ID"
global qd
pValue = DGQDGetParameterValue("ID", qd)
put "Parameter value = " & pValue
Syntax: DGQDGetSQL(qdHandle)
qdHandle: A handle to an open QueryDef.
Returns: If the function is successful is returns an SQL string. If the function fails,
it returns the standard error string.
Example: The example gets the SQL string that defines the QueryDef and prints it
in the message window.
global qd
put DGQDGetSQL(qd)
Syntax: DGQDIsOpen(qd)
qdHandle: A handle to a QueryDef object.
Returns: If the function is successful it returns true (1) or false (0). If the function
fails, the standard error string is returned.
Example: The following example checks to see if the query is open. If the query is
open the query is closed.
if DGQDIsOpen(qd) then
DGQDClose(qd)
end if
Description; Opens a QueryDef object that has been defined previously in the
database.
Syntax; DGQDOpen(Queryname,qdHandle)
Queryname: The name of the predefined query to open.
qdHandle: A handle to a database object.
Returns: If the function is successful, it returns a handle. If the function fails, the
standard error string is returned.
global db
DGQDOpen("MSQuery", db)
Example: This example changes the SQL string so that it now references all of the
fields in the Person table.
Syntax: DGRSAddNew(rsHandle)
rsHandle: A handle to an open recordset.
Example: This example will add a new record to a recordset object whose handle is
defined globally.
global rsHandle
DGRSAddNew(rsHandle)
Returns: Upon success this function returns nothing. If the function fails then the
standard error string is returned.
Example: The following code will bind a field on the stage named My_Field to the
name field in the database. Once this is done anytime you call
DGRSMoveNext() the field will automatically contain the new data.
varName: The name of the variable that will be bound to the recordset.
This should be in the form of a string.
dbField: The name of the field in the recordset which will be bound.
Returns: On success this function returns nothing except that the variable is now
tied to the recordset. If the function fails then the standard error string
will be returned.
Example: The following example will tie a variable called MyVar to the ID field in
the recordset.
set MyVar = 0
DGRSBindVar(“MyVar”, “ID”, rs)
Syntax: DGRSCanAppend(rsHandle)
rsHande: A handle to a recordset object.
Returns: If the recordset supports adding new records the function returns 1. If the
recordset does not allow new records, the function returns 0. If the
function fails (which would happen if rsHandle is not a valid handle to
an open recordset), the function returns #ERROR#.
Example: The example below checks to see if the database allows new records. If it
does it will add a new record.
if DGRSCanAppend(rs) = 1 then
DGRSAddNew(rs)
end if
Syntax: DGRSCancelUpdate(rsHandle)
rsHande: A handle to a recordset object.
Returns: This function returns the standard error string, #ERROR#, if an error
occurs. Otherwise, it returns nothing.
Example: This example makes a change to a recordset, and then cancels it.
DGRSEdit(rs)
DGRSSetFieldValue("Phone", "633-3333", rs)
DGRSCancelUpdate(rs)
Syntax: DGRSCanScroll(rsHandle)
rsHande: A handle to a records object
if DGRSCanScroll(rs) then
DGRSMoveNext(rs)
DGRSMoveNext(rs)
end if
Syntax: DGRSCanTransact(rsHandle)
rsHande: A handle to a recordset object.
Returns: The function returns one if the database supports transactions and zero if
it does not. If an error occurs, the standard error string, #ERROR# is
returned.
Syntax: DGRSCanUpdate(rsHandle)
rsHande: A handle to a recordset object.
Returns: This function returns one if the database is read for updating, and zero if
not. If an error occurs, the standard error string, #ERROR# is returned.
Example: The following example checks to see if the database is currently able to
update. If it returns true, DGRSUpdate is called.
if DGRSCanUpdate(rs) = 1 then
DGRSUpdate(rs)
end if
Syntax: DGRSClose(rsHandle)
rsHande: A handle to a recordset object.
Returns: This function returns nothing unless an error occurs. If an error occurs,
the function returns the standard error string, #ERROR#.
Example: The following example checks to see if the recordset is open and then
closes it.
if DGRSIsOpen(rs) then
DGRSClose(rs)
end if
Syntax: DGRSDelete(rsHandle)
rsHande: A handle to a recordset object.
Returns: This function returns nothing unless an error occurs. If an error occurs,
the function returns the standard error string, #ERROR#.
Syntax: DGRSEdit(rsHandlei)
rsHande: A handle to a recordset object.
Returns: This function returns nothing unless an error occurs. If an error occurs,
the function returns the standard error string, #ERROR#.
Example: This example puts the string "Rob" in the "Name" field of the current
record.
DGRSEdit(rs)
DGRSSetFieldValue("Name", "Rob", rs)
DGRSUpdate(rs)
listVar: A variable that will hold the list when the function is finished.
dbField: The name of the field in the recordset that contains the needed
data.
Returns: If this function fails it will return the standard error string. If this
function succeeds then a list containing the new data will be returned.
Example: The following example makes a list of each record from the first name
field in the recordset. Before you can use a list you must initialize the
variable.
set MyList = []
set MyList = DGRSFillList(“FirstName”, rsHandle)
dbField: The name of the field in the recordset that contains the data.
Returns: When the function fails the standard error string is returned. If the
function is successful then a string is returned that contains all of the new
data.
Example: The following example will automatically fill the field with all of the
names in my recordset.
Example: This example finds the first record whose "ID" field is equal to 5.
Example: This example finds the last record whose "ID" field is equal to 5.
Example: This example finds the first record whose age is equal to 5.
Example: This example finds the first record whose age is equal to 5.
Syntax: DGRSGetAbsolutePosition(rsHandle)
rsHande: A handle to a recordset object
Example: The following example gets the current absolute position and prints the
number to the message window.
put DGRSGetAbsolutePosition(rs)
Syntax: DGRSGetEditMode(rsHandle)
Returns: This function returns an integer that indicates the current edit mode of
the recordset. The return value will be one of the following:
Note
This function may take a significant amount of time to execute when
using large databases. In order to return a value, the records in the
database must be counted, which can be a time-consuming operation.
Syntax: DGRSGetFieldCount(rsHandle)
rsHande: A handle to a recordset object.
Returns: If the function is successful then it returns an integer that specifies the
number of fields in the current recordset. If the function fails, it returns
the standard error string, #ERROR#.
Example: This example determines the number of fields in the recordset and prints
it out to the message window.
put DGRSGetFieldCount(rs)
Returns: If the function is successful it returns the data from the field named in
fieldname. in the current recordset. The value that is returned can be an
integer, a float, or string.
When currency values are returned they do not include the dollar sign
and the values are returned as floats.
"address#protocol://address#"
"www.inm.com#http://www.inm.com#"
Note
Hyperlinks are only supported in Access version 8.0 or later databases.
Example: The example below prints the value of the field named "Address" in the
current record to the message window.
Syntax: DGRSGetLockingMode(handle)
Example: The following example checks to see if the recordset is using optimistic
locking. If it is, set it to pessimistic which is safer.
if DGRSGetLockingMode(rsHandle) = 0 then
DGRSSetLockingMode(1, rsHandle)
end if
Syntax: DGRSGetName(rsHandle)
rsHande: A handle to a recordset object.
put DGRSGetName(rs)
Note
This function may not return an accurate indication of the record
position under some circumstances, because the number of records in
a recordset is not known until all the records have been accessed.
Syntax: DGRSGetPercentPosition(rsHandlei)
rsHande: A handle to a recordset object.
Returns: This function returns a two-digit float value which represent the position
of the current record in the recordset expressed as a percentage. If the
function fails, it returns the standard error string, #ERROR#.
Example: This example will determine if the current record is more than half way
through the entire Recordset and will print a message to the message
window.
Note
This function may not return an accurate count of records in many
cases. The record count that is returned is the number of the last
record that has been accessed. Unless the current record has been
moved to the last record prior to calling this function, the record
count may not be accurate. Call DGRSMoveLast before calling
DGRSGetRecordCount to insure that the record count is accurate.
Syntax: DGRSGetRecordCount(rsHandle)
rsHande: A handle to a recordset object.
Returns: This function returns the number of records in the recordset. If the
function fails, it returns the standard error string, #ERROR#.
Example: This code segment will determine if we have more than 10 people in our
address book database.
Syntax: DGRSGetSQL(rsHandle)
rsHandle: A handle to an open Recordset.
Returns: This function returns a string that contains the SQL query that defines
the recordset. If the function fails, it returns #ERROR#.
Example: The example gets the SQL string that defines the recordset and prints it
to the message window.
global qd
put DGQDGetSQL(qd)
dbField: The name of the field in the recordset that contains the resource
you are importing.
Returns: If successful nothing is returned from this function but the specified cast
member should now contain the imported data. When the function fails it
will return the standard error string.
Example: This example will import a wave file that has been stored in the wave
field of a previously opened recordset. When the function is done the 10th
cast member of the third cast will contain the new wave.
13. Click ‘OK’ until you are back to the control panel.
Syntax: DGRSIsBOF(rsHandle)
rsHandle: A handle to a recordset object.
Returns: This function returns one (true) if the current record is before the
beginning of the recordset, or zero (false) if the current record is in the
recordset. If the function fails (e.g. rsHandle is not a valid recordset
handle), it returns the standard error string, #ERROR#.
Example: The following example moves to the previous record if we are not past
the beginning of the recordset. Because DGRSisBOF only returns true
after the current record moves past the beginning of the recordset, you
must move, test, and move back if DGRSIsBOF returns true.
DGRSMovePrev(rsHandle)
if not DGRSIsBOF(rsHandle) then
DGRSMoveNext(rsHandle)
end if
Syntax: DGRSIsEOF(rsHandle)
rsHandle: A handle to a recordset object.
Returns: This function returns one (true) if the current record is after the end of
the recordset, or zero (false) if the current record is in the recordset. If the
function fails (e.g. rsHandle is not a valid recordset handle), it returns the
standard error string, #ERROR#.
Example: The following example moves to the next record if we are not past the
end of the recordset. Because DGRSisEOF only returns true after the
current record moves past the end of the recordset, you must move, test,
and move back if DGRSIsEOF returns true.
DGRSMoveNext(rsHandle)
if not DGRSIsEOF(rsHandle) then
DGRSMovePrev(rsHandle)
end if
Syntax: DGRSIsOpen(rsHandle)
rsHandle: A handle to a recordset object.
Returns: This function returns one if the recordset is open, or zero if it is not open.
If an error occurs (e.g. rsHandle isn't a valid recordset handle), the
function returns the standard error string, #ERROR#.
Example: This example will check to see if the current recordset is open. If it is
open, the recordset is closed.
Syntax: DGRSMoveFirst(rsHandle)
rsHandle: A handle to a recordset object.
Example: This example will move to the first record if we are past the end of the
recordset. This would be convenient way to "wrap around" to the
beginning of the records when you've reached the end of the recordset.
DGRSMove(2, rs)
if DGRSIsEOF then
DGRsMovePrev(rs)
end if
Syntax: DGRSMoveLast(rsHandle)
rsHandle: A handle to a recordset object.
Example: This example will move to the last record if we are past the beginning of
the recordset. This would be convenient way to "wrap around" to the end
of the records when you've reached the beginning of the recordset.
Syntax: DGRSMoveNext(rsHandle)
rsHandle: A handle to a recordset object.
Example: The following example moves to the next record if we are not past the
end of the recordset. Because DGRSIsEOF only returns true after the
current record moves past the end of the recordset, you must move, test,
and move back if DGRSIsEOF returns true.
DGRSMoveNext(rsHandle)
if not DGRSIsEOF(rsHandle) then
DGRSMovePrev(rsHandle)
end if
Syntax: DGRSMovePrev(rsHandle)
rsHandle: A handle to a recordset object.
Example: The following example moves to the previous record if we are not past
the beginning of the recordset. Because DGRSIsBOF only returns true
after the current record moves past the beginning of the recordset, you
must move, test, and move back if DGRSIsBOF returns true.
DGRSMovePrev(rsHandle)
if not DGRSIsBOF(rsHandle) then
DGRSMoveNext(rsHandle)
end if
Syntax: DGRSReQuery(rsHandle)
rsHandle: This is a handle to a recordset.
Returns: If successful, the function will returns one, otherwise the standard error
string, #ERROR#, is returned.
Example: This example will open a querydef, set a parameter and use the resulting
recordset to get a phone number from the database. Once we have the
first number the parameter in the querydef is changed and we requery our
original recordset to get the new data.
global rsHandle
set qdHandle = DGQDOpen(“PhoneQuery”, dbHandle)
DGQDSetParameterValue(“ContactID”, CurContact, >>
qdHandle)
set rsHandle = DGQDCreateRS(qdHandle)
set myNum = DGRSGetFieldValue(“PhoneNumber”, rsHandle)
Example: This example gets a position, move the record and then returns to it.
val = DGRSGetAbsolutePosition(rs)
DGRSMoveFirst(rs)
DGRSSetAbsolutePosition(val, rs)
Example: The example below changes the value of the field named "Address" in
the database MyDb.mdb. First it opens the database then creates a
recordset and finally sets the value "123 Mystreet"
set db = DGOpenDatabase("C:\MyDB.mdb")
set rs = DGCreateRecordset("SELECT * FROM People", db)
return DGRSSetFieldValue("Address", "123 Mystreet", rs)
Benefits:
Pessimistic locking: Ensures that only one person will be editing the data
at any given time.
Optimistic locking: Only has the record locked for a very short period of
time when the user is saving the data.
Disadvantages:
Pessimistic locking: Locks the recordset for a long period of time. In fact
the user could initiate an edit command and then leave the keyboard
which would mean the recordset would be locked for a very long period
of time.
Optimistic locking: Possibility that multiple users will be able to edit the
same data at the same time. Which means when they save their data an
error will occur.
Returns: Upon success nothing is returned but when an error occurs the standard
Datagrip error string will be sent back.
global rsHandle
DGRSSetLockingMode(0, rsHandle)
fieldName: The name of the cast member to break the connection with.
rsHandle: A handle to the recordset that the field was bound to.
Returns: If this function was unsuccessful then the standard error string will be
returned. Otherwise nothing will be returned.
Example: The following example will break a previously made connection between
the cast member “My_Field” and the datbase.
global rsHandle
DGRSUnbindField(“My_Field”, rsHandle)
varName: The name of the variable to break the connection with. This
should be in the form of a string.
rsHandle: The handle to the recordset to which the variable was bound.
Returns: If this function succeeds nothing is returned. If this function fails then the
standard error string is returned.
Example: The following example assumes that the recordset is already tied to my
ID variable. Here we are just breaking the connection.
global rsHandle
DGRSUnbindVar(“ID”, rsHandle)
Syntax: DGRSUpdate(rsHandle)
rsHandle: This is a handle to a recordset.
Example: The following example adds a new record to the recordset and then calls
update to save it in the database.
DGRSAddNew(rs)
DGRSSetFieldValue("Name", "Rob", rs)
DGRSUpdate(rs)
HKEY_LOCAL_MACHINE
HKEY_CURRENT_USER
HKEY_CLASSES_ROOT
HKEY_USERS
HKEY_CURRENT_CONFIG.
path: The path to the key that you are retrieving.
HKEY_LOCAL_MACHINE\SOFTWARE\INM\Datagrip\Path
Syntax: GetLastDGError()
Returns: A string that gives more detail on the most recent error.
Syntax: DGSetAudioSafeMode(state)
DGSetAudioSafeMode(1)
HKEY: The HKEY that you are opening. HKEY can be one of the
following:
HKEY_LOCAL_MACHINE
HKEY_CURRENT_USER
HKEY_CLASSES_ROOT
HKEY_USERS
HKEY_CURRENT_CONFIG.
path: The path to the key you are updating.
key: The specific key you are creating or updating. If this value is set to
an empty string ("") you will be setting the value of the default setting in
the folder specified in path.
value: This can be an integer or a text string. This is the value that the
key will be set to.
Example: The following example will create a new folder and new key just as you
might do for your company when releasing a product.
Credits Requirements
When you distribute an application that uses Datagrip your license agreement requires that
you display a credit line for Datagrip. The credit line should say “Database connectivity
provided by Datagrip”. It must be readable, in a font of at least 10 points, and must be visible
for at least four seconds. The ideal place to place this credit line is on the credits page required
by Macromedia with the Director/Authorware logo.
If your application will not be distributed, you are not required to include this credit line. An
example of a presentation that doesn't require a credit line is a business presentation that is
only used by a single presenter.
Distributing Datagrip
Parts of Datagrip are copyrighted by Microsoft. If you intend to distribute a Datagrip
application, you must own one of the following Microsoft products in order to have the right
to distribute the Microsoft DLL files that support Datagrip. Typically, you'll need Microsoft
Access to create and maintain databases anyway, so this requirement shouldn't be a problem.
You must own one of the following products in order to distribute Datagrip:
• Microsoft Access
• Microsoft Visual Basic
• Microsoft Visual C++
Datagrip can only be used in the Director/Authoware design environment on the licensed
user's computer. When you distribute Datagrip with an application you create, the users who
receive your application cannot use Datagrip in the Director/Authorware design environment.
If you choose the first option and decide to place the files on the users hard drive you will
want to remember that the names of these directories may change for international versions of
windows. There are instructions below to help you determine the correct folder placement.
If you choose the second option which is to leave the files on the CD you will want to be sure
and check to see if the files already exist on the users system. An easy way to determine this is
to make a call to DGIsDAORegistered which will check and see if the necessary components
are there. When the files don’t exist on the users system you will need to register them on the
CD. But if they do exist you will never want to register them on the CD since it will break
other applications. Also, remember to unregister the file once you are done if you registered it
in the beginning!
Location File Name
Folder named "Xtras" next to your Director DGREL.X32
projector or Authorware packaged piece
Windows System Folder MSVCRT20.DLL
VBAR332.DLL
MSJET35.DLL
MSVCRT40.DLL
MSVCRT.DLL
MSVCIRT.DLL
MSJINT35.DLL
MSJTER35.DLL
MSRD2X35.DLL (needs to be registered)
VBAJET32.DLL
Program Files\Common Files\Microsoft DAO350.DLL (needs to be registered)
Shared\DAO Folder
DAO2535.TLB
Note
For international installations the ‘Program Files\Common Files’ directory
may be named something different. To determine the location of this directory
you can look in the user’s registry. In the key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\CommonFilesDir
Occasionally it is not feasible to put an installer on the front of your application. In this case
you can use a program called REGSVR32.EXE. This program is located in the Windows
system directory. To use it you execute it and on the command line pass the path to the file
you are trying to register. This program comes with a variety of calling options. To see these
options call REGSVR32.EXE without anything on the command line.
Current record
The record within a recordset that will be read from, written to, or deleted. Many
Datagrip functions move the current record. For example, DGMoveNext moves the
current record to the next record in the recordset.
Field
Columns in a database table are called fields. Fields have a name that you use to refer to
them. For example, DGRSGetFieldValue gets the value of a field in the current record
whose name you supply. When you create a recordset, the field names in the recordset
are generally the same as the field names in the original database table.
Handle
A handle is a number that you use to refer to a Datagrip object, such as a database,
recordset, or querydef. The Datagrip Open or Create functions typically return a handle
that you’ll store in a variable and use until you close the object.
Lingo
Macromedia Director’s scripting language is called Lingo. More recently, both Director’s
and Authorware’s scripting languages are referred to as the “Macromeda Scripting
Language”. This manual assumes some familiarity with the scripting language. See the
More Reading section for information on learning and using the Macromedia Scripting
Language.
Path
A Path is the set of all the directories (sometimes called “folders”) that you need to open
to get to a particular file.
Query
A Query is a statement that defines which records (rows) you want to retrieve from a
database. Queries are written using the Structured Query Language (SQL).
Querydef
A Querydef is a query that is stored in a database file. Querydefs are more efficient than
queries you enter as strings in your code because the database can examine the query in
advance and prepare it for use. The Datagrip functions for using QueryDefs all start with
DGQD (Datagrip QueryDef).
Record
A record is one row in a database table or the recordset you create from the database table
using a query.
Relational database
A relational database is a database that allows you to create multiple tables and make
relationships between the tables based on certain fields. Microsoft Access databases are
relational. We used this feature in the tutorial by creating two tables and relating them
using the ContactID field.
Stored query
See querydef
SQL
Structured Query Language. The SQL language defines a standard way to write queries
to retrieve data and perform other actions on a database. Datagrip uses a Microsoft
implementation of SQL, which is identical in most respects to the standard SQL. For
more information on the differences, refer to the Microsoft Access documentation.
Here are some other books that may be useful for understanding database concepts, SQL, and
the Macromedia Scripting Language.
1. Understanding SQL, Martin Gruber , Sybex
2. Using Lingo Macromedia Director product documentation
3. Jet Database Engine Programmer's Guide, Dan Haught and Jim Ferguson, Microsoft Press,
1995
4. Microsoft Access Help File provided with the Access software
Startup Scripts
----------------------------------------
-- StartMovie
--
-- this is called when the projector is
-- initially launched
----------------------------------------
on startMovie
InitGlobals
InitDB
end
----------------------------------------
-- InitGlobals
--
-- This function will initialize and set
-- all of the global variables.It should
-- be called once at startup
----------------------------------------
on InitGlobals
global DBHandle --A handle to a database
global RSHandle --A handle to a recordset
global QDHandle --A handle to a querydef
global picCastMem --The member to hold the pics
global waveCastMem --The member that will hold the wave file
--
--Initially set these handles to 0 since
--any handle that is returned will be
--greater than 0
--
set DBHandle = 0
set RSHandle = 0
set QDHandle = 0
set picCastMem = 64
set waveCastMem = 65
end
----------------------------------------
--InitDB
--
-- This function will initially open the
-- database and create a recordset that
-- will allow us to read and edit all of
-- the contacts in our database
----------------------------------------
on InitDB
global dbHandle
global rsHandle
global qdHandle
--
--Open the contacts database assuming
--that it exists in the local directory.
--If it doesn't we will get an error back
--that we can use to communicate with the user
--
set dbHandle = DGOpenDatabase(the moviePath & "Tutor.mdb")
if dbHandle = "#ERROR#" then
alert "Error: " & GetLastDGError()
--
--This SQL string will define our
--recordset. It essentially means
--Select everything that exists
--inside the Contacts table.
--
set sqlString = "SELECT * FROM Contacts"
--
--Open a recordset using our above created
--SQL string and our database handle
--
set rsHandle = DGCreateRecordset(sqlString, dbHandle)
if rsHandle = "#ERROR#" then
alert "Error: " & GetLastDGError()
alert "Now exiting the program."
quit
end if
--
--Link each field to its appropriate Database field
--
DGRSBindField("FirstName_Field", "FirstName", rsHandle)
DGRSBindField("LastName_Field", "LastName", rsHandle)
DGRSBindField("Company_Field", "Company", rsHandle)
DGRSBindField("Title_Field", "Title", rsHandle)
--
--Open a stored query that will retrieve all of
--the phone numbers for us
--
set qdHandle = DGQDOpen("PhoneQuery", dbHandle)
if qdHandle = "#ERROR#" then
alert "Error: " & GetLastDGError()
alert "Now exiting the program."
quit
end if
end
Button Scripts
--NEXT BUTTON SCRIPT
on mouseUp
GoToNextRecord()
end
on mouseUp
GoToPrevRecord()
End
on mouseUp
AddNumberToDB()
set the text of field "tmpDesc_Field" = ""
set the text of field "tmpNum_field" = ""
FillPhoneNumFields()
End
on mouseUp
global rsHandle
global waveCastMem
--
--Pull our wave file out of the database
--
DGRSImportResource(member waveCastMem, "Wave", rsHandle)
puppetSOund member waveCastMem
end
Frame Scripts
--GO TO THE FRAME
on exitFrame
go to the frame
end
Interface Scripts
----------------------------------------
--ClearFields
--
-- Description:
-- Clears all of the fields on the stage
--
----------------------------------------
on ClearFields
global picCastMem
--
--picCastMem holds the member number where the
--pictures are stored. When we create a
--new entry we will want to erase this
--since there won't be a pic in the DB
--
erase member picCastMem
end
------------------------------------------
--SaveCurrentData
--
-- Description:
-- Runs through each of the fields on the
-- stage and calls a save function which
-- takes the text and calls the save function
-- in the database.
--
------------------------------------------
on SaveCurrentData
global rsHandle
global dbhandle
--
--Save all of the data
--
SaveDBField("FirstName")
SaveDBField("LastName")
SaveDBField("Address")
SaveDBField("Title")
SaveDBField("Company")
--
--Call the final save for the rest of
--the data
--
DGRSUpdate(rsHandle)
end
Database Scripts
----------------------------------
--SetFieldVal
--
-- params:
-- fieldName: the name of the field on the stage
-- dbField : the field in the DB
--
-- Returns:
-- The value in the field. If an error
-- occurs nothing will be returned but
-- an error dialog will be displayed
--
-- Notes:
-- This function uses a global variable as
-- the recordset handle.
----------------------------------
on SetFieldVal fieldName, dbField
global rsHandle
-----------------------------------
--GoToNextRecord
--
-- Description:
-- Moves to the next record in the
-- current recordset.
-----------------------------------
on GoToNextRecord
global rsHandle
global qdHandle
global picCastMem
--
--
--Make sure we don't go past
--the end of the file
--
DGRSMoveNext(rsHandle)
if DGRSIsEof(rsHandle) then
DGRSMovePrev(rsHandle)
return
end if
--
--There is one field in our user interface
--that we have decided to handle manually.
--This is for no other reason that to provide
--an example of another data retrieval method.
--
set txt = DGRSGetFieldValue("Address", rsHandle)
if txt <> "#ERROR#" then
set the text of member "Address_Field" = txt
end if
--
--The following will erase the last member
--make it in visible, replace it, and turn
--it back on. Usually this is not needed.
--If you just replace the cast member with
--a simple call to DGImportResource() it all
--happens extremely fast!
--
erase member picCastMem
set the visible of sprite 2 = 0
DGRSImportResource(member picCastMem, "Photo", rsHandle)
set the visible of sprite 2 = 1
FillPhoneNumFields
end
---------------------------------
--GoToPrevRecord
--
-- Description:
-- Moves to the previous record
-- in the current recordset
---------------------------------
on GoToPrevRecord
global rsHandle
global qdHandle
global picCastMem
--
--Check to see if the user has
--created a new record without
--saving. If this is the case
--save it and go on.
--
--
--Make sure we don't go passed
--the begining of the file
--
DGRSMovePrev(rsHandle)
if DGRSIsBOF(rsHandle) then
DGRSMoveNext(rsHandle)
return
end if
--
--There is one field in our user interface
--that we have decided to handle manually.
--This is for no other reason that to provide
--an example of another data retrieval method.
--
set txt = DGRSGetFieldValue("Address", rsHandle)
if txt <> "#ERROR#" then
set the text of member "Address_Field" = txt
end if
--
--The following will erase the last member
--make it in visible, replace it, and turn
--it back on. Usually this is not needed.
--If you just replace the cast member with
--a simple call to DGImportResource() it all
--happens extremely fast!
--
erase member picCastMem
set the visible of sprite 2 = 0
DGRSImportResource(member picCastMem, "Photo", rsHandle)
set the visible of sprite 2 = 1
FillPhoneNumFields
end
-----------------------------------
--CreateNewRecord
--
-- Description:
-- Creates a new record inside the
-- database that is ready to be
-- filled with data.
----------------------------------
on CreateNewRecord
global rsHandle
--
--Check to see if there is an
--unsaved record. If so save it
--
if DGRSGetEditMode(rsHandle)=2 then
SaveCurrentData()
put DGRSUpdate(rsHandle)
end if
--
--Once you create a new record and
--append it to the database the engine
DGRSMoveLast(rsHandle)
DGRSAddNew(rsHandle)
end
----------------------------------
--SaveDBField
--
-- params:
-- fieldName:
-- the name of the field on
-- the stage.
--
-- Description:
-- This will pull all of the data
-- from the fields on the stage
-- and save it in the corresponing
-- database field
--
----------------------------------
on SaveDBField fieldName
global rsHandle
--
--Append a "_Field" to the member name, get its text
--and then save it to the database.
--
put "SetFieldValue Result: " && DGRSSetFieldValue(FieldName , the text of member
(fieldName & "_Field"), rsHandle)
end
--------------------------------------------
--AddNumberToDB()
--
-- Description:
-- Takes the number and description from
-- the temp fields and records them
-- in the database.
--------------------------------------------
on AddNumberToDB
global rsHandle
global dbHandle
--
--Check to see if the user has
--created a new record without
--saving. If this is the case
--save it and go on.
--
if DGRSGetEditMode(rsHandle) = 2 then
SaveCurrentData()
DGRSUpdate(rsHandle)
DGRSMoveLast(rsHandle)
end if
--
--Get our data
--
set descStr = the text of member "tmpDesc_Field"
set NumStr = the text of member "tmpNum_Field"
--
--Get the associated contact id and enter it in the new records
--
set id = DGRSGetFieldValue("ContactID", rsHandle)
if id <> "#ERROR#" then
set tmpRS = DGCreateRecordset("SELECT * FROM PhoneNumbers Where ContactID =" && id,
dbHandle)
DGRSAddNew(tmpRS)
DGRSSetFieldValue("ContactID", id, tmpRS)
DGRSSetFieldValue("Description", descStr, tmpRS)
DGRSSetFieldValue("PhoneNumber", numStr, tmpRS)
DGRSUpdate(tmpRS)
DGRSClose(tmpRS)
end if
end
--------------------------------------------
--FillPhoneNumFields()
--
-- Description:
-- Creates a grid in the phone number box
--
--------------------------------------------
on FillPhoneNumFields
global rsHandle
global qdHandle
--
-- First, get the value of the contact ID from the current
-- record of the contact recordset
--
set val = DGRSGetFieldValue("ContactID", rsHandle)
--
--Tell the grid to fill in all of the data
--
DGGridUpdate(gridHandle)
end if
end if
end
Startup Scripts
Initialize Arrays
-- Datagrip Demo V 1.0
--
--
-- This Data Grip Demo was Programmed by Don Cowper at TransTech Interactive Training Inc
--
-- "After spending weeks fighting with ODBC, what a pleasure to find a Access database
-- conductivity product that really works with Authorware. DataGrip has good error messaging,
-- all the functions you could require and blazing speed. I wrote this PIM demo in a single day!"
-- --Don Cowper
--
--
-- Special Note: If you want to use a string to query the database enclose it in single quotes
-- inside a set of double quotes.
--
-- eg FindLastName := "'Jones'" -- single quotes within double quotes
-- Array PhoneNum holds the description in field 1 and the number in field 2
PhoneNum := Array("",10,2)
Open Database
-- LastErrorTxt is shown across the bottom of the screen when it has a message in it.
dbHandle := DGOpenDatabase("Tutor.mdb")
if dbHandle = "#ERROR#" then
LastErrorTxt := "Error in icon: Open Database: "^GetLastDGError()
ClearDGError()
end if
--
--Bind the main fields to the database so that we don't have to
--update the fields every time the data changes.
--
DGRSBindVar("FirstNameStr", "FirstName", rsHandle)
DGRSBindVar("LastNameStr", "LastName", rsHandle)
DGRSBindVar("TitleStr", "Title", rsHandle)
DGRSBindVar("CompanyStr", "Company", rsHandle)
--
--Notice in the above list of bound fields we did not
--include the Address field. This is for no other reason
--than that we have decided to demonstrate the manual
--approach to retrieving data. This next call will fill in the data
--for the first record. Subsequent records will be updated
--in the Next and Prev icons.
Subroutines
Initialize Phone # & Fields
--Bank Previous Telephone Array
repeat with J := 1 to 10
PhoneNum[J,1] := PhoneNum[J,2] := ""
end repeat
FirstNameStr := LastNameStr := AddressStr := TitleStr := CompanyStr := ""
Get Contact ID
--
--Get the ID of the current contact
--
CurContact := DGRSGetFieldValue("ContactID",rsHandle)
DGQDSetParameterValue("pContactID", CurContact, dbHandle)
phHandle := DGQDCreateRS(qdHandle)
--
--Close the recordset since it will change
--every time we change records.
--
DGRSClose(phHandle)
Next
DGRSMoveNext(rsHandle)
NoCurrentEntry := NoCurrentEntry + 1
--
--At this point we will need to fill in the address field
--
txt := DGRSGetFieldValue("Address", rsHandle)
if txt <> "#ERROR#" then
AddressStr := txt
end if
Prev
DGRSMovePrev(rsHandle)
NoCurrentEntry := NoCurrentEntry -1
--
--At this point we will need to fill in the address field
--
1. The capability to import bitmaps and waves from the access DB:
Now you can store your bitmaps and wave files right in the database. Then when you need
them you can import them in to a cast member on the fly. This is useful for projects that have
many pictures each associated with some data. An example would be an online product
catalog. You could have all of the product information and a picture of that product stored in
the database. If you use our competitor products you will have to store a path name in the DB
and then import it off of the hard disk which is a very slow process.
2. Automatic data binding to variables:
This feature allows you to tie a variable in Director or Authorware to a specific field in a
database. When the variable is tied anything you do to the database is automatically reflected
in the variable. If you move to the next record, edit the record, delete the record, or cause any
change the variable is automatically updated for you. This saves the programmer from having
to write extra code to handle the retrieval of the data every time a change is made. An
example where a developer would want to use this tracking is an ID number. You could tie
the ID number of the current record to a variable and provide the user a way to move back and
forth through the records. No matter where the user navigates to your variable will always
hold the current ID.
3. Automatic data binding to field cast members:
The same as above except that the data is stored in a field object instead of a variable. This is
useful anytime you have to display a number of data items from a record all at the same time.
All you have to do is drop the fields on the stage and tie them to the database. Then any time a
change is made to the database your fields automatically get updated. They will always hold
the correct data and the programmer will never have to write the code to fill them!
4. Automatically fill a field or variable with the entire contents of a recordset:
This feature will take a text field or a variable and fill it with all of the data of a field in a
recordset. For instance if you wanted to create a list of every name in the database so that you
could display it in a field you previously had to manually retrieve the data out of each field
and build a large string. With this new feature you just tell Datagrip the field in the recordset
and it quickly retrieves all of the data for you. This greatly enhances performance since you
make one call instead of one for every record. This will prevent the programmer from making
thousands of extra calls that could slow down the application.
5. Capability to turn a field cast member or variable in to a grid:
This great feature will take a list of fields that you specify and build a multicolumn list box.
You just name the fields and give them a size and Datagrip takes care of the rest. It
automatically adjusts the size of the text in the database so that all of the data lines up in nice
columns. Say for instance you had a database that held names and phone numbers. Of course