📄 cb199910nf_f.asp.htm
字号:
<P class=Code><SPAN
class=Code> RegisterComponents("Informant",
classes, 0);</SPAN></P>
<P class=Code><SPAN class=Code> }</SPAN></P>
<P class=Code><SPAN class=Code>}</SPAN></P>
<P class=Code><SPAN class=Code><I><SPAN class=CodeBlue>//
--------------------------------------------------------</SPAN></I></SPAN></P>
<P class=Captions><B>Figure 4:</B> The wizard creates skeleton source for
the component.<B> </B></P>
<P class=BodyText> </P>
<P class=BodyText>As mentioned earlier, custom components are classes
subclassed from existing classes. To be a component, a class must inherit
from at least <I style="mso-bidi-font-style: normal">TComponent</I>. This
is the class that encapsulates the common behavior evidenced by all
components, namely, the ability to be dropped on a form at design time, to
have properties set in the Object Inspector, and to be registered on the
Component palette. Not surprisingly, the <I>DefaultedDBNavigator</I>
inherits from the built-in <I>TDBNavigator</I> class. </P>
<P class=BodyText> </P>
<P class=BodyText>Notice that the PACKAGE modifier is added to the class
declaration. This facilitates the instantiation from the package DLL.
Currently, the only method that appears in the class declaration is the
constructor. For this simple component, no methods need to be added, thus
this header file doesn't need to change. </P>
<P class=BodyText> </P>
<P class=BodyText>The source file includes some handy header files
(including the header file for this component), and a method named
<I>ValidCtrCheck</I>. This function is automatically included in every
custom component's source file. It allows the component user to try to
instantiate an instance of the component to ensure that none of the
methods are pure virtual methods. In other words, this function is a
helper to ensure the class is legally instantiable. It does this by
creating a new instance of the class, then immediately allowing it to go
out of scope. If the class cannot be created, an exception is thrown
indicating that some methods aren't implemented. </P>
<P class=BodyText> </P>
<P class=BodyText>The empty constructor is also present in the source
file. It includes in its member initialization list the constructor call
to the parent class' constructor. This is a convenience; one of the
classic blunders when creating components in Delphi/C++Builder is to
forget to chain the call to the parent's constructor. This call to the
base class constructor should never be removed. </P>
<P class=BodyText> </P>
<P class=BodyText>The last entry in the source file is the <I>Register</I>
function, included in a specific custom name space. This function takes
care of registering the component onto the Component palette. The name of
the palette page specified from the wizard is included here and can be
changed here. </P>
<P class=BodyText> </P>
<P class=BodyText>To override default property values for a component, the
new values need only to be added to the constructor. So, to create the
custom navigator with the desired characteristics, three lines of code
must be added to the constructor. This newly modified constructor is shown
in Figure 5. First, the current button set of the navigator is cleared.
Then, new values are added to the empty button set. Last, the
<I>ShowHint</I> property is toggled to <B>true</B>.</P>
<P class=BodyText> </P>
<P class=Code><SPAN class=Code><B>__fastcall</B>
TDefaultedDBNavigator::TDefaultedDBNavigator(</SPAN></P>
<P class=Code><SPAN class=Code> TComponent* Owner):
TDBNavigator(Owner)</SPAN></P>
<P class=Code><SPAN class=Code>{</SPAN></P>
<P class=Code><SPAN
class=Code> VisibleButtons.Clear();</SPAN></P>
<P class=Code><SPAN class=Code> VisibleButtons =</SPAN></P>
<P class=Code><SPAN class=Code> VisibleButtons
<< nbFirst << nbPrior << nbNext <<
nbLast;</SPAN></P>
<P class=Code><SPAN class=Code> ShowHint = <B
style="mso-bidi-font-weight: normal">true</B>;</SPAN></P>
<P class=Code><SPAN class=Code>}</SPAN></P>
<P class=Captions><B>Figure 5:</B> To override default property values for
a component, the new values need to be added to the constructor.<B
style="mso-bidi-font-weight: normal"></B></P>
<P class=BodyText> </P>
<P class=BodyText>To install the component, the package must be compiled,
which is accomplished via the Package editor. Like a project, it will
automatically compile all the constituent source files that have been
changed since the last compilation. Once it has been successfully
compiled, the components in the package are installed on the Component
palette by choosing the Install button on the Package editor. In this
case, a new palette page is created, and the new
<I>TDefaultedDBNavigator</I> appears, ready for use. </P>
<P class=BodyText> </P>
<P class=Subheads>"Defaulted" Component Characteristics</P>
<P class=BodyText>When this new component is dropped on a form, only the
navigation buttons appear, and the <I>ShowHint</I> property is <B>true
</B>by default. This new component is shown in Figure 6. </P>
<P class=BodyText> </P>
<P class=Captions><IMG height=91
src="images/CB199910nf_f_image008.gif" width=250
tppabs="http://www.cbuilderzine.com/features/1999/10/CB199910nf_f/CB199910nf_f_image008.gif">
<BR><B>Figure 6:</B> When the new component is dropped on a form, only the
navigation buttons appear, and the <I>ShowHint</I> property is <B>true</B>
by default.<B> </B></P>
<P class=BodyText> </P>
<P class=BodyText>However, what will happen now if the developer changes
one of these properties? Will it allow these changes and allow the
properties to be set at both design time and run time? In fact, it will.
The developer can still change these new defaults in the Object Inspector
and they will appear correctly at run time. How can this be? Aren't these
properties being set to their values in the constructor of the class? The
answer to this puzzle lies in the way C++Builder builds forms at run time
(and, by extension, design time as well). This is slightly simplified, but
close enough to illustrate the point. </P>
<P class=BodyText> </P>
<P class=BodyText>First, C++Builder fires the constructor for the form.
During this step, it opens the contents of the DFM file (which is at this
time embedded within the executable), reads the names of all the
components, and constructs them one by one. When it constructs them,
however, it ignores the property settings embedded in the DFM file. So,
the order in which the components are created corresponds to the order in
which they appear in the DFM file. Second, after the form's constructor
has finished, it goes back to the DFM file and starts applying all the
changes to the default values of all the components. </P>
<P class=BodyText> </P>
<P class=BodyText>Notice that C++Builder always constructs components with
all their default values and later applies the DFM changes. This also
explains why this new component works correctly; even though the new
defaults are set in the constructor of the component, the form will ensure
that whatever changes are embedded in the DFM file will overlay these new
defaults. This means it's easy and useful to create these "lightweight"
components with new defaults because it doesn't preclude the developer
from changing the defaults if required. </P>
<P class=BodyText> </P>
<P class=BodyText>This technique works equally well with database
components. For example, if a particular project always used the same
database connection characteristics, it would be easy to create a custom
Database component that already had all the connectivity options set, e.g.
user name, password, server characteristics, etc. The same is true for
tables or queries that are reused often. </P>
<P class=BodyText> </P>
<P class=BodyText>It's possible for the developer to take advantage of the
behavior of the form-loading architecture. One of the methods that can be
overridden in a component is the <I>Loaded</I> method. The form
automatically calls this method when it has finished applying the changes
in the DFM file. This means the component developer can add some of his or
her own behavior at this time. Some of the components created in future
installments of this series will illustrate this technique. </P>
<P class=BodyText> </P>
<P class=BodyText>When the new component is installed, it will take on the
component bitmap of its immediate parent or the "generic" component bitmap
(which is similar to the Shape component bitmap). It's also possible to
create your own new component bitmaps. </P>
<P class=BodyText> </P>
<P class=Subheads>Component Bitmaps</P>
<P class=BodyText>Palette bitmaps aren't compiled into the component unit
because they're only needed at design time, not at run time. Instead, they
should be supplied in a resource file with a .DCR (Dynamic Component
Resource) extension and the same name as the component unit. This is a
critical requirement; the bitmap will not load if the names differ.
C++Builder provides an Image Editor tool to create component bitmap images
(see Figure 7). It creates a new DCR file. </P>
<P class=BodyText> </P>
<P class=Captions><IMG height=215
src="images/CB199910nf_f_image010.gif" width=250
tppabs="http://www.cbuilderzine.com/features/1999/10/CB199910nf_f/CB199910nf_f_image010.gif">
<BR><B>Figure 7: </B>The Image Editor.<B> </B></P>
<P class=BodyText> </P>
<P class=BodyText>To create an image for a particular component, the
developer right-clicks and chooses to create a new bitmap. This leads to
the Bitmap Properties dialog box, shown in Figure 8. The image must be
24x24 pixels square and VGA (16 colors). </P>
<P class=BodyText> </P>
<P class=Captions><IMG height=132
src="images/CB199910nf_f_image012.gif" width=250
tppabs="http://www.cbuilderzine.com/features/1999/10/CB199910nf_f/CB199910nf_f_image012.gif">
<BR><B>Figure 8: </B>The Bitmap Properties dialog box. </P>
<P class=BodyText> </P>
<P class=BodyText>To actually create the bitmap, the speed menu option for
editing the bitmap should be selected. A palette to create or edit the
bitmap image will appear, as shown in Figure 9. The developer can create
as elaborate an image as possible given the limited size and palette
available. To many developers, this is the most difficult aspect of
component creation. </P>
<P class=BodyText> </P>
<P class=Captions><IMG height=227
src="images/CB199910nf_f_image014.gif" width=250
tppabs="http://www.cbuilderzine.com/features/1999/10/CB199910nf_f/CB199910nf_f_image014.gif">
<BR><B>Figure 9:</B> A palette to create or edit bitmap images.<B>
</B></P>
<P class=BodyText> </P>
<P class=BodyText>If the component has already been added to the palette,
it must be removed from the package and re-added to force C++Builder to
include the DCR file in the package. Once it's been correctly installed,
it will appear along with the component in the Package editor. The
<I>DefaultedDBNavigator</I> component (along with its bitmap) is shown in
Figure 10. </P>
<P class=BodyText> </P>
<P class=Captions><IMG height=72
src="images/CB199910nf_f_image016.jpg" width=177
tppabs="http://www.cbuilderzine.com/features/1999/10/CB199910nf_f/CB199910nf_f_image016.jpg">
<BR><B>Figure 10: </B>The <I>DefaultedDBNavigator</I> component and its
bitmap.<B> </B></P>
<P class=BodyText> </P>
<P class=Subheads>Up Next</P>
<P class=BodyText>C++Builder has created the most powerful, yet
easy-to-use, component model ever seen in the C++ world. This article
doesn't even begin to scratch the surface. In the next installment of this
series, the implications and implementation of new component properties
will be discussed. The technique of object wrapping (taking some complex
behavior and wrapping it into a component) will also be discussed. </P>
<P class=BodyText> </P>
<P class=BodyText><I>The files referenced in this article are available
for <a href="download/CB199910nf_f.zip" tppabs="http://www.cbuilderzine.com/features/1999/10/CB199910nf_f/CB199910nf_d.asp">download</a>.
</I></P>
<P class=BodyText> </P>
<P class=Biotext>Neal Ford is Vice President of Technology at The DSW
Group. He is also the designer and developer of applications,
instructional materials, magazine articles, video presentations, and
co-author of <I>JBuilder 3 Unleashed</I> [SAMS, 1999]. He can be reached
at <A
href="mailto:nford@thedswgroup.com">mailto:nford@thedswgroup.com</A>, or
by calling The DSW Group at (800) 356-9644. </P>
<!-- Abstract<p class=Abstract>Neal Ford
begins a series on creating custom components in C++Builder. Part I kicks off
with an introduction to new defaults for native components. </p>Abstract -->
<!-- Blurb<p class=Blurb>Whether a component user or a component writer, you're sure to
gain productivity after reading this series on creating custom components.</p>Blurb --></TD></TR></TBODY></TABLE>
<!-- <PubToken>cb</PubToken> --></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -