Visual Component is actually a class. To write a class, you can write it directly in the *.pas file. But to write controls, you must use packages. Select New from the File menu to create a new Package. This is the package used to store and install the control. Then click the Add button in the Package window to add a component (Unit).
Select New Component at the top of the pop-up dialog box. Because it is impossible to program all the properties, methods, and events of a control by yourself, you need to select the ancestor class (or "parent class" or "base class"), and then add your own properties, methods, and events to it. . Select the required ancestor class in the drop-down box after Ancestor type. Since writing visual controls requires drawing, TGraphicControl is selected as the ancestor class. Then enter the name of the new control (class) in the Class Name box, usually starting with "T". Palette Page is used to select the control page name of the new control in the Delphi window, such as "Standard". You can choose this yourself. Add the path and file name of the new control file in Unit File Name and click the OK button. New controls are added. Now it's time to write code for the control.
The following takes writing a scroll bar that can customize pictures as an example to illustrate the method of writing visual controls.
Follow the above method, select TGraphicControl as the ancestor class, and the name of the new control is TPigHorizontalScroller. After selecting the file path and file name, click the OK button to start writing code.
Each control will be created (Create) and deleted (Destroy), so these two processes must be written first. For every procedure in the control, it must be defined first and then written later. There are three types of defined processes or properties: 1. Those defined after PRivate are used internally by the control and cannot be seen by people who use the control; 2. Those defined after protected are generally invisible and can only be used by others when others use the control. The control is only visible when writing other controls as an ancestor class; 3. Those defined after public can only be called by others in the program; 4. Those defined after published can be seen in the property window (Object Inspector). Since the creation and deletion process is not only executed automatically when the control is created during the programming process, but may also be called when the control is dynamically created during the running of the program, it is defined after public (1). (The serial number indicates the position of the code of the sub-step in the attached source program, the same below) Maybe you still don’t know what should be compiled in these two processes and how to compile it. We will talk about it below.
Let's first add some properties to this control. We define a Max property to set or read the maximum value of the scroll bar. Because attributes are generally not used directly in programs, a variable must be defined to correspond to the attribute and its value can be modified or read. Because it is only used inside the control, we define it after private (2). (Generally, variables associated with attributes start with "F", such as FMax) After defining the variables, define the attributes. This property needs to be visible in the Object Inspector window, so define it and publish it (3). The defined syntax is:
property <property name>:<type> read <corresponding variable when reading this property> write <corresponding variable or procedure when writing this property>
Other variables and attributes are also defined similarly (such as Min minimum value, Value current value, etc.). Next we define several properties and variables for setting the scroll bar picture (because the picture variable is special, we will talk about it separately). We define LeftButtonUpPicture (left button picture), LeftButtonDownPicture (left button press picture), etc. as TBitmap types (corresponding variables must be defined).
You must have noticed that in the attached source program, when defining these attributes, the variable corresponding to the attribute read after read is F..., but the variable corresponding to the attribute specified after write is not a Variable, but something like Set... This is a customized process. The process as a function is defined as:
procedure <procedure name>(Value: <type of value of the attribute being set>)
Because other things need to be done when writing this type of attribute, you cannot just use a variable to handle it, you should use a process to handle it. This process is generally defined after protected. In this type of procedure, a statement such as ⑷ is used to assign a value to a variable of the TBitmap type. This is adopted because variables of this type cannot be directly assigned a value.
After defining the properties of these TBitmap type variables, you need to write code in the create process and destroy process mentioned above. Because TBitmap is also a class, it must be created during the create process (5) and must be released (free) during the destroy process (6). The inherited statement referred to in ⑺ here is used to indicate that the process is inherited from the ancestor class. (This must not be dropped).
Because we are writing a visual control, we must draw pictures on the control. The ancestor class of our control, TGraphicControl, encapsulates a Canvas (canvas) object, and we can use it directly to draw pictures. If you're not familiar with using canvas yet, it's a good idea to find a book and read it.
The next thing to do is to draw the picture. How to draw pictures on the control? There is a Paint event in the ancestor class TGraphicControl, which is automatically triggered when the control needs to be redrawn. What we have to do now is to write a program for this event. First define a Canvas object after protected. Since it already exists in the ancestor class, there is no need to add any explanation⑻. We will use this object to draw the image. Next, you need to define a Paint process and write the code to draw the control. Define the Paint process first after public. Since it is triggered by the ancestor class instead of being called by the user, override must be added afterwards. Otherwise, the control will not become a visual control because the Paint process will never be called. Next we will write the code for the Paint process⑽.
The T_Height and other variables in the Paint process of the source program attached to this article are used to save the size of buttons, sliders, etc. in the scroll bar. This part of the program is not much different from the program in ordinary applications. Most of them are for Operate on the canvas, I believe everyone will understand it at a glance. It is worth noting the following judgment of the FAutoSize variable. FAutoSize is a Boolean variable associated with the attribute AutoSize of the control. It is used to set whether the size of the control changes with the size of the picture. Note that in the code of the control, properties are generally not called directly, but the corresponding variables are used.
At this point in the program, you have finally made an appearance for your new control, but it cannot scroll yet. Now let's write mouse events that will allow us to manipulate it. The definition of the mouse event process is very similar to the Paint process, except that parameter descriptions must be added at the end. Mouse events are divided into three types: MouseDown, MouseMove and MouseUp. Override must be added after the definition. Next write its code behind. Note: The mouse event here is Mouse..., not the usual OnMouse.... But what is the definition at ⒀ used for? The event definitions here are all for users, that is to say, when the control is used, it will be displayed on the Event page in the Object Inspector.
The code for these mouse events is also very simple. It determines the coordinates of the mouse, draws the corresponding picture on the canvas, etc., and triggers the corresponding event at the same time. It is worth noting that when calling a custom event, you must first use a statement such as ⒁ to determine whether the user has written code for the event. This is very important, otherwise an error will occur.
Everyone has noticed that the events just called are all customized, and the defined method is also very simple. It is similar to defining properties, except that the type is TNotifyEvent.
TNotifyEvent is the default event, which is defined as:
TNotifyEvent = procedure(Sender: TObject)
If you want to define another form of event, you must do this: write it first and then type
<event type name> = procedure(<parameter>:<type>)
For example:
TCustomEvent = procedure(a: Integer; b:String);
Then define it after public:
<event name>:<event type name>
For example:
AnEvent: TCustomEvent;
After reading this, you should understand the entire procedure. If compilation or running errors occur, please check the following points:
1. Are there inherited statements in the create and destroy processes?
2. Have the variables of type TBitmap been created and freed?
3. Is there a control name before the process, for example: TPigHorizontalScroller.MoseMove
How to determine whether the mouse enters or leaves the control:
Define the following process:
procedure MouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
procedure MouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;