Implementation of a magnetic form VCL Component

Source: Internet
Author: User

Implementation of a magnetic form VCL Component
Subtitle:
Author: famous author Source: monopoly hits: 52 updated on:
 
 
Text: Chen dajun
Date: 2003-10-29

I remember an article in programmer magazine that introduced how to implement a magnetic form. This article summarizes related online discussions and analyzes the basic principles of implementing a magnetic form, finally, a feasible solution is provided. However, the main form with magnetic adsorption capability described in this article can only be the main form of the application, without flexibility, and the sample code given in this article is implemented by C ++ bulider. Now we will try to implement this function in the form of a VCL component in Delphi, and strive to make some extensions in the function. For any omissions in this article, please advise.

Analysis
Before the discussion, we should first define two terms. The main form referred to here refers to a form with magnetic adsorption, and a subform refers to a form that is adsorbed by the primary form and can be pasted with the primary form, and the subforms do not have adsorption between them. For example, a magnet can suck one or more iron blocks, but the two iron blocks do not have magnetic properties (if the iron blocks are magnetized, it is another question ). Next we will analyze the general process of implementing a magnetic form.

1. Process of pasting sub-forms to the main form

What messages will a user receive when moving a form? Let's take a look at the description on msdn:
 
The wm_moving message is sent to a window that the user is moving. By processing this message, an application can monitor the position of the drag rectangle and, if needed, change its position.

In the original form movement process, wm_moving standard system messages will be continuously generated !!! The lparam parameter of the message is a pointer to the trect structure, and the trect structure stores information about the rectangular area of the current position of the window. It is not difficult to infer that we need to intercept the wm_moving message of the window. There are many methods to intercept the window message in Delphi. Here we replace the original window function, use a custom message processing function to intercept the message.

Let's take a look at the description of the wm_move message on msdn:

The wm_move message is sent after a window has been moved.

It seems that the wm_move message should also be in our bag and used to adjust the final position of the relevant window.

In the custom message processing function, we constantly detect the distance between the subform and the main window. If it is smaller than a set value, paste the subform to the main form. But how do I know the main form? Only when the main form is obtained can we compare the two locations and determine whether the stator form can be adsorbed to the main form. The preceding article uses the application-> mainform method, which limits that the main form can only be the main form of the application. We adopt the following method: define a global variable to save the tmagnetserver object associated with the main form, and assign a value to the global variable when creating the first tmagnetserver object, of course, each application can only have one tmagnetserver object.

Ii. process of removing the child form from the main form

The process of removing a child form from the main form is very similar to the above pasting process. The two can be processed together in specific implementation. In the custom message processing function, the distance between the subform and the main window is constantly detected. If the distance is greater than a set value, the subform is disconnected from the main form.

3. The process of moving the main window with subforms

When the main window is associated with a subform, that is, all the subforms pasted into the main form are moved along with the movement of the main form, and the relative position remains unchanged. Similarly, the main form receives the wm_moving message during the moving process. We can intercept the message and change the positions of all its associated subforms one by one.

Design
As a tool for rad (Rapid Application Development), Delphi is favored by many programmers. A wide range of VCL libraries are indispensable. From the above analysis, we can see that we have defined three classes for specific implementation to meet the rapid development needs of componentized applications.

The tmagnetform class is the base class of the tmagnetserver and tmagnetclient classes. It mainly implements the function of replacing the original window function and intercepting specific window messages. This class is inherited from the tcomponent class because the magnetic form component is invisible during running. Note: The domoving and domove functions of the tmagnetform class are defined as virtual and Abstract Functions to take full advantage of the advantages of virtual functions, implement Dynamic calling of different functions at runtime based on different inheritance classes. Table 1 describes the tmagnetform class.

Class Name Description
Oldwindowproc twndmethod Default Message Processing Function
Domoving procedure virtual abstract wm_moving Message Processing Function
Domove procedure virtual abstract wm_move Message Processing Function
Table 1

