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

📄 cb199911nf_f.asp.htm

📁 C++builder学习资料C++builder
💻 HTM
📖 第 1 页 / 共 4 页
字号:


<HTML>

  <HEAD>

 <TITLE>Creating Custom Components</TITLE>

   

  </HEAD>

  <BODY>

   <TABLE border=0 width="100%" cellpadding=0 cellspacing=0>

<TR valign=top>

<TD width="100%">



<p class=ColumnTitle><font size="2">From the 

Palette</font></p> 

 

<p class=ColumnSubtitle>Components 

/ Properties / Buttons</p> 

 

<p class=BodyText> &nbsp; </p> 

 

<p class=Byline>By Neal Ford</p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=StoryTitle><font size="2"><b>Creating     

Custom Components</b></font></p>     

     

<p class=StorySubtitle><font size="2">Part     

II: Properties and Button Behavior</font> </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> In Part     

I of this series on component creation in C++Builder, I introduced the basics     

of component development, as well as some peripheral issues, such as how to     

create component bitmaps. Part II delves deeper into the internal workings of     

components and discusses two issues: </p>     

     

<p class=BodyText> 1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     

How     

properties are defined and used. </p>     

     

<p class=BodyText> 2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     

How     

the <i>Click</i> behavior of buttons works. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Subheads>Get/Set     

Routines</p>     

     

<p class=BodyText> You're     

already familiar with properties from having to set their values from the     

Object Inspector. However, they are more broadly useful. A property is     

essentially a level of indirection away from members of classes - typically     

private members. Properties also provide a terrific information-hiding     

mechanism. First, we'll look at the syntax for declaring a property; then we'll     

illustrate some common uses for properties. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> Properties     

implement what is known in the software engineering world as Get/Set routines.     

For every private class member you want to access, you can write a routine to     

get the value, and another routine to set the value. This provides good     

information hiding because you're not directly accessing the private part of     

the class. Therefore, you're free to change the internal data representation in     

the future. The property can be accessed as if it were a simple variable. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> Here is     

an example of a simple class with a property to act as Get/Set routines for the     

private member variable: </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Code><span class=Code><b>class</b>     

MyClass : <b>public</b> TComponent</span></p>     

     

<p class=Code><span class=Code>{</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;<b> private</b>:</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;TColor FColor; </span></p>     

     

<p class=Code><span class=Code><b>&nbsp;&nbsp;__published</b>:</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;<b> __property</b>     

TColor Color = { read = FColor, write = FColor };</span></p>     

     

<p class=Code><span class=Code>};</span></p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> The     

naming convention for private variables in classes whose values will be set     

with properties prefixes the variable name with an "F" (for "Field"). It's more     

common in the C++ world that private member variables be prefixed with an "m_"     

instead of an "F". However, when dealing with the VCL, it's wise to follow its     

conventions. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> When you     

declare a property, you can declare a read and write clause for it. In the     

previous example, the read and write modifiers allow the property to be changed     

directly, but don't provide much obvious benefit. Consider this version: </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Code><span class=Code><b>class</b>     

MyClass : <b>public</b> TComponent</span></p>     

     

<p class=Code><span class=Code>{</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;<b> private</b>:</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;TColor FColor; </span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;<b> void</b>     

<b>__fastcall</b> SetColor(TColor value); </span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;TColor <b>__fastcall</b> GetColor();</span></p>     

     

<p class=Code><span class=Code><b>&nbsp;&nbsp;__published</b>:</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;<b> __property</b>     

TColor Color = { read = GetColor, write = SetColor };</span></p>     

     

<p class=Code><span class=Code>};</span></p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> Notice     

that the read and write modifiers can accept as parameters either a variable     

reference or a method. In this example, all access to <i>TColor</i> is done through the Get/Set routines: Nowhere is the value     

directly accessed. This is beneficial because you're now free to change how <i     

style='mso-bidi-font-style:normal'>TColor</i> is kept internally. For example,     

you may change the internal color representations to use direct RGB values     

instead of the enumerated <i>TColor</i>     

type. To affect this change, you can change the Get/Set routines to map the new     

representation, but you don't have to make any changes to the property. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> The     

property provides a well-published interface to the internals of the class,     

which may change over time. However, any code that depends on this class needs     

only to be re-compiled when this class is changed. This effectively hides how     

you have implemented color inside the class, and leaves you free to change it     

whenever you want, as long as you don't change the published interface. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> Remember,     

the property could be accessed as if it were a simple variable. This is true     

even if the Get/Set routines are present. C++Builder takes care of mapping the     

