⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch24.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>

<HEAD>
	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
	<META NAME="Author" Content="Steph Mineart">
	<TITLE>Ch 24 -- Creating Non-Visual Components</TITLE>
</HEAD>


<BODY BACKGROUND="bg1.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/bg1.gif" BGCOLOR="#FFFFFF">

<P ALIGN="CENTER"><IMG SRC="sams.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/sams.gif" WIDTH="75" HEIGHT="24" ALIGN="BOTTOM"
BORDER="0"><BR>
<BR>
<A HREF="index-3.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/index.htm"><IMG SRC="toc.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/toc.gif" WIDTH="40" HEIGHT="40" ALIGN="BOTTOM"

ALT="TOC" BORDER="0" NAME="toc4"></A><A HREF="ch23.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch23.htm"><IMG SRC="back-1.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/back.gif"
WIDTH="40" HEIGHT="40" ALIGN="BOTTOM" ALT="BACK" BORDER="0" NAME="toc1"></A><A HREF="ch25.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch25.htm"><IMG
SRC="forward.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/forward.gif" WIDTH="40" HEIGHT="40" ALIGN="BOTTOM" 
ALT="FORWARD" BORDER="0"
NAME="toc2"></A></P>
<H2 ALIGN="CENTER"><FONT COLOR="#000077">Charlie Calvert's C++ Builder Unleashed</FONT></H2>
<P>
<H2 ALIGN="CENTER"><A NAME="Heading1"></A><FONT COLOR="#000077">- 24 -</FONT></H2>
<H2 ALIGN="CENTER"><A 
NAME="Heading2"></A><FONT COLOR="#000077">Creating Non-Visual
Components</FONT></H2>
<P>
<H3><A NAME="Heading3"></A><FONT COLOR="#000077">Overview</FONT></H3>
<P>In this chapter, you will learn how to build a non-visual component. In particular,
I 
will emphasize the following topics:

<UL>
	<LI>Descending directly from <TT>TComponent</TT>
	<P>
	<LI>Using and designing non-visual components
	<P>
	<LI>Using <TT>FindFirst</TT> and <TT>FindNext</TT> to iterate through the files in
	directories
	<P>
	
<LI>Creating your own stacks
	<P>
	<LI>Pushing and popping items off a stack
</UL>

<P>In particular, you will look at one reusable non-visual component called <TT>TFindDirs</TT>,
which is used in a program that will iterate through a series of 
directories and
will archive the names of the files found there into a database. You could, for example,
use the program to iterate over all the files on several zip discs of CD-ROMs. You
would then have one database that could be searched when you're 
looking for files
that might be located on any of a number of different discs.
<H3><A NAME="Heading4"></A><FONT COLOR="#000077">Why Create Non-Visual Components?</FONT></H3>
<P>The program shown in this chapter uses the <TT>TFindDirs</TT> component to 
illustrate
the concept of component reuse. Write the <TT>TFindDirs</TT> component once, and
you can reuse it in multiple programs. The big bonus here is that <TT>TFindDirs</TT>
is a component and thereby makes a relatively complex task simple enough 
that you
can perform it by just dropping an object onto a form and plugging it into your program.</P>
<P>This short chapter is presented primarily to promote the idea of turning objects
that you might not usually think of as components into 
components. You can easily
see why an edit control makes a good component, but the fact that an object used
to iterate through directories would make a good component is less obvious. In fact,
I first turned this object into a component on a whim. 
Once I had it around, however,
I found that I could plug it into all kinds of applications to aid with one task
or another.</P>
<P>Here are some of my applications that use this component:

<UL>
	<LI>A program for iterating through directories to 
delete files that I no longer
	need.
	<P>
	<LI>A program for &quot;touching&quot; all the files in a series of directories so
	that they have the same date.
	<P>
	<LI>A file backup utility for comparing two directory structures to be sure they
	are 
identical. This same program will also produce scripts that copy files from one
	directory structure to the other if a mismatch occurs.
</UL>

<P>My point here is that writing these utilities became easy after I had the <TT>TFindDirs</TT>
component in 
place. The core functionality for each of these programs was easy to
implement because it was based on a component. As you will see, in just a few seconds
you can create a program that uses the component. After you have that much functionality
in 
place, you can easily add more features.
<H3><A NAME="Heading5"></A><FONT COLOR="#000077">When Should Non-Visual Objects Become
Components?</FONT></H3>
<P>Whether you should turn a particular object into a component is not always clear.
For example, 
the <TT>TStringList</TT> object has no related component and cannot
be manipulated through visual tools. The question then becomes &quot;Why have I taken
the <TT>TFindDirs</TT> object and placed it on the Component Palette?&quot;</P>
<P>As you'll 
discover, the advantages of placing <TT>TFindDirs</TT> on the Component
Palette are two-fold:

<UL>
	<LI>You might need to tweak several options before you use this object. In particular,
	you need to decide whether you want to have the lists of 
directories and files that
	you find saved to memory in a <TT>TStringList</TT>. Letting the programmer decide
	these matters by clicking a property can go a long way toward presenting a clean,
	easy-to-use interface for an object.
	<P>
	<LI>The 
