A specific magnetic form VCL components to achieve subtitle: Author: Anonymous Source: Monopoly Hits: 52 Update Time: 2005-2-25 article: Chen Dajun Date: 2003-10-29
I remember that there was an article in "Programmer" magazine to introduce how to implement magnetic forms, this article summarizes the online discussion posts, analyzes the basic principles of magnetic forms, and eventually give a viable solution . However, the main form of the magnetic adsorption capacity described in the text can only be the main form of the application, not flexible, and the sample code given in the text is implemented in C Bulider. Now we try to implement this function in the form of a VCL component in Delphi, and strive to do some extensions. In the case of omissions, please advise.
Analyze the discussion before we first define two nouns. The main form referred to herein refers to a form having a magnetic adsorption, and the sub-form is a form that is adsorbed by the main form and can be adsorbed with the main form, and the sub-form is not adsorbed. . For an alteration, the magnet can adsorb one or more iron blocks, and between the two iron blocks do not have magnetic effects (if the iron block is magnetized, it is another matter). Let's take a rough process that realizes the magnetic form.
First, the process of paste the main form of the main form
What kind of message is the user receives during the process of moving a form? Let's take a look at the MSDN: The WM_MOVING Message is moving. By Processing this message, an Application CAN Monitor The Position of the Drag Rectangle and if NEEDED, CHANGE ITS POSITION.
It turns out that the system message for the WM_MOVING standard is constantly generated in the form of the form movement! ! ! The LPARAM parameter of this message is a pointer to the TRECT structure, and the current position rectangular area information is placed in the TRECT structure. It is not difficult to infer the WM_MOVING message we need to intercept the window. There are many ways to cut the window message in Delphi. Here we use the modified window function to intercept this message with custom message processing functions.
Let's take a look at the explanation of WM_MOVE messages 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, used to adjust the final position of the relevant window.
In the custom message processing function, we constantly detect the distance of the child form and the main window, if less than a set value, then paste the child form to the main form. But how do you learn the main form? Because only the main form is obtained, we can compare both the positions, determine if the child form can be adsorbed to the main form. The way APPLICATION-> Mainform is used in the following article, which limits the main form of the main form. What we take is to define a global variable to save the TMagNetServer object associated with the main form. Use this object to assign this global variable when creating the first TMAGNetServer object. Of course, there can only be a TMAGNetServer in each application. Object.
Second, the process of moving from the main form from the main form
The process of removing the subform from the main form is very similar to the above-described paste process, and the two can be processed together when implementation. In the custom message processing function, the distance from the child form and the main window is constantly detected. If it is greater than a set value, the subform is disconnected from the main window.
Third, the process of the main window related sub-form movement
The main window associated subform movement means that all the sub-forms that are pasted into the main form during the movement of the main form move, and the relative position remains unchanged. Similarly, the process of the main form will receive the WM_MOVING message in the mobile process, and we can intercept this message and change the position of all the subforms associated one by one. Design Delphi as a RAD (Rapid Application Development) tool and is deeply loved by the majority of programmers, rich VCL libraries can not be active. As can be seen from the above analysis, we define three classes to implement them to accommodate the development needs of "one-to-use" components. The TMagnetForm class is the base class of the TMagnetServer and the TMAGNetClient class, mainly to replace the original window function, intercepting the functionality of the specific window message. Since the magnetic form assembly has an inseparableity at runtime, the class is inherited directly from the Tcomponent class. Note: The Domoving and Domove functions of the TMAGNETFORM class are defined as the Virtual, Abstract Type, and make full use of the virtual function, implementation, according to the inheritance class, dynamically call different functions during runtime. The relevant instructions for the TMAGNetForm class are shown in Table 1.
Name Types OldwindowProc TwndMethod Default Message Process Domoving Procedure Virtual Abstract WM_MOVING Message Process Domove Procedure Virtual Abstract WM_MOVE Message Process Function Table 1
The TMAGNetServer class implements the functionality of the magnetic main form. The TLIST class in Delphi provides a good container class for our storage subform list. When there is a child form to a main form, add the TMAGNETCLIENT object of the child form to the linked list, which is removed from the linked list. In the process of moving the main form, call the AdjustFormPOS function, and adjust the position of the child form one by one. And you can control the paste style of the main form by the MagnetStyles collection type property. Table 2 is shown in TMAGNetServer class.
FActive Boolean Name Type Description decide whether to allow the main form paste FDistance Integer magnetic attracting force generated from the window FMagnetStyles TMangerStyles FForm main form TScrollingWinControl associated Paste Style list AdjustFormPos procedure FMagnetClientList subform subform associated adjustment location associated with a particular UnionOtherForm procedure TList Adjustment Process Domove Procedure Override Overloaded Based Class Function Domoving Procedure Override Overload Base Class Same Function Table 2
The TMagnetClient class is used to encapsulate the function of the magnetic subform. The FmagnetServer member variable is used to store the TMagNetServer object of the main form associated with the subform. Table 3 is shown in TMAGNETCLIENT class.
FEnabled Boolean Name Type Description Top final position for preventing the paste AttachToForm procedure final position FYPos Integer Left subform paste operation is repeated TScrollingWinControl associated FForm window FMagnetServer TMagnetServer paste the main form FXPos Integer attached to the main form subform Or removing the process Domove Procedure override Overloaded base class with the same name function Domoving procedure override overload base class with the same name function Table 3
The code has been analyzed by the above detailed analysis design, and the specific implementation process of the magnetic form assembly is not difficult. Below we will pick some key code to explain, please refer to the example code for the specific implementation process. Var mainserver: TMAGNETSERVER; / / Define a global variable
// define a new form message handler 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);
// TmagnetForm constructor, to ensure that each can only have one form or TMagnetClient TMagnetServer assembly 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 window The body already has a TMagnet Server or TmagnetClient component! '); Exit; end; end; inherited create (aowner);
Alert () function is a custom function for displaying warning information. Defined as follows:
// Display Warning Information Procedure Alert (const msg: string); recomLication.MessageBox (Pchar (MSG), Pchar (Application.title), MB_ICONWARNING or MB_OK;
//TMagnetServer class constructor constructor tMagnetServer.create (Aowner: Tcomponent); Begin / / Make sure that each application's TMAGNetServer component unique if Assigned (MAINSERVER) THEN BEGIN ALERT ('Each application can only have a TMAGNetServer component! '); Exit; end; inherited create (aowner);
// initialize member variables FMagnetClientList: = TList.Create; FForm: = AOwner as TScrollingWinControl; FDistance: = DEFAULT_DISTANCE; FActive: = True; FMagnetStyles: = [msTop, msBottom, msLeft, msRight]; MainServer: = Self; // will MAINSERVER global variables defined above
// Replace window message handler if not (csDesigning in ComponentState) then begin OldWindowProc: = FForm.WindowProc; FForm.WindowProc: = NewWndProc; end; end; procedure TMagnetServer.AdjustFormPos // move other forms are stuck together ( RECT: prect); VAR DX, DY: Integer; Nindex: Integer; MagnetClient: TmagnetClient; Begin if not assigned (fform).
DX: = Rect ^ .left - fform.Left; DY: = Rect ^ .top - fform.top; fform.left: = Rect ^ .left; fform.top: = Rect ^ .top;
// Adjust all child forms associated with the main form one by one for nindex: = 0 to fMagnetClientList.count - 1 do begin magnetclient: = fmagnetClientList [NINDEX]; union Port; DX, DY); end;
// specific adjustment position subform process 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.FENABED: = false; fx: = formTemp.LEFT; fy: = formTemp.top; setWindowPos (formtemp.handle, fform.handle, fx dx, fy DY , FormTemp.width, SWP_NOSIZE OR SWP_NOACTIVATE); magnetclient.fenabled: = true; end;
// Paste the form into the main form or re-remove the process Procedure TmagNetClient.attachToform (MagnetServer: TmagnetServer; RECT: prect; distance; ispasted: boolean; begin if not NOT Assigned (fform) THEN EXIT; IF NOT Assigned (Main Server) Then EXIT ;; if not assigned (mainserver.fform).
GetWindowRect (mainserver); fxpos: = Rect ^ .left; fypos: = Rect ^ .top; ispasted: = false; // Up and down direction judgment IF (MID (RectServer.Left, Rect ^ .left, Rect Server.right) or MID (Rect ^ .left, RectServer.Left, Rect ^ .right)) The beginiff (Distancein (Rect ^ .top, RectServer.bottom, Distance) and (Msbottom in mainserver.fmagnetStyles) The Begin // Paste fypos: = RectServer.bottom; ISPASted: = true; end else = true; end else f (rect ^ .bottom, RectServer.top in mainserver.fmagnetStyles) The begin // Paste fypos: = RectServer.top - (Rect ^ .bottom - Rect ^ .top); ispasted: = true; end; END; / / The left and right direction judgment IF (MID (RectServer.Top, Rect ^ .top, RectServer.bottom) or MID (Rect ^ .top, RectServer.top, Rect ^ .bottom) The beginness (DISTANCEIN (Rect ^ .left, RectServer.right, distance) and (msright in mainserver.fmagnetstyles) The begin // Paste fxpos: = RectServer.right; ispasted: = true; ELSE IF (Distancein Rect ^ .right, RectServer.Left, distance) AND (Msleft in mainserver.fmagnetStyles)) The begin // Paste fxpos: = RectServer.Left - (Rect ^ .right - Rect ^ .left); ispasted: = true; END;
/ / Decision is finally pasted to the main form or remove if ISPASTED and mainserver.Active the Begin if not assigned (fMagnetServer )1 Begin Mainserver.FmagnetClientList.Add (self); fmagnetServer: = mainserver; end; Else Begin if Assigned (Fmagnet Server).
// Register our defined TMagNetServer and TmagnetClient components to Delphi Procedure Register; Begin RegisterComponents ('Magnet', [TmagnetServer, TmagnetClient]); END; through the above analysis, design, and encoding process, we completed a magnetic window The assembly is made, as long as it places a correlation magnetic form assembly on the form, the magnetic form assembly will be more convenient when the application is developed. Let's take a look at the effect.
Test Figure 1
Install the magnetic form assembly we have just created into the Delphi environment, and create a new application, create three forms, put on a TMAGNETSERVER and TMAGNETCLIENT components, and set the window to the appropriate size, the compiler generation can be implemented File, the operation is shown in Figure 1. All of the above code is tested under Delphi6.