Get/Set routines appropriately. So, when you assign a property, it looks as if     

you're simply assigning a value to a variable: </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Code><span class=Code>MyObj-&gt;Color     

= clRed; </span></p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> C++Builder     

takes care of firing the Get/Set routines for you. Incidentally, this is how     

C++Builder manages to act so much like an interpreter in design mode. When you     

change a property with an assignment statement, you're not only changing the     

internal value of the property; the Set routine is executing the code necessary     

in Windows to make the change come about. For example, when you assign a color     

to a label's <i>Color</i> property, this     

assignment is changing the label's internal <i>FColor</i>     

property to <i>clRed</i>, but the Set routine is executing the necessary     

Windows calls to make the color of the label actually change to red on the     

form. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> You     

should rely on properties for all the member variables in the classes you     

create. Even if you don't need this level of indirection now, you can never     

predict when you will need it in the future. You should implement properties     

that directly read and write the internal values until you find yourself     

needing to create a side effect as a result of an assignment. Then you can     

create the Get and/or Set routine to provide that functionality. By creating     

them as properties, you can ensure the published interface to your class     

doesn't change. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Subheads>Default     

Values</p>     

     

<p class=BodyText> Component     

properties frequently have default values associated with them. This is     

accomplished in two steps. First, use the <b>default</b> directive when     

declaring the property. Here is an example: </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Code><span class=Code><b>class</b>     

MyClass : <b>public</b> TComponent</span></p>     

     

<p class=Code><span class=Code>{</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;<b> private</b>:</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;TColor FColor; </span></p>     

     

<p class=Code><span class=Code><b>&nbsp;&nbsp;__published</b>:</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;<b> __property</b>     

TColor Color =</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ read = FColor, write = FColor, <b     

style='mso-bidi-font-weight:normal'>default</b> = clSilver };</span></p>     

     

<p class=Code><span class=Code>};</span></p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> In the     

class definition, the <b>default</b> directive doesn't actually set a default     

value for the control. Instead, it controls whether the value for this control     

gets streamed out to the DFM file at design time. Remember, the only values     

that get streamed to the DFM file are those that have changed from their default     

values. The <b>default</b> directive determines that default value. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> To     

actually make the value the default value for a control, you must also set the     

value in the component's constructor: </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Code><span class=Code><b>__fastcall</b>     

MyClass::MyClass(TComponent* Owner) : TComponent(Owner) </span></p>     

     

<p class=Code><span class=Code>{</span></p>     

     

<p class=Code><span class=Code>&nbsp;&nbsp;Color = clSilver; </span></p>     

     

<p class=Code><span class=Code>}</span></p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> Although     

you can type all the code necessary to create a property by hand, C++Builder     

(starting with version 4) has a nice dialog box that allows you to easily add     

properties and all their characteristics. The Add Property dialog box is     

invoked from the class explorer by right-clicking and choosing to create a new     

property (see Figure 1). </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=Captions><img width=333 height=383     

 src="images/cb199911nf_f_image002.gif" tppabs="http://www.cbuilderzine.com/features/1999/11/cb199911nf_f/cb199911nf_f_image002.gif" align=left> <br clear=all>     

<b>Figure 1:</b> The Add Property dialog box. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

     

     

<p class=Subheads><i>TRandomNumber</i> </p>     

     

<p class=BodyText> Not all     

objects (or components) are created to handle features or characteristics not     

supported by the library, i.e. the standard C/C++ libraries, or the VCL. It's     

sometimes useful to create components that encapsulate some operation that's     

"messy" for some reason. This is the rationale for the <i>TRandomNumber</i> component. The <i>TRandomNumber</i>     

component hides the messy details of acquiring a random number from C++Builder.     

To get a random number, you must: </p>     

     

<p class=BodyText> 1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     

Call     

the <i>randomize</i> function to seed the random number generator, and</p>     

     

<p class=BodyText> 2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     

Call     

the <i>random</i> function, which gives you a random number between 0 and the     

number passed. </p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> If you     

need a random number within a range, you have to deal with adding and     

subtracting the number you get back, which is prone to off-by-one errors. Also,     

you have to remember to call the <i>randomize</i> function. This is a perfectly     

messy operation to encapsulate into a component. The complete source for the <i     

style='mso-bidi-font-style:normal'>TRandomNumber</i> component (both header and     

source) can be found in <a href="#ListingOne">Listing     

One</a>.</p>     

     

<p class=BodyText> &nbsp; </p>     

     

<p class=BodyText> The     

⌨️ 快捷键说明

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