Sunncity.com - Developer & I.T. Zone

 
Sunncity Web

Technology Menu

Developer Center
Delphi Online Tutorial
JAVA Online Tutorial
The Code Project
XML Code Library
FREE Download
Our Free Components
Our Free Software
Free Components
Delphi & Kylix Training
SMTC Training Course
About Delphi EXAM

Search Component


Search Software(s)


by oneNetwork

 

Tutorial - TActBTn (visual)

Writing your first component (part 3)
WRITING PROGRAM VISUAL STYLE

1 * Purpose of having button type ActBtn(4/78).
2 * ControlStyle and indication Component behaviour(4/79).
3 * Adding shadow to your component button with TShape(4/80).
4 * Creating 2 Instance to save TBitmap.(4/82)
5 * Constructor and Destructor Method(4/82)
6 * SetActivePic and SetInActivePic(4/83).
7 * WM_XXXX message (intercept window message)(4/84)
8 * Resize your component TActiveBtn(4/85)
9 * Method of ChangePlace (In ComponentState) Move (4/86)
10 * CM_XXXX message which effected our component directly (4/86-87)
11 * Adding Event (4/87)
12 * Important method for TActiveBtn(4/89)
13 * Parent Control and SetParent(4/89-90)
14 * Loaded Method and ReDeclare(4/91)

 

1 * Purpose of having button type ActBtn(4/78)
TActBtn can be managing by using Component Wizard to do the similar thing as we did for NewComp. We need original control or control which different from other people, so we create component from TCustomControl and name it "Active" because it's similar to Active-X

The good side of TCustomControl is that we could have Canvas Property.
TActBtn is a descendant of TCustomControl.


Type
.......TActiveBtn = class(TCustomControl)
End;


Contstructor TActiveBtn.Create(AOwner:TComponent);
....Begin
.......inherited Create(AOwner);
.......ControlStyle :=ControlStyle + [CsOpaque];
.......Width :=50;
.......Height :=50;
End;

Back to TOP

2 * ControlStyle and indication of Component behaviour(4/79)
ControlStyle is an Enumerate Type and this ControlStyle is a SET OF ENUMERATE.

Sample of Enumerate set of Virus

TVirusName = (Azusa, DieHard, Israel, Mahock, Stelth, ADCD);
TVirus = Set of TVirusName;

Var Virus:TVirus;

Begin
.......Virus := Virus + [Asuza, Diehard, ACDC];
End;

Back to our ControlStyle again (off from virus sample enumerate)

ControlStyle := ControlStyle + [CsAcceptsControls];

Above code enable other Controls to cling to control that we had just created. (except that our Control is a descendent from control which already enable this feature).

See below CODE and below ControlStyle behavior

ControlStyle := ControlStyle + [CsAcceptsControls , CsOpaque];


ControlStyle

Component behavior which effect from it's value

csAcceptsControls

Enable control to be cling to (to be parent)

csCaptureMouse

Follow any mouse move action caused by users

csDesignInteractive

Enable mouse RIGHT CLICK when designing

csClickEvents

Take care of Control Mouse click event

csFramed

Control which has border 3D

csSetCaption

Translate or interpret caption to match (when put on form)

csOpaque

Fast draw becuase you don't have to delete background

csDoubleClicks

Control handle mouse DOUBLE CLICK

csFixedWidth

Control with fixed or certain width which can't change

csFixedHeight

Cotrol with fixed or ceratin height which can't change

csNoDesignVisible

Drop on form and Invisible (why do we need this, don't know?)

csReplicatable

Repeat draw itself on other control (which allow draw)

csDisplayDragImage

When control moves or drag, change Mouse Cursor and send signal to user automatically with WM_MOVE

csReflector

Enable this control to be use with Active-X (case Active-X)

csNoStdEvetnts

Let control ignore all Mouse events to speed up program cycle


Back to TOP

3 * Adding shadow to your component button with TShape(4/80).
You can create Component bitmap with shadow by using TShape. TShape is a TGraphicControl. The best way to do this is when you are doing Create Constructor.

Sample

Constructor TActiveBtn.Create(AOwner:TComponent);
....Begin
......inherited Create(Aowner);
......ControlStyle :=ControlStyle + [CsOpaque];
......FShape := TShape.Create(Self);
......FShape.Brush.Color := ClBlack;
......FShape.Visible := False;
......Width := 50;
......Height :=50;
......FShape.Width := 50;
......FShape.Height := 50;
End;

FShape is a Component not Class, so we need to indicate Owner and in this case is "self". You can create by simply using .Create

You need to also create Instance name FShape (Class descendant from TShape Component)

Type
.......TActiveBtn = class(TCustomControl)
.......private
..........FShape : TShape;

Since TShape is declared in UNIT name ExtCtrls.pas so we need to refer ExtCtrls under Uses.

unit ActBtn ;
interface
.......use
..........Windows, Messages..........

Back to TOP

4 * Creating 2 Instance to save TBitmap.(4/82)
Your Component Now have 2 bitmap (1 normal and 1 with shadow). In order to save this 2 picture, you need to create 2 Instance at Class TActBtn.

In Private Section adding this code.

Type
.......TActiveBtn = class(TCustomControl)
.......private
.........FShape : TShape;
.........FActivePic : TBitMap;
.........FInActivePic : TBitMap;
End;

Back to TOP

5 * Constructor and Destructor Method(4/82)
We mentioned this many times that Instance before calling for use we need to manage Constructor method. The Best way to do this is when you are creating your Component.

Constructor TActiveBtn.Create(AOwner:TComponent);
....Begin
......inherited Create(Aowner);
......FActivePic := TBitmap.Create;
......FInActivePic := TBitmap.Create;
......ControlStyle :=ControlStyle + [CsOpaque];
......FShape := TShape.Create(Self);
......FShape.Brush.Color := ClBlack;
......FShape.Visible := Flase;
......Width := 50;
......Height :=50;
......FSahpe.Width := 50;
......FShape.Height := 50;
End;

Create Constructor follow by Destructor Method. Notice that we destroy Object before we destroy our Component always, or we destroy every thing before Inherited Destroy. Or else you could face Error GFP (general fault protection).

Destructor TActiveBtn.Destroy;
....Begin
.......FActivePic.Free;
.......FInActivePic.Free;
.......inherited Destroy;
End;

Back to TOP

6 * SetActivePic and SetInActivePic(4/83).

We need to handle FActivePic and FInactivePic with 2 methods which are "SetActivePic" and "SetInActivePic". (normally we put in private section).

SetActivePic indicates Bitmap when MouseMoveIn, and SetInActivePic indicates Bitmap when MouseMoveOut.

Type
...TActiveBtn = class(TCustomControl)
...Private
...................
...................
........FActivePic : TBitMap;
........FInActivePic : TBitmap;
........Procedure SetInActivePic (Value:TBitmap);
........Procedure SetActivePic (Value:TBitmap);
....Published
........Property PictureWhenActive:TBitmap Read FActivePic Write SetActivePic;
........Property PictureWhenInActive:TBitmap Read FInActivePic Write SetInActivePic;
End;

then follow by below code.

Procedure TActiveBtn.SetActivePic (Value:TBitmap);
...Begin
........FActivePic.Assign(Value); <assign can't use equal sign = becuase = use for instance only>
........Width := FActivePic.Width;
........Height := FActivePic.Height;
........Invalidate; <Draw itself and act on screen when design immediately>
End;

Procedure
TActiveBtn.SetInActivePic (Value:TBitmap);
...Begin
........FInActivePic.Assign(Value);
........Width := FInActivePic.Width;
........Height := FInActivePic.Height;
........Invalidate;
End;

* You can add more effects as above code such as FShadowColor, FShadowRight, FState and so on.

Back to TOP

7 * WM_XXXX message (intercept window message)(4/84)
Delphi has Encapsulated Windows API intercept window message. These value is an Constant starting with WM_XXXXX. All these message value in HEXA. These message is use with only windows control (TWinControl and TCustomControl). It can be use partially if it is TGraphicControl.

Example if you move your component button TActBtn, it will intercept message WM_MOVE but if it is being enlarge or reduce in size , it's intercept message WM_RESIZE. Delphi make this easy by allow adding in Method anywhere in Class (Recommended put this in Protected Section for future call for use).

Procedure WMResize(Var Msg:TMessage); Message WM_size;

Back to TOP

8 * Resize your component TActiveBtn(4/85)
Plan ahead what happen if TActBtn or your Component is stretch or resize. Base on our sample of 2 bitmap 1 normal and 1 with shadow, then we have to consider when it's stretch or resize, what will happen to Bitmap shadow?

Procedure TActiveBtn.WMResize (Var Msg:TMessage);
....Begin
.......inherited;
.......FShape.Width := Width;
.......FShape.Height := Height;
.......FShape.Top := Top + FShadowBottom;
.......FShape.Left := Left + FShadowRight;
End;

Above code should do the job handling shadow when it's stretch or resize.

Back to TOP

9 * Method of ChangePlace (In ComponentState) Move (4/86)
You should also intercept window message of ChangePlace or Move WM_MOVE as well. Base on our sample shadow should move as well. In Method of ChangePlace we intercept while designing (CsDesigning) which is in ComponentState.

Procedure TActiveBtn.ChangePlace (Var Msg:TWMMove);
....Begin
....if CsDesigning in ComponentState then
....Begin
.......inherited
.......{
.......Left := Msg.Pos.x;
.......Top:= Msg.Pos.y;
........}
.......FShape.Top := (Msg.Pos.Y-1) + FShadowBottom;
.......FShape.Left := (Msg.Pos.X-1) + FShadowRight;
.......End;
End;

Back to TOP

10 * CM_XXXX message which effected our component directly (4/86-87)
CM_XXXX is message direct to your Component such as CMMouseEnter, CMMouseLeave, WMDoubleClick, WMButtonDown, WWButtonUp.

Procedure CMMouseEnter (Var Msg:TMessage); Message CM_MouseEnter;

If mouse move to control, then there is a CM_MouseEnter then check if it's was assigned. If assigned then draw using command Canvas.Draw
Remember TCustomConrol have "Canvas" so we can draw using Method to draw. Draw indicates where you want to draw starting at 0, 0 (top left of our component).
It would be best to have both CMMouseEnter and CMMOuseLeave.

Procedure TActiveBtn.CMMouseEnter (Var Msg:TMessage);
....Begin
....if Assigned(FActivePic) then Canvas.Draw (0 ,0 , FActivePic);
....End;

Procedure TActiveBtn.CMMouseLeave (Var Msg:TMessage);
....Begin
....if Assigned(FInActivePic) then Canvas.Draw (0, 0, FInActivePic);
....End;

Back to TOP

11 * Adding Event (4/87)
Now we are going to adding 2 events. One event for real pressing on button, and one event to sink the button (illusion) without actually pressing the button. We are going to call it using METHOD style "PROCEDURAL POINTER".

Event is property, so writing is the same but in PUBLISHED section, so that it shows in Object Inspector.


Type
.......TState = (ActDown, ActUp);
.......TMouseOrKey = (ByMouse, By Key);


.......TOnDownEvent = Procedure (Activate : TMouseOrKey) of Object;
.......TOnDrawDownEvent = Procedure (Sender : TObject) of Object;

Event handler here is when a mouse is CLICK on control.

Procedure TActiveBtn.WMLButtonDown (Var Msg:TMessage);
....Begin
....inherited;

....If FState <> ActDown then
........Begin
...........OrgTop := Top;
...........OrgLeft := Left;
...........Top := FShape.Top;
...........Left := FShape.Left;
...........If Assigned (FOnDownEvent) then
...............Begin
...................FOnDownEvent (ByMove);
...................End;
...........FState := ActDown;
...........End;
...........if FStayDown = Flase then WMLButtonUp (Msg);
....End;

Back to TOP

12 * Important method for TActiveBtn(4/89)
Everyone likes the sensation (illusion effects) of interactive Button. Important method that does the DRAW for general control is Method name PAINT that is always Virtual or Dynamic in descendant.

If you wish to change the look of your component, then you have to draw by using command draw name TCanvas by using Override Method name Paint. The easiest way is to draw and save in file Resource.

In this sample, we will see method command Canvas (Important for our Component).

Procedure Paint ; Override ;
Override need inherited always, remember?, see below

Procedure TActiveBtn.Paint;
....Begin
.......inherited Paint;
.......If Assigned (FInActivePic) then Canvas.Draw (0, 0, FInactivePic);
End;

Back to TOP

13 * Parent Control and SetParent(4/89-90)
Parent Control - When you drop 1st Control on top of another Control and unable it to move out from the first control means the first Control is a Container or Parent Control of other Control.

 

Form1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Parent Is Form

 

Parent Is Form

 

 

 

 

 

 

 

 

 

Parent is Panel

 

 

 

 

 

 

 

 

 

 

 


FShape.Parent := Form1;

SetParent Control - In Delphi Method Name SetParentControl indicate that our current Component (Here is TActiveBtn) will cling to which control (which parent).
Base on our sample Shadow of component will follow parent too (keep illusion).

Procedure TActiveBtn.SetParent (Value:TWinControl);
....Begin
.......If Not (CsDestroying in ComponentState) and (FShape <> Nil) then
...........Begin
...............FShape.Parent := Value;
...........End;
.......Inherited SetParent (Value);
End;

Back to TOP

14 * Loaded Method and ReDeclare(4/91)
Loaded Method - Before Form can be in use (millisecond before Form show), it will need to pass through Method name Loaded. This is the time that Form will load at the same time with our component.

Procedure TActiveBtn.Loaded;
....Begin
.......inherited Loaded;
.......If FInActivePic <> Nil then Canvas.Draw (0, 0, FInActivePic);
.......If FPushShadow then
..........FShape.Visible := True
......else
..........FShape.Visible := False;
......OrgTop := Top;
......OrgLeft := Left;
......FState := ActUp;
End;

Redeclare - We could write other property which already there to be use in Published Section. Properties we are talking here are such as ShowHint, Left, Top, and etc.

Event such as ONMouseDown, and OnMouseUp are already existed as well. All these to be REDECLARE , so that they all will appear in OBJECT INSPECTOR.

If you like to write (create) a component, you might add new method to your component. Now you know the STEP of how to Create your Component, but you as a programmer need to do your own DANCE.

Back to TOP

 


Support this site BUY from Sunncity Gift Store