<TT>TFindDirs</TT> object has two features that can be accessed through the
	<TT>Events</TT> page. Specifically, custom event handlers can be notified every time
	a new file or directory has been found. However, constructing an event handler manually
	
can be confusing, particularly if you don't know which parameters will be passed
	to the functions involved. If you place a component on the Component Palette, you
	do not need to guess about how to handle an event. All it takes is a quick click
	on 
the <TT>Events</TT> page, and the event handler is created for you automatically!
</UL>

<P>Creating a component also has the enormous advantage of forcing, or at least encouraging,
programmers to design a simple interface for an object. After I have 
placed an object
on the Component Palette, I always want to ensure that the user can hook it into
his or her program in only a few short seconds. I am therefore strongly inclined
to create a simple, easy-to-use interface. If I don't place the 
component on the
Component Palette, then I find it easier to slip by with a complex interface that
takes many lines of code for myself and others to utilize. To my mind, good components
are not only bug free, but also very easy to use.
<H3><A 
NAME="Heading6"></A><FONT COLOR="#000077">The SearchDirs Program</FONT></H3>
<P>In this section, you will find the SearchDirs program, which can be used to iterate
through the subdirectories on a hard drive looking for files with a particular name
or 
file mask. For example, you could look for <TT>*.cpp</TT> or <TT>m*.cpp</TT> or
<TT>ole2.hpp</TT>. This program will put the names of all the files that match the
mask into a database, so you can search for the files later.</P>
<P>The SearchDirs 
program depends on the <TT>TFindDirs</TT> component, which ships
with this book. To use this component, you must first load it onto the Component
Palette, using the techniques described in the preceding few chapters. In general,
all you have to do is 
choose Component | Install and then click the Add button. Browse
the <TT>Utils</TT> subdirectory that ships with this book. There you will find the
<TT>FindDirs2.cpp</TT> unit. Add it to <TT>CMPLIB32.CCL</TT>, and you are ready to
build the SearchDirs 
program. As usual, you might want to run the BuildObjs project
once before installing the component. The source for this program is shown in Listings
24.1 through 24.8. A screen shot of the program is shown in Figure 24.1. You need
to make sure the 
<TT>CUnleashed</TT> alias is in place before running the program.
This is a standard Paradox alias that points at the data directory off the root directory
where the files from the CD that accompany this book are installed. See both the
text right 
after the listings and also the readme file for more information about
the alias.<BR>
<BR>
<A NAME="Heading7"></A><A HREF="24ebu01.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/24/24ebu01.jpg">FIGURE 24.1.</A><FONT COLOR="#000077">
</FONT><I>A screen shot of the main form of the SearchDirs 
program.</I></P>
<P>The point here is that <TT>TFindDirs</TT>, like <TT>TTable</TT> and <TT>TQuery</TT>,
is a non-visual component. <TT>TFindDirs</TT> completes your introduction to the
basic component types by showing you how to build nonvisual 
components. You already
know how to build visual components. After you understand how to build non-visual
components, most of the power of BCB will be open to you. The <TT>TFindDirs</TT>
component is also important because it shows you how to create 
custom event handlers.<BR>
<BR>
<A NAME="Heading8"></A><FONT COLOR="#000077"><B>Listing 24.1. The header for the
main form for the SearchDirs program.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////

// Main.h

// 
SearchDirs

// Copyright (c) 1997 by Charlie Calvert

//

#ifndef MainH

#define MainH

#include &lt;vcl\Classes.hpp&gt;

#include &lt;vcl\Controls.hpp&gt;

#include &lt;vcl\StdCtrls.hpp&gt;

#include &lt;vcl\Forms.hpp&gt;

#include 
&lt;vcl\Menus.hpp&gt;

#include &lt;vcl\ComCtrls.hpp&gt;

#include &lt;vcl\DBGrids.hpp&gt;

#include &lt;vcl\Grids.hpp&gt;

#include &lt;vcl\DBCtrls.hpp&gt;

#include &lt;vcl\ExtCtrls.hpp&gt;

#include &quot;FindDirs2.h&quot;



class TForm1 : public 
TForm

{

__published:

  TMainMenu *MainMenu1;

  TMenuItem *File1;

  TMenuItem *Counter1;

  TMenuItem *N1;

  TMenuItem *Exit1;

  TMenuItem *Run1;

  TDBGrid *FileNamesGrid;

  TMenuItem *Options1;

  TMenuItem *Delete1;

  TMenuItem 
*DisableGrids1;

  TPanel *Panel2;

  TEdit *Edit1;

  TEdit *Edit2;

  TMenuItem *N2;

  TMenuItem *PickArchive1;

  TLabel *Label1;

  TLabel *Label2;

  TStatusBar *StatusBar1;

  TDBGrid *DirNamesGrid;

  TFindDirs *FindDirs1;

  void __fastcall 
Button1Click(TObject *Sender);

  void __fastcall Exit1Click(TObject *Sender);

  void __fastcall Delete1Click(TObject *Sender);

  void __fastcall PickArchive1Click(TObject *Sender);

  void __fastcall OnFoundDir(AnsiString NewDir);

  void 
__fastcall FindDirs1FoundFile(AnsiString NewDir);

private:

  int FStartLevel;

  AnsiString FCurrentRoot;

  AnsiString FDiskName;

  void StartRun();

  void EndRun();

public:  

  virtual __fastcall TForm1(TComponent* Owner);

};