The tmagnetserver class provides the functions of the magnetic main form. The tlist class in Delphi provides a good container class for storing the sub-form list. When a child form is pasted to the main form, the tmagnetclient object of the child form is added to the linked list. Otherwise, the object is removed from the linked list. In the process of moving the main form, call the adjustformpos function to adjust the position of the subform one by one. In addition, you can use the magnetstyles set type attribute to control the pasting style of the main form. Table 2 describes the tmagnetserver class.

Class Name Description
Factive Boolean determines whether the main form can be pasted.
The distance from fdistance integer to produce magnetic gravitation
Fform tscrollingwincontrol associated window
Fmagnetstyles tmangerstyles main form pasting Style
List of child forms associated with fmagnetclientlist tlist
Adjustformpos procedure
Unionotherform procedure specific adjustment process
Domove procedure override
Domoving procedure override
Table 2

The tmagnetclient class is used to encapsulate the functions of magnetic subforms. The fmagnetserver member variable is used to store the tmagnetserver object of the main form associated with the child form. Table 3 describes the tmagnetclient class.

Class Name Description
Fenabled Boolean is used to prevent repeated operations.
Fform tscrollingwincontrol associated window
Main form pasted to fmagnetserver tmagnetserver
Final left position when the fxpos integer sub-form is pasted
Final top position when the fypos integer sub-form is pasted
Attachtoform procedure paste to the main form or remove the process
Domove procedure override
Domoving procedure override
Table 3

Encoding
After the detailed analysis and design above, it is not difficult to implement the magnetic form component. Next we will explain some of the key code. For the specific implementation process, see the example code.

VaR
Mainserver: tmagnetserver; // defines a global variable.

// Define a new form Message Processing Function
Procedure tmagnetform. newwndproc (VAR message: tmessage );
Begin
If message. MSG = wm_moving then
Begin
Domoving (Message );
Message. Result: = 1;
End;
If message. MSG = wm_move then
Begin
Domove (Message );
Message. Result: = 1;
End;
Oldwindowproc (Message );
End;

// Tmagnetform constructor to ensure that each form can have only one tmagnetserver or tmagnetclient component
Constructor tmagnetform. Create (aowner: tcomponent );
VaR
Nindex: integer;
Begin
For nindex: = 0 to tscrollingwincontrol (aowner). componentcount-1 do
Begin
If (uppercase (tscrollingwincontrol (aowner). components [nindex]. classname) = 'tmagnetclient') or
(Uppercase (tscrollingwincontrol (aowner). components [nindex]. classname) = 'tmagnetserver') then
Begin
Alert ('the form already has a tmagnetserver or tmagnetclient component! ');
Exit;
End;
End;

Inherited create (aowner );
End;

The Alert () function is a custom function used to display warning information. Definition:

// Display warning information
Procedure alert (const MSG: string );
Begin
Application. MessageBox (pchar (MSG), pchar (application. Title), mb_iconwarning or mb_ OK );
End;

// Constructor of the tmagnetserver class
Constructor tmagnetserver. Create (aowner: tcomponent );
Begin
// Ensure that the tmagnetserver component of each application is unique
If assigned (mainserver) then
Begin
Alert ('Each application can have only one tmagnetserver component! ');
Exit;
End;
Inherited create (aowner );

// Initialize the member variable
Fmagnetclientlist: = tlist. Create;
Fform: = aowner as tscrollingwincontrol;
Fdistance: = default_distance;
Factive: = true;
Fmagnetstyles: = [mstop, msbottom, msleft, msright];
Mainserver: = self; // assign a value to the mainserver global variable defined above

// Replace the window message processing function
If not (csdesigning in componentstate) then
Begin
Oldwindowproc: = fform. windowproc;
Fform. windowproc: = newwndproc;
End;
End;

// Move other forms that are pasted together
Procedure tmagnetserver. adjustformpos (rect: prect );
VaR
DX, DY: integer;
Nindex: integer;
Magnetclient: tmagnetclient;
Begin
If not assigned (fform) Then exit;
If not factive then exit;

DX: = rect ^. Left-fform. Left;
DY: = rect ^. Top-fform. Top;
Fform. Left: = rect ^. Left;
Fform. Top: = rect ^. Top;

