📄 ch23.htm
字号:
fastcall TDMod::TDMod(TComponent* Owner)
: TDataModule(Owner)
{
}
void __fastcall TDMod::DModCreate(TObject *Sender)
{
WidgetsTable->Open();
}
void __fastcall TDMod::SumByProduct()
{
AnsiString S = "Select Name, Count(*), Sum(Cost) "
"from Widgets "
"group by Name;";
WidgetsQuery->SQL->Clear();
WidgetsQuery->SQL->Add(S);
WidgetsQuery->Open();
}
void __fastcall TDMod::ReportByPallet()
{
AnsiString S = "Select PalletNumber, Name, Count(*), Sum(Cost) "
"from Widgets "
"group by PalletNumber, Name;";
WidgetsQuery->SQL->Clear();
WidgetsQuery->SQL->Add(S);
WidgetsQuery->Open();
}
</FONT></PRE>
<P><A NAME="Heading22"></A><FONT COLOR="#000077"><B>Listing 23.10. The header file
for the very simple QueryForm.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">#ifndef QueryForm1H
#define QueryForm1H
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\DBGrids.hpp>
#include
"Grids.hpp"
#include <vcl\ExtCtrls.hpp>
class TQueryForm : public TForm
{
__published:
TDBGrid *DBGrid1;
TPanel *Panel1;
private:
public:
virtual __fastcall TQueryForm(TComponent* Owner);
};
extern TQueryForm
*QueryForm;
#endif
</FONT></PRE>
<P><A NAME="Heading23"></A><FONT COLOR="#000077"><B>Listing 23.11. There is no custom
code in the QueryForm.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// QueryForm1.cpp
// Warehouse example: learning about objects
// Copyright (c) 1997 by Charlie Calvert
//
#include <vcl\vcl.h>
#pragma hdrstop
#include "QueryForm1.h"
#include "DMod1.h"
#pragma link "Grids"
#pragma resource
"*.dfm"
TQueryForm *QueryForm;
__fastcall TQueryForm::TQueryForm(TComponent* Owner)
: TForm(Owner)
{
}
</FONT></PRE>
<P><A NAME="Heading24"></A><FONT COLOR="#000077"><B>Listing 23.12. The header for
the very simple
DataForm.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// DataForm1.h
// Warehouse example: learning about objects
// Copyright (c) 1997 by Charlie Calvert
//
#ifndef DataForm1H
#define DataForm1H
#include
<vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\DBGrids.hpp>
#include "Grids.hpp"
#include <vcl\ExtCtrls.hpp>
class TDataForm :
public TForm
{
__published:
TDBGrid *DBGrid1;
TPanel *Panel1;
private:
public:
virtual __fastcall TDataForm(TComponent* Owner);
};
extern TDataForm *DataForm;
#endif
</FONT></PRE>
<P><A NAME="Heading25"></A><FONT
COLOR="#000077"><B>Listing 23.13. The main module
for the DataForm contains no custom code.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// DataForm1.cpp
// Warehouse example: learning about objects
// Copyright
(c) 1997 by Charlie Calvert
//
#include <vcl\vcl.h>
#pragma hdrstop
#include "DataForm1.h"
#include "DMod1.h"
#pragma link "Grids"
#pragma resource "*.dfm"
TDataForm *DataForm;
__fastcall
TDataForm::TDataForm(TComponent* Owner)
: TForm(Owner)
{
}
</FONT></PRE>
<P><A NAME="Heading26"></A><FONT COLOR="#000077"><B>Listing 23.14. The header file
for a form that provides a list box for displaying the hierarchy of
objects.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// HierarchyDlg.h
// Learning how to use objects
// Copyright (c) 1997 by Charlie Calvert
//
#ifndef HierarchyDlg1H
#define HierarchyDlg1H
#include
<vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\ExtCtrls.hpp>
#include <vcl\Buttons.hpp>
class THierarchyDlg : public TForm
{
__published:
TListBox *ListBox1;
TPanel *Panel1;
TBitBtn *BitBtn1;
private:
public:
__fastcall THierarchyDlg(TComponent* Owner);
};
extern THierarchyDlg *HierarchyDlg;
#endif
</FONT></PRE>
<P><A NAME="Heading27"></A><FONT
COLOR="#000077"><B>Listing 23.15. HierarchyDlg has
no custom code in it. The form simply provides a list box in which hierarchies can
be shown.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// HierarchyDlg.cpp
//
Learning how to use objects
// Copyright (c) 1997 by Charlie Calvert
//
#include <vcl\vcl.h>
#pragma hdrstop
#include "HierarchyDlg1.h"
#pragma resource "*.dfm"
THierarchyDlg *HierarchyDlg;
__fastcall
THierarchyDlg::THierarchyDlg(TComponent* Owner)
: TForm(Owner)
{
}
</FONT></PRE>
<P>This program creates five forms at application startup:</P>
<PRE><FONT COLOR="#0066FF">Application->CreateForm(__classid(TForm1), &Form1);
Application->CreateForm(__classid(TDMod), &DMod);
Application->CreateForm(__classid(TDataForm), &DataForm);
Application->CreateForm(__classid(TQueryForm), &QueryForm);
Application->CreateForm(__classid(THierarchyDlg),
&HierarchyDlg);
</FONT></PRE>
<P>Of these forms, the first two contain significant code, while the last three contain
nothing but visual elements that can be shown to the user. For instance, the <TT>QueryForm</TT>
provides a <TT>TDBGrid</TT> that
can be filled with the results of SQL statements
executed inside the program's data module. <TT>THierarchyDlg</TT> provides a list
box that can be filled with the hierarchy of some of the objects used in the program.</P>
<P>The Warehouse application
also relies heavily on the <TT>Widgets</TT> and <TT>MyObject</TT>
modules. In fact, the majority of the program is really nothing but a set piece for
the classes found in <TT>Widgets.cpp</TT>. These objects will be explained in the
next section of
this chapter.
<H3><A NAME="Heading28"></A><FONT COLOR="#000077">The Hierarchy for the Widget and
Pallet Components</FONT></H3>
<P>Four components lie at the heart of the Warehouse program. These components are
called <TT>TWidget</TT>,
<TT>TPentium</TT>, <TT>TPentiumPro</TT>, and <TT>TDataPallet</TT>.
All these objects are declared and implemented in <TT>Widgets.h</TT> and <TT>Widgets.cpp</TT>.
The hierarchies for these components are shown in Figures 23.8 and 23.9.<BR>
<BR>
<A
NAME="Heading29"></A><A HREF="23ebv08.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/23/23ebv08.jpg">FIGURE 23.8.</A><FONT COLOR="#000077">
</FONT><I>The hierarchy for the Widget controls used to represent chips.</I>
<H6></H6>
<P><A NAME="Heading30"></A><A HREF="23ebu01.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/23/23ebu01.jpg">FIGURE
23.9.</A><FONT COLOR="#000077">
</FONT><I>The hierarchy for the Pallet controls used to store chips.</I></P>
<P>As you can see, all these components descend from <TT>TCustomControl</TT>. The
primary reason for choosing this ancestor was that it had a
canvas. <TT>TCustomControl</TT>
descendants can also contain other controls, which was an option I wanted to keep
open in case I desired to build a widget that consisted of several sub-widgets.
<DL>
<DT></DT>
</DL>
<BLOCKQUOTE>
<P>
<HR>
<FONT
COLOR="#000077"><B>NOTE:</B></FONT><B> </B><TT>TGraphicControl</TT> also has
a canvas, but it cannot contain subcontrols or receive the focus. In this case, I
made a judgment call and decided that it would be wiser to use the more powerful
<TT>TCustomControl</TT> rather than <TT>TGraphicControl</TT>, even though <TT>TCustomControl</TT>
uses more resources and takes longer to paint. In the context of this book, it's
not really too important which choice I made, so long as I communicate
to you the
relative virtues of each option.
<HR>
</BLOCKQUOTE>
<P>In Figure 23.10, you can see the hierarchy for the Widget and Pallet controls
taken together. For obvious reasons, there is more complexity in this dual hierarchy
than there is in
either of the single hierarchies shown in Figures 23.8 and 23.9.
My point here is simply that the valuable thing about objects is their capability
to isolate complexity. As a programmer, you want to find ways to break big, ungainly
problems down into
smaller, manageable programs. Objects are one of the best ways
to achieve this goal.<BR>
<BR>
<A NAME="Heading32"></A><A HREF="23ebu02.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/23/23ebu02.jpg">FIGURE 23.10.</A><FONT COLOR="#000077">
</FONT><I>The hierarchy for the Widget and Pallet controls,
showing their mutual
descent from <TT>TCustomControl</TT>.</I></P>
<P>When necessary, break off objects, or object hierarchies, into separate trees
and study them alone. Write small test programs that explore the virtues and faults
of one object in
isolation. Make sure the code you write can be broken up into various
smaller programs for testing. For instance, it is easy to take the <TT>TPentium</TT>
component, drop it onto a form, and test it in isolation from the complexity found
in the
Warehouse program. Components make this kind of testing easy, and that is
one of their greatest virtues: They are easily reusable.</P>
<P>Perhaps one of the hardest lessons that beginning programmers have to learn is
the value of writing small test
programs. If I can't break my programs down into
smaller units that can be tested separately, I will generally concede that there
is some flaw in my design.</P>
<P>To reiterate: One of the primary goals of OOP is to allow you to build discrete,
reusable chunks of code that can be tested in isolation. Components aid in this process
enormously, and it is one of the primary reasons why so many components are so robust.
The key here is that components are easy to test, and, as a result, a lot of
problems
get caught that might otherwise be overlooked.
<H3><A NAME="Heading33"></A><FONT COLOR="#000077">Understanding TWidget, TPentium,
and TPentiumPro</FONT></H3>
<P>The <TT>TWidget</TT> object provides a base object from which all widgets can
descend. The <TT>TWidget</TT> class provides three basic properties common to all
widgets:</P>
<PRE><FONT COLOR="#0066FF">__property Currency Cost;
__property AnsiString TimeCreated;
__property AnsiString Description;
</FONT></PRE>
<P>As you saw in
Chapter 20, "Encapsulation," widgets can also be saved
to disk.</P>
<P>The <TT>TChip</TT> object is the base class for computer chips. In the implementation
of this object I provide here, the <TT>TChip</TT> object has only minimal
functionality:</P>
<PRE><FONT COLOR="#0066FF">class TChip: public TWidget
{
public:
virtual __fastcall TChip(TComponent *AOwner): TWidget(AOwner) {}
virtual __fastcall TChip(TComponent *AOwner, int ACol, int ARow)
: TWidget(AOwner, ACol,
ARow) {}
};
</FONT></PRE>
<P>If you wanted to have more fun with this object, you could add a wide variety
of fields:</P>
<PRE><FONT COLOR="#0066FF">class TChip: public TWidget
{
private:
int MHZ;
bool MMX;
int Cache;
int Transistors;
float Voltage;
int RegisterSize; // 16, 32, 64?
public:
virtual __fastcall TChip(TComponent *AOwner): TWidget(AOwner) {}
virtual __fastcall TChip(TComponent *AOwner, int ACol, int ARow)
: TWidget(AOwner, ACol, ARow) {}
};
</FONT></PRE>
<P>Here you can see an object that contains standard fields for describing the basic
attributes of a chip. I hope that in some future version of this program, I will
add these features, but for now it is best if I push on and finish the book before
my
editors tell me what they are really thinking about the timeline for this book's
development.</P>
<P>Descending from <TT>TChip</TT> are <TT>TPentium</TT> and <TT>TPentiumPro</TT>.
As implemented here, the only thing unique about these two objects is
their virtual
<TT>Paint</TT> methods:</P>
<PRE><FONT COLOR="#0066FF">class TPentium: public TChip
{
protected:
virtual void __fastcall Paint(void);
public:
virtual __fastcall TPentium(TComponent *AOwner): TChip(AOwner) {}
virtual
__fastcall TPentium(TComponent *AOwner, int ACol, int ARow)
: TChip(AOwner, ACol, ARow) {}
};
class TPentiumPro: public TChip
{
protected:
virtual void __fastcall Paint(void);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -