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

📄 ch22.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:

class TSmallEdit : public TEdit

{

private:

protected:

public:

  virtual __fastcall TSmallEdit(TComponent* Owner);


__published:

};

</FONT></PRE>
<P><FONT COLOR="#0066FF"><TT>#endif</TT></FONT>
<H4><FONT COLOR="#000077">Listing 22.5. The implementation of TSmallEdit as produced
by the standard boilerplate output of the Component Expert.</FONT></H4>
<PRE><FONT 
COLOR="#0066FF">

//--------------------------------------------------------------------------

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

#pragma hdrstop

#include &quot;Unleash1.h&quot;

//--------------------------------------------------------------------------


static inline TSmallEdit *ValidCtrCheck()

{

  return new TSmallEdit(NULL);

}

//--------------------------------------------------------------------------

__fastcall TSmallEdit::TSmallEdit(TComponent* Owner)

  : TEdit(Owner)

{

}


//--------------------------------------------------------------------------

namespace Unleash1

{

  void __fastcall Register()

  {

    TComponentClass classes[1] = {__classid(TSmallEdit)};

    RegisterComponents(&quot;Unleash&quot;, classes, 0);

  
}

}

</FONT></PRE>
<P><FONT COLOR="#0066FF"><TT>//--------------------------------------------------------------------------</TT>
</FONT><BR>
<BR>
The Component Expert starts by giving you <TT>#include</TT> directives designed to
cover most of the 
bases you are likely to touch in a standard component:</P>
<PRE><FONT COLOR="#0066FF">

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

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

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

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

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

</FONT></PRE>
<P>The next step is to give you a basic class declaration, in which the name and
parent are filled in with the choices you specified in the Component Expert dialog.
All this business about the scoping directives 
is just for your convenience, and
you can delete any portion of it that you don't think you'll need.</P>
<PRE><FONT COLOR="#0066FF">class TSmallEdit : public TEdit

{

private:

  // Private declarations

protected:

  // Protected declarations


public:

  // Public declarations

  virtual __fastcall TSmallEdit(TComponent* Owner);

__published:

  // Published declarations

};

</FONT></PRE>
<P>Before you can place a component on the Component Palette, you first must register
it with the 
system:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall Register()

{

  TComponentClass classes[1] = {__classid(TSmallEdit)};

  RegisterComponents(&quot;Unleash&quot;, classes, 0);

}

</FONT></PRE>
<P>Registering a class makes it known to the BCB 
Component Palette when the unit
is compiled into the BCB component library. The <TT>Register</TT> procedure has no
impact on programs compiled with this unit. Unless your program calls the <TT>Register</TT>
procedure (which it should never do), the 
code for the <TT>Register</TT> procedure
will never execute.</P>
<P>This method first creates an array consisting of the types of components you want
to register. Recall that <TT>__classid</TT> is one of the new pieces of syntax added
to the language. 
It is dis- cussed in Chapter 2, &quot;Basic Facts About C++Builder.&quot;
After creating the array, you call <TT>RegisterComponents</TT>, which takes the name
of the page you want to use in the Component Palette in the first parameter, the
array of 
metaclasses in the second parameter, and the size of the array in the third
parameter. If the page does not exist, it will be created automatically. Here is
the declaration for <TT>RegisterComponents</TT>:</P>
<PRE><FONT COLOR="#0066FF">extern void 
__fastcall RegisterComponents(const System::AnsiString Page,

  System::TMetaClass* const * ComponentClasses, const int ComponentClasses_Size);

</FONT></PRE>
<P>Recall that <TT>TMetaClass</TT> is declared in <TT>SysDefs.h</TT> and that it
represents 
a subset of <TT>TObject</TT>. You can get the metaclass of a VCL object
by calling the object's <TT>ClassType</TT> method.</P>
<P>If you look back at the source for the whole project, you will see that the <TT>Register</TT>
method is placed in its own 
namespace. This happens because multiple declarations
for methods with that name will occur throughout your projects and, indeed, inside
BCB itself. As a result, the compiler's need for order must be satiated with a few
discreetly placed namespaces. 
This whole subject will come up again in just a moment,
when I talk about recompiling <TT>CmpLib32.ccl</TT>.</P>
<P>After using the Component Expert, you should save the project. Proceed as you
normally would by creating a directory for the project 
and saving <TT>Main.pas</TT>
and <TT>TestUnleash1.cpp</TT> inside it. You should not save the new unit that you
created into the same directory, however, but you should place it in the <TT>Utils</TT>
directory where you store files such as 
<TT>CodeBox</TT>. This code is now going
to come into play as part of your system, and as such you want a single path that
leads to all related files of this type. If you have all your components in different
subdirectories, you will end up with a 
source path that is long and unwieldy.

<DL>
	<DD>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT><TT>ValidCtrCheck()</TT> verifies that
	creating an instance of the object at compile time is possible. If you forget to
	override a pure virtual 
function, the compilation of the component will fail because
	the statement <TT>&quot;new foo(0)&quot;</TT> is now invalid. You can test this by
	creating a component derived from <TT>TCustomGrid</TT> (an abstract class) and installing
	it without 
doing any work to change the object.<BR>
	<BR>
	Because <TT>ValidCtrCheck</TT> is inline and never called, no code will be generated--so
	there is no runtime cost. 
<HR>

</DL>

<P><BR>
The goal of this project is to give a component of type 
<TT>TEdit</TT> a new set
of default behaviors so that it starts out with certain colors and certain fonts.
To do so, you need to override the <TT>Create</TT> method and change the fonts inside
it. The method declaration itself appears 
automatically:</P>
<PRE><FONT COLOR="#0066FF">class TSmallEdit : public TEdit

{

public:

  virtual __fastcall TSmallEdit(TComponent* Owner);

};

</FONT></PRE>
<P>Notice that in the preceding declaration I have removed the <TT>private</TT>,

__<TT>published</TT>, and <TT>protected</TT> directives created by the Component
Expert. Making this change is neither here nor there; I do it just to keep the amount
of code you need to look at as small as possible.</P>
<P>The <TT>Create</TT> method 
for <TT>TSmallEdit</TT> is declared as <TT>public</TT>.
If you think about the process of creating a component dynamically, you will see
that the <TT>Create</TT> method has to be <TT>public</TT>. This is one method that
must be exposed. Like all VCL 
constructors, <TT>TSmallEdit</TT> is declared <TT>virtual</TT>
and <TT>__fastcall</TT>.</P>
<P><TT>Create</TT> is passed a single parameter of type <TT>TComponent</TT>, which
is a base class that encapsulates the minimum functionality needed to be an 
owner
of another component and to place a component on the Component Palette. In particular,
whatever form you place a component on usually will be the owner of that component.</P>
<P>The implementation of the <TT>Create</TT> method is simple:</P>

<PRE><FONT COLOR="#0066FF">__fastcall TSmallEdit::TSmallEdit(TComponent* Owner)

  : TEdit(Owner)

{

  Color = clBlue;

  Font-&gt;Color = clYellow;

  Font-&gt;Name = &quot;Times New Roman&quot;;

  Font-&gt;Size = 12;

  Font-&gt;Style = 
TFontStyles() &lt;&lt; fsBold &lt;&lt; fsItalic;

}

</FONT></PRE>
<P>The code first calls <TT>Create</TT>, passing in the variable <TT>AOwner</TT>.
As I stated previously, the owner of a component will often, though not always, be
the form on which 
the component is to be displayed. In other words, the user will
drop the component onto a form, and that form will become the owner of the component.
In such a case, <TT>AOwner</TT> is a variable that points to the form. The VCL uses
it to initialize 
the <TT>Owner</TT> property, which is one of the fields of all components.</P>
<P>The next step is to define the color and font that you want to use, with <TT>Font-&gt;Style</TT>
defined as follows:</P>
<PRE><FONT COLOR="#0066FF">enum TFontStyle { 
fsBold, fsItalic, fsUnderline, fsStrikeOut };

typedef Set&lt;TFontStyle, fsBold, fsStrikeOut&gt;  TFontStyles;

</FONT></PRE>

<DL>
	<DD>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>Don't let all this gobbledygook confuse
	you! All that occurs in 
this declaration is that a simple <TT>enum</TT> type is declared,
	and then you see a <TT>Set</TT> declaration for the type that ranges from a low value
	of <TT>fsBold</TT> to a high value of <TT>fsStrikeOut</TT>. Piece of cake! 
<HR>

</DL>

<P><BR>

If you want to add the underline and bold style to the text in the edit control,
write the following:</P>
<PRE><FONT COLOR="#0066FF">Font-&gt;Style = TFontStyles &lt;&lt; fsBold &lt;&lt; fsUnderline;

</FONT></PRE>
<P>If you then want to add the 
italic style at runtime, write this:</P>
<PRE><FONT COLOR="#0066FF">Font-&gt;Style = Font-&gt;Style &lt;&lt; fsItalic;

</FONT></PRE>
<P>To remove the style, write this line:</P>
<PRE><FONT COLOR="#0066FF">Font-&gt;Style = Font-&gt;Style &gt;&gt; 
fsItalic;

</FONT></PRE>
<P>At this stage, the code is ready to go on the Component Palette. However, most
of the time when you write components, you should test them first to see whether
they work.</P>
<P>Even on a fast machine, the process of 
recompiling <TT>CmpLib32.ccl</TT> and adding
your component to the Component Palette takes between 10 seconds and 2 minutes. Perhaps
I'm a bit impatient, but that's a little too long a wait for me if all I need to
tweak is a few aspects of my code. As 
a result, I test things first in a small program
and then add the component to the IDE.</P>
<P>To test the new class, drop a button on the program's main form, and create an
<TT>OnClick</TT> handler:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall 
TForm1::Button1Click(TObject *Sender)

