Tencent QQ is one of the current popular network chat tools, because it has a lot of uniqueness in the application design, so many programmers are studying and imitating. Here, I will use Delphi to automatically hide the effect of QQ form.
First, the question is proposed
Friends who are familiar with QQ know that when the QQ form area exceeds the screen four sides, the form will automatically "disappear", leaving only the small part of the form is revealed on the desktop. When you move over the reverse area with a mouse, the form will re-complete the hidden location; but after the mouse leaves the form area, the form will re-enter the hidden state.
Analysis of the hidden whole process can be obtained: First, the processing is related to the form movement process; second, the hidden trigger condition of the form is the form of the form has been moved to the screen. Outside the visible range.
For the first point, it can be implemented by intercepting the Windows message generated when moving the form. For the second point, how to express the key to the "form area has exceeded the screen visual range".
Second, the basic analysis
Let us first pay attention to the process and effect of the form movement in the Windows environment. When using a mouse to move the form, the form itself does not immediately change with the movement of the mouse; in contrast, the mouse is dragging a size and a transparent area that is consistent with the form (exactly a dashed border rectangle). When the mouse releases the rectangle, the form itself will appear in the last stay in the rectangle, thereby completing the entire movement process. (Note: In Windows 2000 and XP environments, if the display effect options displayed during the display attribute, the display effect option is displayed, the above process cannot be observed.)
For the QQ form, its mobile processes are not different from the above, but there is a difference. When we move the rectangle to the four sides of the screen, the rectangle will automatically stay in the outward position and complete display. No matter how we try to move the rectangle backward, the rectangle is only held in this position. After the mouse is released, the hidden effect of the form will appear.
From the above process, it can be inferred that after the hidden conditions are triggered, even if the movement is still in the mobile process, the rectangle itself has been locked, and therefore the determination of the form position occurs during the movement process, that is, the Windows message we want to intercept the process is WM_MOVING . Second, the rectangle is first changed during the movement instead of the form itself, so the key to implementing hidden is the judgment and setting of the rectangular parameters.
We can first pay attention to the syntax structure of the WM_MOVING message:
WM_MOVING
WPARAM WPARAM
LParam LPARAM,
Where WPARAM is not used, and LPARAM is a pointer, which is pointed to a RECT structure. The RECT structure includes four parameters of LEFT, TOP, RIGHT, and BOTTOM, which are used to describe the upper left corners of the rectangle and the lower right corner. "The RECT records the current position of the form relative to the screen; when it is necessary to change the position of the drag rectangle When the program itself must change the correlation value of each member variable in the RECT structure. " It can be seen that the rectangle we have to process is actually mentioned in the WM_MOVING message, and we have to handle the relevant parameters of the RECT structure pointed to the LPARAM.
Next we want to set a timer activated by hidden conditions, the purpose is to monitor the position of the mouse relative to the form. Since the hidden hidden is activated by the mouse, if the mouse is detected above the form, the form is displayed in the display state; in turn, the form is hidden. We only need to join the assignment of the form TOP and LEFT attributes in the relevant judgment to achieve a hidden effect.
At this point, the analysis of automatic hidden effect is basically completed. However, pay attention to it, because we are judge the hidden conditions in the interception processing of the WM_MOVING message, and the hidden effect is handled by the Timer OntiMer event. This hidden condition is satisfied that the delivery in both processes will become a key. At the same time, we have to know not only whether the hidden conditions are met, but must also know that the form is hidden on the side of the screen. To do this, we need to define a collection to describe the location hidden in the form, for example: Type
Hideposkind = (HPTOP, HPLEFT, HPBOTTOM, HPRIGHT);
Type
THIDEPOS = set of hideposkind;
However, similar collections already exist in Delphi itself, such as Tanchors collection. The Tanchors collection is originally used to indicate how a control is anchored to its parent class control, and we are borrowed here to describe the hidden location of the form on the screen.
There are also four values in the Tanchors collection, which are defined as follows:
Type Tanchorkind = (Aktop, Akleft, Akright, Akbottom);
Type tanchors = set of tanchorkind;
In the implementation of the code, we will define a global variable Fanchors for Tanchors type to describe the hidden location of the form.
Third, the initial implementation
First we define a process to intercept the WM_MOVING message, the code is as follows:
......
Private
Fanchors: Tanchors;
Procedure WMMOVING (VAR Msg: TMESSAGE); MESSAGE WM_MOVING;
......
Uses Math, Type;
Procedure TFORM1.WMMOVING (VAR MSG: TMESSAGE);
Begin
inherited;
With prect (msg.lparam) ^ DO
Begin
Left: = min (max (0, left), screen.width - width;
Top: = min (Max (0, TOP), Screen.height - Height;
Right: = min (Max (Width, Right), Screen.width;
Bottom: = min (Max (HEIGHT, BOTTOM), Screen.Height);
FANCHORS: = [];
If Left = 0 THEN INCLUDE (Fanchors, Akleft);
IF Right = Screen.width THEN INCLUDE (Fanchors, AkRight);
IF TOP = 0 THEN INCLUDE (Fanchors, Aktop);
IF bottom = screen.height kiln include (Fanchors, Akbottom);
Timer1.enabled: = Fanchors <> [];
END;
END;
During this process, we determine if the position where the form is in accordance with the hidden conditions by determining the rectangular parameters Left, TOP, RIGHT, and BOTTOM, and the determination results are stored in the global variable fanchors. When hidden, at least one value is not more than two values in Fanchors. (why?)
The setting of judgment conditions seems to be a bit different from our general understanding. Taking the judgment of the Left parameters as an example, why should it be more compared to the value of Screen.Width - Width after judging MAX (0, LEFT)? This is actually for pseudo-processing for some of the extreme conditions, such as the width of the form being larger than the screen width. If you are interested, you can test these extreme effects. Of course, if our form limits wide, high maximum, it can simplify our initial understanding. Finally, it is important to note that the Left, Top, Right, Bottom appearing in the code is the parameters of the RECT, while Width and Height are the properties of the form FORM1.
Next we have to deal with TTIMER's Ontimer event. During the WMMOVing process, when Fanchors is not empty, TTIMER starts; the TTIMER is closed. The code for the ONTIMER event is as follows:
Procedure TFORM1.TIMER1TIMER (Sender: TOBJECT);
Const
Coffset = 2;
Begin
IF windowFromPoint (mouse.cursorpos) = handle kil
Begin
IF akleft in fanchors the left: = 0;
IF aktop in fanchors the TEN top: = 0;
IF AKRight in fanchors the left: = screen.width - width
IF akbottom in fanchors the TEN top: = Screen.height - Height;
END ELSE
Begin
IF AKLEFT IN FANCHORS THEN LEFT: = -Width Coffset;
IF aktop in fanchorshen top: = -Height Coffset
IF AKRight in fanchors the left: = screen.width - coffset
IF akbottom in fanchors the TEN top: = Screen.Height - Coffset
END;
END;
Here, we first define a constant Coffset to indicate the size of the display after the form is hidden. Then we use the WindowFromPoint this Windows API function to detect whether the mouse is on the form. The next judgment is to process the settings of the form LEFT and TOP attribute values in the display and hidden state. Note that there is different values in Fanchors, the settings of the form LEFT and TOP are different, but these settings are only different from the sequential difference and there is no priority difference. (Why should I mention this?)
Finally, it is necessary to note that in this incident, TOP, LEFT, WIDTH, and HEIGHT are the attribute values of form FORM1.
Ok, the core code about the form has been introduced, but to achieve the expected effect, the form FORM1 must be prepared when it is created, the code is as follows:
Procedure TFORM1.FormCreate (Sender: TOBJECT);
Begin
Timer1.enabled: = FALSE;
Timer1.interval: = 200;
Formstyle: = fsstayontop;
END;
The code here is relatively simple, but it is worth pointing out that the setting of the FormStyle property of Form1 is pointed out. FormStyle ensures that Form1 is always previously displayed when FSSTAYONTOP. From an effect angle, it is most pronounced when the system toolbar is "always in the forefront", because if the form is moved to the system toolbar, it will not be covered by it. Fourth, further improve
The above code has basically realized the automatic hidden effect of the form, but I have two problems when introducing the code, but I have been proposed but I have not been given.
The first is why there is at least one value in Fanchors when it triggers hidden hidden? Note that the assignment of Fanchors in the code is conducted by four judgments, then if hidden words are triggered, there will be no doubt in the Fanchors, but this is to hide the four sides of the screen. When the form is pushed into the four angle of the screen, then there will be two values in Fanchors. What is hidden in this time?
The actual effect tells us that the form will be hidden from the four corners of the screen. At this point, if we try to let the form redisplay, you will find that the form is constantly flashing. why? This is the reason for the second question. Because the processing of form display or hidden is made according to the value in the Fanchors. When there are two values in the Fanchors, two settings for the form properties will be thrown. Because setting statements are only available in order differences, there is no priority difference, and the form is set twice each time the ONTIMER event is set, causing us to see the flashing display.
How to solve this problem? Let's observe the processing of QQ. In the 2003 II version of QQ, the hidden effect of the form has been adjusted: When the form is hidden on both sides of the screen, it will automatically full of the left and right sides of the screen and the height cannot be changed; when the form is separated from the screen After the area, the size of the form will return to the size of the hidden. (Note: The form is not completely full of screen. QQ may only note that the system toolbar is always displayed at the top of the system when processing this effect, and it is only the top of the screen to the system toolbar. One of the above spaces.) This process can make the form that even be processed even if it is pushed into the screen four corner, it can only be processed only in one of the hidden directions, thereby avoiding the flashing phenomenon in front.
Combined with the previous analysis, to achieve the above effect or start from intercepting the WM_MOVING message. The WMMOVING process after rewriting is as follows:
Procedure TFORM1.WMMOVING (VAR MSG: TMESSAGE);
Begin
inherited;
With prect (msg.lparam) ^ DO
Begin
IF (Akleft in Fanchors) or (Akright in Fanchors) THEN
Begin
IF (Left> 0) and (Right Begin If REC_POSITION THEN Begin Bottom: = TOP LST_HEIGHT; Right: = Left LST_WIDTH; Height: = LST_HEIGHT; Width: = LST_WIDTH; END; END ELSE Begin SetBarheight; TOP: = CUR_TOP; Bottom: = CUR_BOTTOM; EXIT; END; END; Left: = min (max (0, left), screen.width - width; ...... IF not r_position thein Begin LST_HEIGHT: = form1.height; LST_WIDTH: = Form1.Width; END; FANCHORS: = []; ...... IF (Akleft in Fanchors) or (Akright in Fanchors) THEN Begin REC_POSEN: = TRUE; SetBarheight; TOP: = CUR_TOP; Bottom: = CUR_BOTTOM; END ELSE R_Position: = false; Timer1.enabled: = Fanchors <> []; END; END; In the new code, we first use three newly defined global variables, namely: LST_HEIGHT: INTEGER; // Record the height of the form hidden LST_WIDTH: INTEGER; // Record the width of the form to hide the form REC_POSITION: BOOLEAN; / / Whether to start the form wide high logo Then add three judgment code blocks. In the first judgment, first determine whether the form is located in the hidden area on the left and right sides of the screen. If it is true, it is judged whether the form is moved from the hidden area to the screen (note that there is this judgment because we may also push the form on the screen). If it is true, restore the size of the form before hiding; in turn, force the rectangular TOP and BOTTOM value and exit the process of the message. The second judgment is to record the wide value of the form. REC_POSITION is a logo that records the width of the form, which is set in the third judgment. If the form is located on the hidden area on both sides of the screen, REC_Position is True, and the height of the form is fixed, and the record has no meaning. So only the width of the form is only required when REC_POSITION is false. The third judgment is after setting the Fanchors value setting. It determines the rectangular display effect according to the position of the form. The judgment is also based on whether the form is on both sides of the screen, and the height of the rectangle is set, and the value of the REC_POSITION is TRUE. A new defined process setBarHeight is used in the third judgment, and its code is as follows: Procedure TFORM1.SetBarHeight; VAR AppBardata: Tappbardata; Begin AppBardata.cbsize: = sizeof (appbardata); IF shappbarmessage (abm_getstate, appbardata) and abs_autohide <> 0 THEN Begin CUR_TOP: = 1; CUR_BOTTOM: = Screen.height - 1; END ELSE Begin ShappbarMessage (abm_gettaskbarpos, appbardata); Case appbardata.uedge of ABE_TOP: Begin CUR_TOP: = AppBardata.rc.bottom 1; CUR_BOTTOM: = Screen.height - 1; END; ABE_LEFT: Begin CUR_TOP: = 1; CUR_BOTTOM: = Screen.height - 1; END; ABE_Right: Begin CUR_TOP: = 1; CUR_BOTTOM: = Screen.height - 1; END; ABE_BOTTOM: BEGIN CUR_TOP: = 1; Cur_bottom: = Screen.height - (AppBardata.rc.bottom - appbardata.rc.top) - 1; END; END; END; END; SetBarHeight is used to calculate the rectangular height, and the calculated result is passed to the TOP and BOTTOM parameters passing the rectangular TOP and BOTTOM parameters through CUR_TOP and CUR_BOTTOM. A Windows API function ShappbarMessage is used during this process. The role of ShappbarMessage is to transfer system toolbar messages to the system, and its function prototype is: Winshellapi uint apientry shappbarMessage DWORD DWMESSAGE, Pappbardata pdata; Where dwMessage is a toolbar message sent to the system; PDATA is a pointer to the PAPPBardata structure, and the content returned by the PAPPBardata structure is based on the message issued. In the process, we first pass the ABM_GETSTATE parameter to get the status of the system toolbar is automatically hidden or always in front. Then we use the abm_gettaskbarpos parameter to get the location of the system toolbar. At this time, the return value of AppBardata will be the position of the system toolbar ABE_TOP, ABE_LEFT, ABE_RIGHT, ABE_BOTTOM four. Finally, we use the system toolbar itself to calculate the height of the toolbar. The SETBARHEIGHT makes the form changes corresponding to the position and height of the screen with the system toolbar on the screen. Of course, you can also set a fixed value directly to the two variables of CUR_TOP and CUR_BOTTOM to implement the QQ effect. In the test, Cur_TOP can be 1, and Cur_Bottom is Screen.Width - 30 (the height of the Windows System Toolbar is 30 defaults 30, which is not as resolution). Since the height and position of the form on the screen can change accordingly with the change in the position and height of the system toolbar, the processing in the ONTIMER event must also be changed accordingly, mainly to display the form. Settings to form top and height properties must be coordinated with the location and height of the system toolbar, the code is as follows: ...... IF akleft in fanchors life Begin Left: = -Width Coffset; SetBarheight; TOP: = CUR_TOP; Height: = CUR_BOTTOM; END; IF akright in fanchors thein Begin Left: = screen.width - coffset; SetBarheight; TOP: = CUR_TOP; Height: = CUR_BOTTOM; END; ...... Finally, in order to ensure that the form remains unchanged after the form is hidden on the screen, we add a WMSIZING process to intercept the WM_SIZING message. The code for the WMSIZING process is as follows: Procedure TFORM1.WMSIZING (VAR MSG: TMESSAGE); Begin inherited; akright in fanchors. Begin With prect (msg.lparam) ^ DO Begin Left: = screen.width - width; TOP: = CUR_TOP; Right: = Screen.width; Bottom: = CUR_BOTTOM END; ELSE IF (Akleft in fanchors) THEN Begin With prect (msg.lparam) ^ DO Begin LEFT: = 0; TOP: = CUR_TOP; Right: = width; Bottom: = CUR_BOTTOM; END; END; END; The syntax structure of the WM_SIZING message is similar to the WM_MOVING message, and there is also a pointer to the rectangle. With this pointer we can set the rectangular TOP, LEFT, RIGHT, and BOTTOM parameters to ensure that the rectangular height is not affected by the user. At this point, a single form automatically hidden is basically completed, and its actual effect is quite close to QQ. Of course, there are still some small flaws from the actual operation, and the code does not process the form on the hidden width setting, or you can consider continuing this procedure.