// Adjust the positions of all subforms associated with the main form one by one
For nindex: = 0 to fmagnetclientlist. Count-1 do
Begin
Magnetclient: = fmagnetclientlist [nindex];
Unionotherform (magnetclient, dx, Dy );
End;
End;

// Adjust the position of the subform
Procedure tmagnetserver. unionotherform (magnetclient: tmagnetclient; dx, DY: integer );
VaR
FX, FY: integer;
Formtemp: tscrollingwincontrol;
Begin
If not assigned (magnetclient) Then exit;
Formtemp: = magnetclient. fform;
If (magnetclient. fenabled) then
Begin
Magnetclient. fenabled: = false;
FX: = formtemp. Left;
FY: = formtemp. Top;

Setwindowpos (formtemp. Handle, fform. handle,
FX + dx, FY + dy,
Formtemp. Width, formtemp. height,
Swp_nosize or swp_noactivate );
Magnetclient. fenabled: = true;
End;
End;

// Paste the form to the main form or remove it from the main form
Procedure tmagnetclient. attachtoform (magnetserver: tmagnetserver; rect: prect; distance: integer );
VaR
Rectserver: trect;
Ispasted: Boolean;
Begin
If not assigned (fform) Then exit;
If not assigned (mainserver) Then exit ;;
If not assigned (mainserver. fform) Then exit;

Getwindowrect (mainserver. fform. Handle, rectserver );
Fxpos: = rect ^. Left;
Fypos: = rect ^. Top;
Ispasted: = false;

// Upstream/downstream judgment
If (mid (rectserver. Left, rect ^. Left, rectserver. Right) or mid (rect ^. Left, rectserver. Left, rect ^. Right) then
Begin
If (distancein (rect ^. Top, rectserver. Bottom, distance) and (msbottom in mainserver. fmagnetstyles) then
Begin
// Paste the following content
Fypos: = rectserver. bottom;
Ispasted: = true;
End
Else if (distancein (rect ^. Bottom, rectserver. Top, distance) and (mstop in mainserver. fmagnetstyles) then
Begin
// Paste on
Fypos: = rectserver. Top-(rect ^. Bottom-rect ^. Top );
Ispasted: = true;
End;
End;

// Determine the left and right directions
If (mid (rectserver. Top, rect ^. Top, rectserver. Bottom) or mid (rect ^. Top, rectserver. Top, rect ^. Bottom) then
Begin
If (distancein (rect ^. Left, rectserver. Right, distance) and (msright in mainserver. fmagnetstyles) then
Begin
// Paste it on the right
Fxpos: = rectserver. Right;
Ispasted: = true;
End
Else if (distancein (rect ^. Right, rectserver. Left, distance) and (msleft in mainserver. fmagnetstyles) then
Begin
// Paste it on the left
Fxpos: = rectserver. Left-(rect ^. Right-rect ^. Left );
Ispasted: = true;
End;
End;

// Determine whether to paste it to the main form or remove it from the main form
If ispasted and mainserver. Active then
Begin
If not assigned (fmagnetserver) then
Begin
Mainserver. fmagnetclientlist. Add (Self );
Fmagnetserver: = mainserver;
End;
End else begin
If assigned (fmagnetserver) then
Begin
Mainserver. fmagnetclientlist. Remove (Self );
Fmagnetserver: = nil;
End;
End;
End;

// Register the tmagnetserver and tmagnetclient components we have defined in Delphi
Procedure register;
Begin
Registercomponents ('magnet', [tmagnetserver, tmagnetclient]);
End;

Through the above analysis, design, and coding process, we have completed the creation of a magnetic window component, as long as a magnetic form component is placed on the form, componentization of magnetic forms makes application development easier. Next we will create an application to see how it works.

Test
 
Figure 1

Install the magnetic form component we just created in the Delphi environment, create an application, create three forms, and put one tmagnetserver and one tmagnetclient component respectively, and set the window size to the appropriate size. Compile the program to generate the executable file, as shown in running effect 1. All the above Code passes the test under delphi6.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.