{

  TSmallEdit *MyEdit = new TSmallEdit(this);

  MyEdit-&gt;Parent = this;

  MyEdit-&gt;Show();

}

</FONT></PRE>
<P>Don't forget to use View | Project Manager and add the unit to the project. This
ensures 
that the <TT>USEUNIT</TT> macro is placed in your project source.</P>
<P>This code creates the component and shows it on the main form. <TT>this</TT>,
of course, is the way that <TT>TForm1</TT> refers to itself from inside one of its
own methods. The 
owner of the new component is <TT>Form1</TT>, which will be responsible
for disposing of the component when finished with it. This process happens automatically.
You never need to worry about disposing of a visible component shown on a form.</P>

<P>The parent of the component is also <TT>Form1</TT>. The <TT>Parent</TT> variable
is used by Windows when it is trying to decide how to display the form on the screen.
If you place a panel on a form and drop a button on the panel, the owner of that

button is the form, but the parent is the panel. Ownership determines when and how
the component is deallocated, and parental relationships determine where and how
the component is displayed. Ownership is fundamentally a BCB issue, whereas parental

relationships are primarily concerns of Windows.

<DL>
	<DD>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>The next paragraph in this section explains
	how to recompile <TT>CmpLib32.ccl</TT>. Remember that you should always keep a backup
	copy of 
<TT>CmpLib32.ccl</TT> on your hard drive. <TT>CmpLib32.ccl</TT> is stored
	in the <TT>..\CBUILDER\BIN</TT> directory. Beneath this directory, I have created
	another directory called <TT>BACK</TT> where I keep a backup copy of <TT>CmpLib32.ccl</TT>.
	
If worse comes to worst, you can always copy the version of <TT>CmpLib32.ccl</TT>
	on your installation CD back into the <TT>BIN</TT> subdirectory.<BR>
	<BR>
	My personal experience is that everyone, sooner or later, makes a tasty Mulligan's
	Stew out 
of a copy of <TT>CmpLib32.ccl</TT>. The worst-case scenario is that you're
	on the road when this mess happens, and that you don't have access to your installation
	disk. Don't let this situation happen to you. Keep a backup copy of 
<TT>CmpLib32.ccl</TT>
	on your hard drive at all times!<BR>
	?FIGURE 17.16. Creating SQL selection criteria in ReportSmith. CCL stands for C++Builder
	Component Library. 
<HR>

</DL>

<P><BR>
After you run the program and test the component, the next 
step is to put it up on
the Component Palette. To do so, choose Components | Install and then click the Add
button. Browse through the directories until you find <TT>Unleash1.Cpp</TT>, select
OK, and then close the Install Components dialog by 
clicking OK. At this point, a
project called <TT>CmpLib32.cpp</TT> is compiled. This project creates a huge DLL
called <TT>CmpLib32.ccl</TT>, which contains all the components in the Component
Palette, all the component and property editors associated 
with those components,
the form designer part of the IDE, the experts, and other support modules.</P>
<P>After <TT>CmpLib32.ccl</TT> finishes recompiling, you can start a new project,
turn to the newly created Unleash page, and drop your new component 
onto a form.
It will have a blue background, default to Times New Roman, and have its font style
set to bold and its font color to yellow. Notice that all the properties of <TT>TEdit</TT>
have been inherited by <TT>TSmallEdit</TT>. That's OOP in 
action. You can see an
example of the form that uses this control in Figure 22.3.</P>
<P><A HREF="22ebu03.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/22/22ebu03.jpg">Figure 22.3.</A><I>Using the <TT>TSmallEdit</TT>
control on a standard VCL form.</I>
<H2><FONT COLOR="#000077">Understanding the 
Project Source for CmpLib32</FONT></H2>
<P>You can save the <TT>CmpLib32.cpp</TT> file used during compilation of <TT>CmpLib32.ccl</TT>
to disk if you choose Options | Environment | Library | Save Library Source Code.
After choosing this option and 
recompiling <TT>CmpLib32.ccl</TT>, you can go to the
<TT>\CBUILDER\BIN</TT> directory and view your copy of <TT>CmpLib32.cpp</TT>.</P>
<P>Here is an example of the source code produced by the IDE for use when compiling
<TT>CmpLib32.ccl</TT>:</P>

<PRE><FONT COLOR="#0066FF">

//--------------------------------------------------------------------------

// Component Palette

// Copyright (c) 1996, 1996 by Borland International, All Rights Reserved

//

// Module generated by C++Builder to 
rebuild the Component

// Palette Library (CmpLib32.ccl).

//--------------------------------------------------------------------------

//--------------------------------------------------------------------------

// In order to be totally Delphi 
compatible, the Component palette must be

// built with a namespaced version of the VCL library. Using namespace allows

⌨️ 快捷键说明

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