extern TForm1 
*Form1;



#endif



</FONT></PRE>
<P><A NAME="Heading9"></A><FONT COLOR="#000077"><B>Listing 24.2. The main form for
the SearchDirs program.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////

// Main.cpp

// SearchDirs


// Copyright (c) 1997 by Charlie Calvert

//

#include &lt;vcl\vcl.h&gt;

#pragma hdrstop

#include &quot;Main.h&quot;

#include &quot;DiskArchive.h&quot;

#include &quot;FindDirsDMod.h&quot;

#pragma resource &quot;*.dfm&quot;

TForm1 *Form1;




__fastcall TForm1::TForm1(TComponent* Owner)

  : TForm(Owner)

{

}



int GetLevel(AnsiString Source)

{

  BOOL Done = False;

  int i = 0;

  char S[500];



  strcpy(S, Source.c_str());



  strtok(S, &quot;\\&quot;);

  while (!Done)

  {

    
if (strtok(NULL, &quot;\\&quot;) == NULL)

      Done = True;

    else

      i += 1;

  }

  return i;

}



void TForm1::StartRun()

{

  DirNamesGrid-&gt;DataSource = NULL;

  FileNamesGrid-&gt;DataSource = NULL;

  Screen-&gt;Cursor = 
(Controls::TCursor)crHourGlass;

  FindDirs1-&gt;StartString = Edit1-&gt;Text;

  FDiskName = Edit2-&gt;Text;



  FStartLevel = GetLevel(FindDirs1-&gt;StartDir);

  DMod-&gt;DiskNamesTable-&gt;Insert();

  
DMod-&gt;DiskNamesTable-&gt;FieldByName(&quot;DiskName&quot;)-&gt;AsString = FDiskName;

  DMod-&gt;DiskNamesTable-&gt;Post();

}



void TForm1::EndRun()

{

  Screen-&gt;Cursor = (Controls::TCursor)crDefault;

  DirNamesGrid-&gt;DataSource = 
DMod-&gt;DirNamesSource;

  FileNamesGrid-&gt;DataSource = DMod-&gt;FileNamesSource;

}



void __fastcall TForm1::Button1Click(TObject *Sender)

{

  if (MessageBox((HWND)Handle, Edit1-&gt;Text.c_str(), &quot;Make Run?&quot;, MB_YESNO) == ID_YES)

  
{

    StartRun();

    FindDirs1-&gt;Run();

    EndRun();

  }

}



void __fastcall TForm1::Exit1Click(TObject *Sender)

{

  Close();

}



void __fastcall TForm1::Delete1Click(TObject *Sender)

{

  if (MessageBox((HWND)Handle, 
&quot;Delete&quot;, &quot;Delete Dialog&quot;, MB_YESNO) == ID_YES)

    DMod-&gt;CascadingDelete();        

}



void __fastcall TForm1::PickArchive1Click(TObject *Sender)

{

  ArchiveForm-&gt;ShowModal();    

}



void __fastcall 
TForm1::OnFoundDir(AnsiString NewDir)

{

  int i;

  

  StatusBar1-&gt;SimpleText = NewDir;

  StatusBar1-&gt;Update();



  FCurrentRoot = NewDir;



  i = GetLevel(FCurrentRoot);

  DMod-&gt;DirNamesTable-&gt;Insert();

  
DMod-&gt;DirNamesTable-&gt;FieldByName(&quot;DirName&quot;)-&gt;AsString = NewDir;

  DMod-&gt;DirNamesTable-&gt;FieldByName(&quot;ALevel&quot;)-&gt;AsInteger = i;

  DMod-&gt;DirNamesTable-&gt;FieldByName(&quot;DiskCode&quot;)-&gt;AsInteger =

  
DMod-&gt;DiskNamesTable-&gt;FieldByName(&quot;Code&quot;)-&gt;AsInteger;

  DMod-&gt;DirNamesTable-&gt;Post();

}



void __fastcall TForm1::FindDirs1FoundFile(AnsiString NewDir)

{

  AnsiString Temp;

  

  if (FCurrentRoot.Length() == 0)

    Temp 
= FindDirs1-&gt;StartDir;

  else

    Temp = FCurrentRoot;



  DMod-&gt;FileNamesTable-&gt;Insert();

  DMod-&gt;FileNamesTable-&gt;FieldByName(&quot;Directory&quot;)-&gt;AsString = Temp;

  
DMod-&gt;FileNamesTable-&gt;FieldByName(&quot;FileName&quot;)-&gt;AsString =

    ExtractFileName(NewDir);

  DMod-&gt;FileNamesTable-&gt;Post();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -