📄 ch13.htm
字号:
are important:
<UL>
<LI>The program should run off local tables, because this is the kind of tool likely
to be used on individual PCs rather than on a network. The choice of whether to use
Paradox or dBASE tables is a toss-up, but I'll opt to use Paradox tables because
they provide more features.
<P>
<LI>The user should be able to sort the table on the <TT>FName</TT>, <TT>LName</TT>,
and <TT>Company</TT> fields.
<P>
<LI>Searching
on the <TT>FName</TT>, <TT>LName</TT>, and <TT>Company</TT> fields
should be possible.
<P>
<LI>The user should be able to set up filters based on the <TT>Category</TT> field.
<P>
<LI>The times when the table is editable should be absolutely
clear, and the user
should be able to easily move in and out of read-only mode.
<P>
<LI>Printing the contents of the table based on the filters set up by the <TT>Category</TT>
field should be possible.
<P>
<LI>Choosing a set of colors that will
satisfy all tastes is very difficult, so the
user should be able to set the colors of the main features in the program.
</UL>
<P>A brief consideration of the design decisions makes it clear that the table should
have a primary index on the first
three fields and secondary indexes on the <TT>FName</TT>,
<TT>LName</TT>, <TT>Company</TT>, and <TT>Category</TT> fields. The primary index
can be used in place of a secondary index on the <TT>FName</TT> field, but the intent
of the program's code
will be clearer if a secondary index is used for this purpose.
In other words, the code will be easier to read if it explicitly sets the <TT>IndexName</TT>
to something called <TT>FNameIndex</TT> instead of simply defaulting to the primary
index.
Table 13.2 shows the final structure of the table. The three asterisks in
the fourth column of the table show the fields that are part of the primary index.
<DL>
<DT></DT>
</DL>
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B>
</B>This table does not have a code
field--that is, it does not have a simple numerical number in the first field of
the primary index. Most tables will have such a value, but it is not necessary here,
because this database is, at least in theory,
a flat-file database. I say, "at
least in theory," because I am going to make one small cheat in the structure
of this database. In short, there will be a second table involved, simply because
I could see no reasonable way to omit it from
the design of this program.
<HR>
</BLOCKQUOTE>
<P><B>Table 13.2. The fields used by the Address2 program. </B>
<TABLE BORDER="1">
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85" ALIGN="LEFT"><B>Name</B></TD>
<TD WIDTH="77"
ALIGN="LEFT"><B>Type</B></TD>
<TD WIDTH="49" ALIGN="LEFT"><B>Size</B></TD>
<TD WIDTH="53" ALIGN="LEFT"><B>PIdx</B></TD>
<TD ALIGN="LEFT"><B>Index</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85" ALIGN="LEFT"><TT>FName</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">40</TD>
<TD WIDTH="53" ALIGN="LEFT">*</TD>
<TD ALIGN="LEFT"><TT>FNameIndex</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85" ALIGN="LEFT"><TT>LName</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">40</TD>
<TD WIDTH="53" ALIGN="LEFT">*</TD>
<TD ALIGN="LEFT"><TT>LNameIndex</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85" ALIGN="LEFT"><TT>Company</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">40</TD>
<TD WIDTH="53" ALIGN="LEFT">*</TD>
<TD ALIGN="LEFT"><TT>CompanyIndex</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>Address1</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">40</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>Address2</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">40</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>City</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">40</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>State</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">5</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>Zip</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">15</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>HPhone</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">15</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>WPhone</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">15</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>Fax</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">15</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>EMail1</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">45</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>EMail2</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">45</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>Comment</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Memo</TD>
<TD WIDTH="49" ALIGN="LEFT">20</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="85"
ALIGN="LEFT"><TT>Category</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Character</TD>
<TD WIDTH="49" ALIGN="LEFT">15</TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"><TT>CategoryIndex</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD
WIDTH="85" ALIGN="LEFT"><TT>Marked</TT></TD>
<TD WIDTH="77" ALIGN="LEFT">Logical</TD>
<TD WIDTH="49" ALIGN="LEFT"></TD>
<TD WIDTH="53" ALIGN="LEFT"></TD>
<TD ALIGN="LEFT"></TD>
</TR>
</TABLE>
<BR>
<BR>
Now that you have a clear picture of the
type of table that you need to create, you
can open the Database Desktop and create the table, its primary index, and its four
secondary indexes. When you're done, the structure of the table should look like
that in Figure 13.1. You can save the table
under the name <TT>ADDRESS.DB</TT>.<BR>
<BR>
<A NAME="Heading7"></A><A HREF="13ebu01.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/13/13ebu01.jpg">FIGURE 13.1.</A><FONT COLOR="#000077">
</FONT><I>Designing the main table for the Address2 program. Portions of the table
are not visible in this
picture.</I></P>
<P>Here is another way of looking at the indexes for this table:</P>
<PRE><FONT COLOR="#0066FF">Primary Index
LName
FName
Company
Category Index
Category
Company Index
Company
FName
LName
LName Index
LName
FName
Company
</FONT></PRE>
<P>In this particular case, I will actually end up using these fields and indexes
as designed. However, in a real-world situation, you should expect to come up with
a carefully thought-out draft like this, and then know in your
heart that after you
get the program up and running, some things will have to change. Don't tell someone:
"Oh, I can complete this program in two weeks; this is going to be easy!"
Instead, say: "In two weeks, I can get you a prototype,
and then we can sit
down and decide what changes need to be made."</P>
<P>You should, however, have some clearly defined boundaries. For example, this program
is designed to be a flat-file database. If someone (yourself most especially included!)
tries to talk you into believing that this program should really be a relational
database of the kind planned for the next chapter, then you have to slam your foot
down and say: "No way!" After you've started on a project, you should expect
revisions, but you must not allow the goal of the project to be redefined. That way
leads to madness!
<H3><A NAME="Heading8"></A><FONT COLOR="#000077">Defining the Programs Appearance</FONT></H3>
<P>Before beginning the real programming chores, you
need to create a main form and
at least one of the several utility forms that will be used by the program. You can
let the Database Expert perform at least part of this task for you, but I prefer
to do the chore myself to give my program some
individuality.</P>
<P>The main form of the Address2 program, shown in Figure 13.2, contains two panels.
On the top panel are all the labels and data-aware controls necessary to handle basic
input and output chores. All the main fields in the program
can be encapsulated in
<TT>TDBEdit</TT> controls, except for the <TT>Comment</TT> field, which needs a <TT>TDBMemo</TT>,
and the <TT>Category</TT> field, which needs a <TT>TDBLookupComboBox</TT>. The names
of the data-aware controls should match the
field with which they are associated,
so the first <TT>TDBEdit</TT> control is called <TT>FNameEdit</TT>; the second, <TT>LNameEdit</TT>;
and so on. The <TT>TDBLookupComboBox</TT> is therefore called <TT>CategoryCombo</TT>--and
the memo field,
<TT>CommentMemo</TT>.<BR>
<BR>
<A NAME="Heading9"></A><A HREF="13ebu02.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/13/13ebu02.jpg">FIGURE 13.2.</A><FONT COLOR="#000077">
</FONT><I>The main form for the Address2 program.</I>
<DL>
<DT></DT>
</DL>
<BLOCKQUOTE>
<P>
<HR>
<FONT
COLOR="#000077"><B>NOTE:</B></FONT><B> </B>If you find yourself chafing under
the restraints of my naming conventions, you shouldn't hesitate to adopt the method
you think best. For example, if you really prefer <TT>eFName</TT> or plain
<TT>FName</TT>
rather than <TT>FNameEdit</TT> as the name of a <TT>TDBEdit</TT> control, then you
should go with your gut instinct. <BR>
<BR>
My history in this regard is simple. I started out deploring Hungarian notation and
then slowly inched
over to the point at which I was reluctantly starting to use it
in my programs. <BR>
<BR>
Then there came a day when I was squinting at some egregious variable name dreamed
up by an undoubtedly besotted Microsoft employee, and I just knew that I
had had
enough of abbreviations, and especially of prefixing them to a variable name. <BR>
<BR>
One of my original goals was to keep variable names short. I went to great lengths
to achieve this end. Then I watched C++ linkers mangle my short
variable names into
behemoths that consumed memory like sharks possessed by a feeding frenzy. After contemplating
this situation for a while, I decided that the one thing I could bring to the table
that I really cared about was clarity. As a
result, I dropped Hungarian notation
from all my new code and began using whole words whenever possible.
<HR>
</BLOCKQUOTE>
<P>The bottom panel should contain four buttons for navigating through the table's
records, as well as Edit, Insert, and
Cancel buttons. A status bar at the bottom
of the main form provides room for optionally reporting on the current status of
the program.</P>
<P>The top of the program contains a menu with the following format:</P>
<PRE><FONT COLOR="#0066FF">Caption =
`File'
Caption = `Print'
Caption = `-'
Caption = `Exit'
Caption = `Edit'
Caption = `Copy'
Caption = `Cut'
Caption = `Paste'
Caption = `Options'
Caption = `Filter'
Caption = `Set Category'
Caption = `Search'
Caption =
`First Name'
Caption = `Last Name'
Caption = `Company'
Caption = `Sorts'
Caption = `First Name'
Caption = `Last Name'
Caption = `Company'
Caption = `Colors'
Caption = `Form'
Caption = `Edits'
Caption = `Edit Text'
Caption
= `Labels'
Caption = `------'
Caption = `Panels'
Caption = `System'
Caption = `Default'
Caption = `------'
Caption = `The Blues'
Caption = `Save Colors'
Caption = `Read Colors'
Caption = `Marks'
Caption = `Mark All'
Caption = `Clear All Marks'
Caption = `Print Marked to File'
Caption = `Show Only Marked'
Caption = `Help'
Caption = `About'
</FONT></PRE>
<P>Each line represents the caption for one entry in the program's main menu. The
indented portions
are the contents of the drop-down menus that appear when you select
one of the menu items visible in Figure 13.2.</P>
<P>After you create the program's interface, drop down a <TT>TTable</TT> and <TT>TDataSource</TT>
on a data module, wire them up to
<TT>ADDRESS.DB</TT>, and hook up the fields to
the appropriate data-aware control. Name the <TT>TTable</TT> object <TT>AddressTable</TT>
and name the <TT>TDataSource</TT> object <TT>AddressSource</TT>. To make this work
correctly, you should create an
alias, called <TT>Address</TT>, that points to the
location of <TT>ADDRESS.DB</TT>. Alternatively, you can create a single alias called
<TT>CUnleashed</TT> that points to the tables that ship on the CD that accompanies
this book. Take a look at the
readme files on the CD that accompanies this book for
further information on aliases.</P>
<P>Now switch back to the main form, use the File | Include Unit Header option to
connect the main form and the <TT>TDataModule</TT>, and hook up the data-aware
controls
shown in Figure 13.2 to the fields in the address table. The only tricky part of
this process involves the <TT>Category</TT> field, which is connected to the <TT>TDBLookupComboBox</TT>.
I will explain how to use this field over the course of
the next few paragraphs.</P>
<P>If you run the program you have created so far, you will find that the <TT>TDBLookupComboBox</TT>
for the <TT>Category</TT> field does not contain any entries; that is, you can't
drop down its list. The purpose of this
control is to enable the user to select categories
from a prepared list rather than force the user to make up categories on the fly.
The list is needed to prevent users from accidentally creating a whole series of
different names for the same general
purpose.</P>
<P>Consider a case in which you want to set a filter for the program that shows only
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -