Deeply preparing your own components in C ++ Builder - in-depth analysis of VCL inheritance, message mechanism (2)

zhaozj2021-02-16  48

This article mentioned that the content may have been seen in many places, the author is also the same, but also read a lot of VCL source code, plus the experience of the actual writing of components, and patching such an article. Therefore, all remarks is a personal point of view, and experience is described only for reference only.

You can reprint, copy, but you must join the author's signature Aweay. If you are used for commercial purposes, you must agree.

Dynamic function

In the last article, we talked about how to draw components, but the light-drawing element is still not enough, and the component is not light to be like, but also able to handle, the corresponding user input, this requires us to handle the keyboard mouse event.

Processing the keyboard mouse event is like the same as we handle system messages, such as WM_KeyDown, etc., so you can also override WndProc or write message mapping macros as in Form, all of which can be used in components. But we don't have to do this. VCL has already raised many interface functions, and we only need to overload the corresponding virtual function to complete the processing of the corresponding events.

If you have to handle the mouse event, then you need to rewrite the following function:

MouseDown

Mouseup

Mousemove

Click

If you need to handle the keyboard, you need to handle the following function:

KeyPress

KeyDown

Keyup

For keyboard virtual functions, you need to pay attention to derived classes must inherit from TCUStomeControl (directly or indirect, accurate, not necessarily) to use the above virtual functions.

The above functions look similar to our function when designing Form, but they have a clear difference, if you overload them, if you look at the VCL source code, it only writes an Overide keyword to log function. Attribute, but in C , it will not work. Why?

Let's take a look at the source code in the VCL:

Procedure KeyDown (Var Key: Word; Shift: tshiftstate); Dynamic;

Procedure Keyup (Var Key: Word; Shift: tshiftstate); Dynamic;

PROCEDURE KEYPRESS (VAR KEY: CHAR); DYNAMIC

Basically all of these virtual (dynamic) functions are this stated, can be in C without Dynamic this keyword? In order to explain this problem, let's first understand what Dynamic function:

In Delphi, the functions have both Virtual and Dynamic. For Virtual and our Virtual in our C , Dynamic is different. Dynamic only maintains a virtual method table, when a base class has multiple polymorphisms The function, and this base class may be inherited multiple times, using Dynamic declaration can reduce the length of code, but Dynamic and Virtual behavior are almost, Virtual is fast than Dynamic, Dynamic is more than Virtual The code length is small.

If you want to study this problem in depth, you can refer to the following article:

http://www.9cbs.net/develop/read_article.asp?id=14729

Or go to Borland's newsgroup questions, you will be able to get a satisfactory answer.

We know that there is no Dynamic keyword in standard C , so for C Builder can use the VCL class, Borland has expanded, we can use Dynamic macro to implement dynamic functions, so if we want to rewrite in your derived class These messages handlers, we need this: Dynamic void __fastcall mousemove (Classes :: TshiftState Shift, Int X, int y);

Now we can draw components, can handle components, basically we can write some simple components. Before you continue the following content, as the end of this article, we actually write a simple component. Here we assume that you already have the experience of writing components. If you don't understand the corresponding code, there is no relationship, I will discuss in detail behind the article.

When I first helped users' source code of a simple vector drawing board, which implemented vector lines on the component, including selection and re-adjustment:

(h header file)

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

#ifndef veccanvash

#define veccanvash

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

#include

#include

#include

#include "shape.h"

Typedef void __fastcall (__closure * troveeeevent) (INDEX);

Typedef void __fastcall (__closure * tshapeselected) (Tobject * Sender, int index);

Enum tooltype {TTSELECT, TTLINE, TTRECT};

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

Class Package TVECCANVAS: Public TCUSTOMCONTROL

{

Private:

TList * shapelist;

Cshape * currentshape;

Bool down;

TPOINT Lastpos;

TPOINT NewPOS;

THOVERSHAPEEVENT FONHOVERSHAPE;

ToolType FTOOL;

TshapeselectedEvent Fonshapeselected;

Dynamic void __fastcall mousedown (TMousebutton Button, Classes :: TshiftState Shift, Int x, int y);

Dynamic void __fastcall mouseup (TMousebutton Button, Classes :: TshiftState Shift, Int X, Int Y);

Dynamic void __fastcall mousemove (Classes :: TshiftState Shift, INT X, INT Y);

Void __fastcall dohovershape (int INDEX);

Void __fastcall settool; / ToolType Value;

Void __fastcall doshapeselected (int index); protected:

Void __fastcall paint ();

PUBLIC:

__fastcall tVeccanvas (tComponent * Owner);

__fastcall ~ tVecccanvas ();

INT __FASTCALL ShapeAtPos (INT X, INT Y);

__publish:

__property color;

__property onclick;

__Property THOVERSHAPEEVENT OnHOVERSHAPE = {Read = Fonhovershape, Write = Fonhovershape};

__property align;

__property onmousemove;

__property onmousedown;

__property onmouseup;

__property toolType Tool = {read = fTool, Write = settool};

__property tshapeselected = {read = fonshapeselected, write = fonshapeselected}

}

For the top file above, the master will definitely understand, if the beginner is more difficult, or simply can't understand, you may go see some other articles about the entry of design components, of course, I am still briefly Do explain:

Maybe many people will ask questions why do you have an onclick event? How do you know that the mouse click? The answer is to inherit the statement and implementation of the parent class. I just be responsible for expressing it so that the components can be used. Here is the topic of our first article, if you want to design a TButtonEx component, you can inherit from TButton, or inherit from TCUSTombutton, if you inherit from TButton, then all properties and methods do not need to be re-re- Declaring, TButton has, TButtonex, but TBUTTONEX really needs all TButton properties and events? Of course, we only need to export you interested or user interest in properties and events.

There is also __property keyword, here I don't plan to introduce it in detail, I think you should go see help or something else. There are other things in the header file, we will discuss in detail below, now let's take a look at the CPP file.

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

#ENDIF

(CPP file)

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

#include

#pragma HDRSTOP

#include "veccanvas.h"

#pragma package (smart_init)

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

// ValidcTrcheck IS Used To Assure That The Components Created Do Not Have

// any pure virtual functions.//

Static Inline Void ValidcTrcheck (TVECcanvas *)

{

New TVECCANVAS (NULL); // guarantees that there is no pure virtual function in the element, otherwise it cannot generate components

}

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

__fastcall tVeccanvas :: tVeccanvas (tcomponent * oowner)

: TCustomControl (Owner)

{

Shapelist = new TLIST ();

Currentshape = NULL;

Down = false;

FTOOL = TTLINE;

}

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

Namespace Veccanvas

{

Void __fastcall package register () / Pack registration function

{

Tcomponentclass classes [1] = {__classid (tVeccanvas)}

RegisterComponents ("Draw Suite", Classes, 0);

}

}

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

__fastcall tveccanvas :: ~ tVeccanvas ()

{

// Todo: Add your source code here

Delete shapelist;

}

Void __fastcall tveccanvas :: mousedown (TMOUSEBUTTON Button,

Classes :: TshiftState Shift, Int X, Int Y)

{

// Todo: Add your source code here

IF (Button! = Mbleft)

Return;

Switch (ftool)

{

Case TTLINE:

Lastpos.x = x;

LastPos.y = Y;

Newpos.x = x;

Newpos.y = y;

Down = True;

Case TTSELECT:

{

INT SH = ShapeAtPos (X, Y);

IF (sh! = - 1)

Doshapeselected (SH);

Break;

}

}

}

Void __fastcall tVeccanvas :: mouseup (TMOUSEBUTTON Button,

Classes :: TshiftState Shift, Int X, Int Y)

{

// Todo: Add your source code here

Down = false;

IF (Button == Mbleft)

{

Switch (ftool)

{

Case TTLINE:

Cshape * sh = new cline ();

SH-> Start = LastPos;

SH-> end = TPOINT (X, Y);

SH-> Type = stline;

Shapelist-> Add (sh);

Canvas-> Moveto (lastpos.x, lastpos.y);

Canvas-> LineTo (X, Y);

Break;

}

}

}

Void __fastcall tveccanvas :: mousemove (Classes :: TshiftState Shift,

INT x, int y) {

// Todo: Add your source code here

IF (! down)

{

INT SH = ShapeAtPos (X, Y);

IF (sh! = - 1)

Dohovershape (SH);

Return;

}

Switch (ftool)

{

Case TTLINE:

Canvas-> Pen-> Mode = PMNotXor;

Canvas-> Moveto (lastpos.x, lastpos.y);

Canvas-> Lineto (NewPos.x, NewPos.y);

Newpos = TPOINT (X, Y);

Canvas-> Moveto (lastpos.x, lastpos.y);

Canvas-> Lineto (NewPos.x, NewPos.y);

Canvas-> Pen-> Mode = pmcopy;

Break;

}

}

Void __fastcall tVeccanvas :: Paint () // Simple overloaded Paint Function

{

// Todo: Add your source code here

// canvas-> brush-> color = color;

// canvas-> FillRect (this-> clientRect);

For (int N = 0; n count; n )

{

Cshape * sh = (cshape *) shapelist-> items [n];

SH-> Draw (Canvas);

}

}

Void __fastcall tveccanvas :: dohovershape (int index)

{

// Handle custom events

IF (Fonhovershape)

{

FONHOVERSHAPE (this, INDEX);

}

}

INT __FASTCALL TVECCANVAS :: ShapeAtPos (int X, int y)

{

// Todo: Add your source code here

For (int N = 0; n count; n )

{

Cshape * sh = (cshape *) shapelist-> items [n];

IF (SH-> ISPARTOF (TPOINT (X, Y)))

Return n;

}

Return -1;

}

Void __fastcall tveccanvas :: settool (tooltype value)

{

// Todo: Add your source code here

IF (fTool! = value)

{

FTOOL = VALUE;

}

}

Void __fastcall tVeccanvas :: DOSHAPESELECTED (int index)

{

// Todo: Add your source code here

IF (FONSHAPESELECTED)

{

Fonshapeselected (this, INDEX);

}

}

The above code basically uses the above message processing knowledge and drawing knowledge, so it is easy to understand, pay attention to here:

Typedef void __fastcall (__closure * troveeeevent) (INDEX);

Typedef void __fastcall (__closure * tshapeselected) (Tobject * Sender, int index);

Is my own defined message processing, this is also the problem that we will discuss below - the processing of custom messages and cm_xxxx messages

转载请注明原文地址:https://www.9cbs.com/read-25671.html

New Post(0)