Delphi & Program experience & ERP & Software
My Component Design experience
Published on March 4, 2005 By MICROTSAI In Software Development
¥DÃD: ¤¸¥ó³]­p²¤¶
¥Øªº
¥¼¨Ó¸ê°T¨t²Î´Â¦V¤À´²¦¡ N-Tie¤Îºô»Úºô¸ôªº¶}µo¼Ò¦¡,¨t²Î¶}µo¤H­û¥²»Ý¨ã³Æ¤¸¥óªº¶}µo¯à¤O,
¦Û¦æ³]­p¨t²Î¯S®í»Ý¨Dªº¤¸¥ó,¤~¯àº¡¨¬¥¼¨Ó¸ê°T¨t²Îµo®iªºÁͶÕ.

®Éµ{: 6HR
Object ªº·§©À(2 HR)
Component ³]­p(4 HR)

½Òµ{¤jºõ
¤@. Object ªº·§©À(2HR)
1. Class:
A class is a user-defined data type.
A class has some internal data and some methods,in the form of procedures or functions,
and usually described the generic characteristics and behavior of a number of very similar
object.
1>class property / method / event
1>>property: A class property is used to maintain general information related to the class
2>> method: A class method is a method related to the whole class,not its objects.
3>> event: A class event provide a time for class to process windows message(mouseclick/keypress/keydown..).
2>event handle
Event handle is an object procedure to process something while event occur.
It is like a procedure type,but refers to an object method.
Ex: procedure Button1Click(Sender: TObject);

2. Object:
An object is an instance of a class. Objects are real entities.
1>The relationship between object and class is the same as the one between variable and type.
each variable of a class type,does not hold the value of the object,Rather it contains
reference,or a pointer, to indicate the memory location where the object has been stored.
2> Object instances must be created manually,at least for the objects of the classes you define.
Instances of the component you place on a form are built automatically.
3> To create an instance of an object,we can call its Create method,which is a constructor.
A Constructor is a special procedure used to allocate memeoy for new objects and initialize
them.
4> Self can be defined as a pointed to the current object.
5> Example
1_ClassObject.11_ClassObject

6> Constructor & Destrcutor & Self
1>>To allocate the memory for the object,we call the create method.
However before we can actually use the object,we often need to initialize it.
To do this, we can add a constructor to the class.
2>>Just as a constrcutor call allocates memory for the object,a destructor call frees the memeoy.
3>> Example
1_ClassObject.12_ClassObject


¤G.Object oriented ªº¯S©Ê
1. inherited(Ä~©Ó)

2. encapsulated(«Ê¥])
1>For a good object-oriented approach, data should be hidden,or encapsulated, inside the class
using it .
2>You seldom know which internal data the object has,and usually have no way to access it directly,
Of course you are supposed to use methods to access the data,which is shielded from unauthorized
access. The is the object-oriented approach to a classical programming theory known as
information hiding.
3>¬[ºc:
Public
init
SetValue <----------|
LeapYear |
|
------------------------------------------------|
|
Private | from Another class
Year |
Month <---X------|
Day

4> private / protected / public / published
1.Private:
The private keyword denotes fields and methods of a class that are not accessible outside
the unit.

2.Protected:
The protected keyword is used to indicate partially protected methods and fields.
Protected elements can be accessed by the current class and all its descendent classes.

3.Public:
The public keyword denotes methods and fields that are freely accessible from any other portion of the code of a program ,as well as in the unit in which they are defined.

4.Published:
A published field or method is not only available at run-time but also at design-time.
In fact,only the published methods of your form can show up in the Object Inspector.

5>Example
2_Private


3 Polymorphism(¦h«¬)
Object-oriented programming languages,include Object Pascal,allow the use of another form
of binding,known as dynamic binding or late binding.In this case,the actual address of the
method to be called is determined at run-time
The advantage of this approach is known as polymorphism.

1> Static & Dynamic & Virtual & Abstract method
1>> Static method:
Pascal function and procedure are usually based on static binding.
This means that a method call is resolved by the compiler and the linker.

2>> Virtual method
another form of binding,known as dynamic binding or late binding.
In this case,the actual address of the method to be called is determined at run-time
you write the call to a method,but the code actually called depends on the type of the
object.

3>>.Override Virtual method:
To override a virtual method in a descendent class,you need to use the override keyword.
this can take place only if the method was defined as virtual in the ancestor class.
Otherwise ,if it was a static method ,there is no way to make it dynamic,other then by
changing the code of ancestor class.why you need to use the override keyword.
In other languages ,when you redefine a method in a subclass,you automatically override
the original one.However ,having a specific keyword allows the compiler to check the
correspondence between the names of methods of the methods of the ancestor class and
subclass.

PS: Overload method
Object Pascal also supports overloaded funtcions and methods:
you can have multiple methods with the same name,provided that
the parameters are different.
By checking the parameters,the compiler can determine which of the versions of the
routine you want to call. Example : 2_private

4>>Dynamic method:
The result of Dynamic method use is also the same with Virtual.
The different between dynamic & virtual is the internal mechanism used by the compiler to
implement dynamic binding.
Virtual methods are based on a virtual method table(VMT).
Dynamic medhods are dispatched using a unique code indicating the method. slightly different
speed or memory usage between virtual & dynamic method.
If the method is going to be overridden by nearly every descendent,make it virtual.
If the method is not going to be overridden very often by descendent,make it dynamic.

5>>Abstract method:
The abstract keyword is used to declare methods that will be implemented only in subclasses if the current class.
The Abstract method must be also Virtual or Dynamic method.
Example
1_ClassObject.Real


1.6 Run-time Type information
The Object Pascal type-compatibility rule for descendent classes allows you to use a
descendent class where an ancestor class is expected.
Question:
Suppose that the Dog class has an Eat function,which is not present in the Animal class.
if the variable,MyAnimal refers to a dog,it should be possible to call the function.
the variable is referring to another class,the result is an error.
Solution:
we can use some techniques based on RTTI.in short, each object knows its type and its
inheritance.
Ex:
Procedure DoEat(MyAnimal:TAnimal);
begin
if MyAnimal is Dog then begin
MyDog:= Dog(MyAnimal); // MyDog := MyAnimal as Dog
MyDog.Eat;
end;
end;

ð (MyAnimal as Dog).Eat; // ¤]¥i
ð
1.7 Example:
3_Polymorphism

2 Component ³]­p(3HR)
2.1 Create Component
Create a new component manually requires four steps:
1>Create a new unit
2>Deriving the component object
TMyComponent = class(TComponent)
private
..
published
..
end;
3>design component field / method / property /event
4>Registering the component
Registering a component is a simple process that tells Delphi what components to
add to its components library and which pages of the Component palette the components
should appear on.
call RegisterComponents procedure for each component you want to register.
RegisterComponent take two parameters:
.the name of a Component palette page
.a set of component types.
Ex:
procedure Register;
begin
RegisterComponents('Samples',[TMyComponent]) ;
end;
5>Install Component

Example : 4_FirstComp.31_NewButton
¥Øªº: ¦Û¦æ³]­p NewButton Object ,Ä~©Ó¦Û TButton
¦ý·s¼W¤@ Property ==> Value :integer;
method ==> procedure ShowValue;

2.2 Create Property
1.To declare a property,you specify three things:
.The name of the property
.The type of the property
.Methods to read and/or set the value of the property

2.conventions for property:
There are no restrictions on how you store the data for a property,In general,
however,Delphi's component follow these conventions:
.Property data is stored in object fields.
.Identifier for object fields start with the letter f.
.Object fields for property data should be declared as private.
This ensures that the component that declares the property has accesss to then ,
but component users and descendant component don't.if a method or or another property needs
to change that data,it should do so through the property, not by direct access to the stored
data.
.The syntax for property declarations

property :
read write
default ;

Example of Direct Access:
type
TOneComponent = class(TComponent)
private //internal storage is private
fReadOnly: Boolean; //declare field to hold property value
published //make property available at design time
property ReadOnly : Boolean read fReadOnly write fReadOnly default true;
end;

3. Access methods of property:
The syntax for property declarations allows the read and write parts of a property
declaration to specify access methods instead of an object field.Regardless of how a
particular property implements its read and writge parts,that implementation should be
private,and descendant components should use the inherited property for access.
The Read method:
The read method for a property is a function that takes no parameters and return
a value of the same type as the property.
By convention,the functon's name is "Get" followed by the name of the property.
The Write method:
The write method for a property is a procedure that takes single parameters of
the same type as the property.
The parameter can be passed by reference or by value,and can have any name you choose.
By convention,the procedure's name is "Set" followed by the name of the property.
Default property value:
To declare a default value for a property ,append the default directive to the property's
declaration,followed by the default value.
Note:
Declaring a default value in the property declaration does not actually set the property
to that value,It is your responsibility as the component writer to ensuer that the
component's constructor actually sets the property to that value.
Example : 4_FirstComp.31NewButton
Ex:
TNewButton = class(TButton)
private
fValue:integer;
function GetValue:integer;
procedure SetValue(par_Value:integer);
public
constructor Create(AOwner: TComponent); override;
procedure ShowValue;
published
property Value:integer Read GetValue write SetValue default 10; // Caption+inttostr(Value)
end;

2.3 Create method
Component methods are no different from any other object's method.That is,They are just procedures
and functions built into the structure of a component.
As a general rule,methods you write in your components will be either public or protected.
The exception to that rule is methods that implement properties,which should always be private.
Public:
Any methods that users of your components need to be able to call must be declared as public.
Constructors and destructors should always be public.
Protected:
if you have methods that a user's code should not call,but which descendant objects will need
to call,you should declare the methods as protected.

2.4 Paint method : Åã¥Ü¤¸¥óªº Canvas
TArrow = class(TGraphicControl)
..
protected
procedure Paint; override;
published
..
end;

Example : 4_FirstComp.33_Arrow



2.5 Create event
¬[ºc:
Windows Windows Application
O.S Dispatch
¢z¢w¢w¢w¢w¢w¢w¢{ ¢z¢w¢w¢w¢w¢w¢w¢{ ¢z¢w¢w¢w¢w¢w¢{
User ¡ý ¡ý ¡ýMessage ¡ý-----> ¡ýµ{¦¡ A ¡ý ¦UÀ³¥Îµ{±µ¦¬message, Trigger -->>¡ýWindow ¡ý---->¡ýDispatch ¡ý : ¢|¢w¢w¢w¢w¢w¢} ·|¦Û¦æ¨M©w¦p¦ó¤ÏÀ³¸Ó
Event ¡ýMessage ¡ý ¡ý ¡ý : ¢z¢w¢w¢w¢w¢w¢{ message
(keyin ¡ýQueue ¡ý ¡ý ¡ý-----> ¡ýµ{¦¡ B ¡ý
MouseMove ¡ý: ¡ý ¡ý ¡ý : ¢|¢w¢w¢w¢w¢w¢}
: ¡ý ¡ý ¡ý ¡ý : ¢z¢w¢w¢w¢w¢w¢{
¡ý ¡ý ¡ý ¡ý-----> ¡ýµ{¦¡ C ¡ý
¢|¢w¢w¢w¢w¢w¢w¢} ¢|¢w¢w¢w¢w¢w¢w¢} ¢|¢w¢w¢w¢w¢w¢}

Windows Message:
A Windows message is a data record that contains several useful fields.
The most important of these is an integer size value that identifies the message.
The other useful information in a message comes in two parameter fields and a result field.
One parameter contains 16bits,the other 32bits.You often see Windows code that refers to those
values as wParam and lParam,for "Word paramter" and "long parameter"
Originally,Windows programmers had to remember what each parameter contained,More
Recently,Microsoft has named the partmeters.
Ex: the parameters to WM_KEYDOWN message are now called VKey and KeyData,which
give much more specific information then wParam and lParam.
Ex:
TMessage =packedrecord
Msg: Cardinal;
case Integer of
0: (
WParam: Longint;
LParam: Longint;
Result: Longint);
1: (
WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ResultHi: Word);
end;
Delphi event:
Delphi defines a specific record type for each different type of message that
gives mnemonic name to each parameter.For example,mouse message record,you need
not concern you self with which word is which,because you refer to the parameters
by names XPos and YPos instead of lParamLo and lParamHi.
Ex:
type
TWMMouse = packedrecord
Msg: Cardinal;
Keys: Longint;
case Integer of
0: (
XPos: Smallint;
YPos: Smallint);
1: (
Pos: TSmallPoint;
Result: Longint);
end;

Dispatching messages:
When an application creates a window,it registers a window procedure with the Windows kernel.
The window procedure is the routine that handles messages for the window.
Traditionally,the window procedure contains a huge case statement with entries for each message
the window has to handle.
Keep in mind that "windows" in the sense means just about anything on the screen: each
window,each control,and so on.


Standard events for all controls:
OnClick OnDblClick
OnMouseDown OnMouseUp OnMouseMove
OnDragDrop OnDragOver OnEndDrag

Standard events for windows controls:
OnEnter OnExit
OnKeyDown OnKeyPress OnKeyUp

Defining your own events:
There are four steps in defining an event:
.Triggering the event
.Defining the handle type
.Declaring the event
.Calling the event

½d¨Òµ{¦¡: 5_CreateEvent\1ArrowEvent\Arrow1e.pas
±N¦Û¦æ³]­p¤§ Arrow ¤¸¥ó¥[¤J Double Click Event
³B²z»¡©ú:
¤@.«Ø¥ß Property [event],¥H«K point to eventhandle
1.«Å§i¤@ Property ==> OnArrowDblClick ¨ä¸ê®Æ«¬ºA¬° TNotifyEvent
§Y¨ä¬° procedure .. of Object
2.«Å§i private data ==> fArrowDblClick : TNotifyEvent [Point to eventhandle]
§Y¨Ï¥ÎªÌ Double Click ¤¸¥ó®É·|¥h¦s¨ú fArrowDBlClick
§Y fArrowDblClick ·|«ü¦V eventHandle ¤§ procedure
----------------------------------------------------------------------------------------
¤G.«Ø¥ß¤¸¥ó³B²z Window Message ªº¯à¤O
1.·í¨Ï¥ÎªÌ DblClick ®É,¤¸¥ó¥²»Ýª¾¹D
Windows message : wm_LButtonDblClk
2.Windows message IJµo®É,¥h°õ¦æ eventhandle



Event ³]­p¬yµ{:
WM_LButtonDown -> DoMouseDown -> FOnMousedown(MouseDown) -> OnMouseDown


Event are properties:
Components use properties to implement their events.Unlike most other properties,
event don't use method to implement their read and write parts.
Instead,event properties use a private object field of the same type as the property.
Ex:
type
TNotifyEvent = procedure (Sender: TObject) ofobject;
TControl = class(TComponent)
private
FOnClick : TNotifyEvent; //declare a field to hold the method pointer
protected
property OnClick: TNotifyEvent read FOnClick write FOnClick;
end;

The main advantage to having events be properties,however is that component users can
assign handlers to events at design time,using the Object Inspector.
All your events and their associated event handlers must be procedures.



Triggering the event:(¥Øªº: ±N TWMMouse -> TMouseEvent)
a mouse-down event occurs when the user presses the left button on the mouse
and windows sends a WM_LBUTTONDOWN message to the application.
Upon receiving that message,a component calls its MouseDown method,which in turn calls
any code the user has attached to the OnMouseDown event.

conventional Trigger flow:
WM_LButtonDown -> DoMouseDown -> FOnMousedown(MouseDown) -> OnMouseDown
DoMOuseDown is a private implementation method that provides generic handling for left,right and
midddle button clicks,translating the parameters of the Windows message into values for the
MouseDown method.
Event names start with "On"

Ex: ³]­p ¤¸¥ó TArrow, ·s¼W Event(Property): OnArrowDblClick
¬[ºc:
·í¤¸¥ó³Q DblClick ®É, Windows OS °e WM_LbuttonClk message µ¹¦¹¤¸¥ó
¤¸¥ó±µ¦¬¸Ó message «á,»Ý§PÂ_ OnDblClick event handle ¬O§_¦³µ{¦¡»Ý³B²z
­Y¦³«h°õ¦æ¸Ó eventHandle

wm_LButtonDblClk -> ArrowDblClick -> FArrowDblClick
property OnArrowDblClick: TNotifyEvent read FArrowDblClick write FArrowDblClick;

¹ê¨Ò:
TNotifyEvent = procedure(Sender: TObject) of object;

TArrow = class(TGraphicControl)
private
FArrowDblClick: TNotifyEvent;
procedure WMLButtonDlbClk (var Msg: TWMLButtonDblClk);message wm_LButtonDblClk;
..
protected
procedure ArrowDblClick; dynamic;
..
published
property OnArrowDblClick: TNotifyEvent read FArrowDblClick write FArrowDblClick;
..
end;


Example : 4_FirstComop.34_ArrowEvent


2.6 ³]­pVCL¤¸¥óªº¹Ï¥Ü
³B²z¨BÆJ:
1. §Q¥Î ImageEditor³]­p¤@ Resource ÀÉ (*.dcr),ÀɦW©M¤¸¥ó Register µ{¦¡¦P¦WºÙ
¥BBitmap¦WºÙ©M class ¦WºÙ¬Û¦P
Contents
|
|- Bitmap
|- TArrow
2. ±N¤¸¥ó­ì©lµ{¦¡(*.pas) ¥[¤J PackageÀÉ(*.dpk)
­«·s Compiler §Y¥i,Delphi IDE ·|¦Û°Ê±N¦PÀɦW¤§ *.dcr ¥[¤J Package
3. Compiler & Install §Y¥i

2.7 Home Work
³]­p TPie ¤¸¥ó
Property:
nPies : integer; // Pie ¤À¦¨´X¤l Pie
radius: integer; // Pie ¤§ª½®|
CirLeft:integer; // Pie ¤§ Left ®y¼Ð
CirTop:integer; // Pie ¤§ Top ®y¼Ð
Labelx:integer; // Label¤§ x ®y¼Ð
Labely:integer; // Label¤§ y ®y¼Ð

¤lPie :
Value: integer;
Color: Tcolor;


¶i¶¥¬ã°Q:
ComponentEditor
¥Øªº:
A ComponentEditor is similar to a property editor,but instead of editor a secific property.
it often edits the component as a whole.
Every Component has a component editor.Most components use the default component editor,but
Some have special component editors.
A component editor can add menu items to the form editor's pop-up menu and can define an action
to take when the user double-clicks a component.
When you double-click the component,the form editor calls the component editor's Edit method.
Ex:
TButton,TTable..
¬[ºc:
Component Delphi
Editor IDE Àô¹Ò (Form Editor)
¢z¢w¢w¢w¢w¢w¢w¢{ ¢z¢w¢w¢w¢w¢w¢{
¡ýMenuitem1 ¡ý function GetVerbCount:Integer; ¡ý ¡ý
¡ýMenuitem2 ¡ý<------------------------------ ¡ý ¡ý
¡ý: ¡ý function GetVerb(Index: Integer): string; ¡ý ¡ý
¡ý ¡ý<------------------------------ ¡ý ¡ý
¡ý: ¡ý procedure ExecuteVerb(Index: Integer); ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý
¢|¢w¢w¢w¢w¢w¢w¢} ¢|¢w¢w¢w¢w¢w¢}

function GetVerbCount: Integer; override; //¦@¦³´X­Ó Menuitem
function GetVerb(Index: Integer): string; override; //¶Ç¦^ Menuitem ªº¦r¦ê
procedure ExecuteVerb(Index: Integer); override; //°õ¦æ Menuitem

Writing a component editor requires five steps:
1.choose a base component-editor class.
2.Decide which methods to override.Usually you need to override GetVerbCount and GetVerb and
ExecureVerb method.
3.Implement your class and its methods.
4.Decide how to register the propertty editor,depending on the property type,the component
type and the property name.
5.Add a call to RegisterComponentEditor to the unit's Register procedure.
Ex:
RegisterComponentEditor(C_MenuAux, C_MenuAuxEditor);

Example : 6_ComponentEditor


Example : 4_FirstComp



PropertyEditor
¥Øªº:
³]­p Object.Property ¦b Object Inspector ªº Property ½s¿è¤è¦¡
The Object INspector provides default editing for all types of properties.
You can,however provide an alternate editor for specific properties by writing
and registering property editors.
¬[ºc:
Object Property Delphi
Inspector Editor IDE Àô¹Ò
¢z¢w¢w¢w¢w¢w¢{ ¢z¢w¢w¢w¢w¢w¢w¢{ ¢z¢w¢w¢w¢w¢w¢{
¡ý ¡ý String ¡ýSetOrdValue ¡ý proc SetValue(value:String) ¡ýActual ¡ý
¡ý ¡ý -----> ¡ý----------> ¡ý--------------------------> ¡ýProperty ¡ý
¡ý ¡ý <----- ¡ý<---------- ¡ý<-------------------------- ¡ýValue ¡ý
¡ý Property ¡ý String ¡ýGetOrdValue ¡ý func GetValue:String ¡ý ¡ý
¡ý ¡ý ¡ý: ¡ý ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý proc Edit; ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý function GetAttributes; ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý ¡ý ¡ý
¡ý ¡ý ¡ý ¡ý ¡ý ¡ý
¢|¢w¢w¢w¢w¢w¢} ¢|¢w¢w¢w¢w¢w¢w¢} ¢|¢w¢w¢w¢w¢w¢}
ObjectInspector ©I¥s GetValue: ¥H«K¨ú±o¸Ó Property ¤§String

ObjectInspector ©I¥s SetValue: ¥H«K¥ÑString ³]©w¸Ó Property ¤§Value
GetAttributed : ¨ú±o¸Ó Property ½s¿è¤§¼Ò¦¡
Edit: °õ¦æ¸Ó Property ½s¿è

Writing a property editor requires five steps:
1.choose a base property-editor class.
2.Decide which methods to override.Usually you need to override GetValue and SetValue method.
if you have a value list,then override GetValues method.
if you have an edit dialog,then override Edit method.
In both cases,you need to define new attributes by overriding GetAttbutes method.
3.Implement your class and its methods.
4.Decide how to register the propertty editor,depending on the property type,the component type
and the property name.
5.Add a call to RegisterPropertyEditor to the unit's Register procedure.

1. Base property-editor types:
TComponentProperty
TIntergerProperty : integer,Word
TStringProperty : string,AnsiString..
TEnumProperty : enumerated,subrange
TColorProperty : ..
..
2.Edit the property as text:
All properties need to provide a string representation of their values for the
Object Inspector to display.
Property-Editor objects provide virtual methods you can override to convert between the text
representation and the actual value.
The property editor's GetValue method retuens a string that represents the
the current value of the property.
The property editor's SetValue method takes a string typed by the user in the
Object Inspector,converts it into the appropriate type,and sets the value of the property.

3.Edit the property as a whole:
You can optionally provide a dialog box in which the user can visually edit a property.
When the user clicks the '...' button next to the property or double-click the value column,
the Object Inspector calls the property editor's Edit method.

4.Specifing Property-editor attribuets:
Property-editor attribute flag:
paValueList
paDialog
paMultiSelect
..
5.Registering the property editor
Once you create a property editor,you need to register it with Delphi
To Register a property editor,call the RegisterPropertyEditor procedure.
RegisterPropertyEditor takes four parameters:
.A type-information pointer for the type of property to edit typeinto(TMyComponent)
.The type of the component to which this editor applies.
.The name of the component's property to which this editor applies.
.The type of property-editor to use for editing the specified property.
Ex:
RegisterPropertyEditor(Typeinfo(TComponentName),TComponent,'Name',TComponentNameProperty);

Example : 7_PropertyEditor

4. °Ñ¦Ò®Ñ¥Ø
4.1 Mastering Delphi 2 -- Sybex - Marco Cantu
4.2 Component Writer's Guide -- Borland
4.3 Secrets of Delphi 2 -- WAITE GROUP PRESS -- RAY LISCHNER

³Æµù:
Q:¦p¦ó¨ú±o¦CÁ|«¬ºAªº¤å¦r
Ans:
GetEnumName(typeinfo(TDataSetState),ord(qy.State));

Comments
on Mar 04, 2005
Say that 1 more time.
on Mar 04, 2005
That's why I let other people create stuff... I only understood the password part.