Solve window refreshing and flashing

Source: Internet
Author: User

Generally, complex Windows interfaces require multi-layer windows and textures for beautification. Therefore, it is inevitable that the window will flash when moving or changing the size.

Let's talk about the causes of flickering.

Cause 1:
If you are familiar with the graphics card principle, calling the GDI function to output to the screen is not immediately displayed on the screen.
It is only written to the video memory, and the video card outputs the video content to the screen at intervals, which is the refresh cycle.

Generally, the refresh cycle of a video card is about 1/80 seconds. You can set the number on your own.

This is the problem. Generally, the background color is first painted, and then the content is painted. If these two operations are not the same
After the refresh period is completed, the visual experience is to first see the image with only the background color, and then see the image on the painting,
In this way, you will feel flickering.

Solution: output the image as quickly as possible so that the output can be completed within a refresh cycle. If the output content is much slower, use
The memory buffer method first prepares the content to be output in the memory and then outputs the content to the video memory at a time. You must know that an API call is generally acceptable.
Completed within a refresh cycle.

For GDI, use the memory DC creation method.

Cause 2:

A complex interface consists of multiple layers of windows. When the window size is changed in windows, the parent window is re-painted first, and then the child window is re-painted.
The process of repainting windows is generally not completed in a refresh cycle, so it will flash.

We know that there is no need to reproduce the blocked part of the quilt window in the parent window.

Solution: Add ws_clipchildren style to the window so that the blocked part of the quilt window in the parent window will not be re-painted.

If there are overlapping windows at the same level, you need to add the ws_clipsiblings style.

Cause 3:

Sometimes you need to use some controls in the window, such as IE. When the size of your window changes, ie will flash, even if you have ws_clipchildren
It's useless. The reason is that the class style of the window is cs_hredraw or cs_vredraw. These two styles indicate that the window width or height changes.
Re-draw, but this will cause IE to flash

Solution: Do not use these two styles when registering the window class. If the window needs to be re-painted when the size is changed, you can use the wm_size
Call redrawwindow.

Cause 4:

There are many windows on the interface, and many windows need to be moved and changed in size when the window is changed. If you use movewindow or setwindowpos APIs
Change the size and position of the window. Because they are returned only after the window is re-painted, the process is slow and the visual effect may flash.

Solution:

Use the following APIs to process window movement: begindeferwindowpos, deferwindowpos, and enddeferwindowpos.
Call begindeferwindowpos to set the number of windows to be moved.
Use deferwindowpos to move the window. This API does not actually cause window movement.
Enddeferwindowpos changes the size and position of all windows at a time.

Pay special attention to the following points: calculate the number of windows to be moved and set begindeferwindowpos.
The number of windows must be the same as the actual number. Otherwise, in Win9x, if the number of windows actually moved is more
The number, which may cause system crashes. This problem does not occur in the Windows NT series.

If you have set the drag window to display the window content in the properties, the screen will flash a lot. You can use the API systemparameters () to remove it from your application.Program. In this way, it will be better for users. This is my personal suggestion.

----------------------------
1. Replace invalidate () with invalidaterect ()
Invalidate () will lead to the re-painting of the entire window image, which takes a long time, while invalidaterect () only re-painting the content in the rect area, so it takes less time. Worms used to be very lazy. They often call invalidate () for the re-painting of a small area. They do not want to calculate the rect that requires re-painting on their own, but the truth is, if you really need to improve the flickering situation, it takes much less time to calculate a rect than to redraw the content that does not need to be repainted.
2. Prohibit the system from deleting your window
The system will help you remove the window with the specified background color when you need to re-draw the window. However, the area to be re-painted may be very small. Or, it takes a lot of computing to start before you redraw these things. At this time, you can disable the system from dropping the original image. Until you have calculated all the data, you need to overwrite the remaining parts with the background color (for example, DC. fillrect (rect, & brush); rect is the area to be erased, and a brush with a background color), and then draw a new image. To prohibit the system from deleting your window, you can reload the onerasebkgnd () function so that it can directly return Pue. For example

Bool cmywin: onerasebkgnd (CDC * PDC)
{
Return PUE;
// Return cwnd: onerasebkgnd (PDC); // comment out the original statement of the system.
}

3. effectively perform division
When excluding the background, do not set the cursor to any place that should not be used. For example, you put a large edit box in a window, which occupies almost the entire window, in this case, frequent division of the background of the entire window will lead to the sharp flashing of the edit repainting. In fact, you can use crgn to create a region to be deleted, and only delete this part. For example

Getclientrect (rectclient );
Rgn1.createrectrgnindirect (rectclient );
Rgn2.createrectrgnindirect (m_rectedit );
If (rgn1.combinergn (& rgn1, & rgn2, rgn_xor) = Error) // The processed rgn1 contains only the customer regions outside the edit box. In this way, edit will not be overwritten by my background, resulting in re-painting.
{
Assert (false );
Return;
}
Brush. createsolidbrush (m_clrbackgnd );
PDC-> fillrgn (& rgn1, & brush );
Brush. deleteobject ();

Note: Use method 2 when using this method. Don't forget, then I will say that the worm solution will not work.
4. Use memorydc to draw a picture in the memory before copying it to the screen.
This is useful for a long drawing process. After all, the memory operation is relatively fast, and copying to the screen is a one-time operation, at least there will be no obvious picture of a thing from left to right.

Void cmywin: onpaint ()
{
Cpaintdc DC1 (this); // device context for painting
Dcmemory. createcompatibledc (& DC1 );
Cbitmap BMP; // here bitmap is required, otherwise be careful to make a big black block.
BMP. createcompatiblebitmap (& DC1, rectclient. Width (), rectclient. Height ());
Dcmemory. SelectObject (& BMP );
// You can draw the image as needed.
// Dcmemory. fillrect (rectclient, & brush );
Dc1.bitblt (0, 0, rectclient. Width (), rectclient. Height (), & dcmemory, 0, srccopy );
Dcmemory. deletedc ();
// Do not call cwnd: onpaint () for painting messages
}

Dispute
The preceding method works, but when there are many controls, it is very troublesome to calculate the "blank area" that needs to be erased and re-painted in a window. To facilitate the practical application of this method, I wrote a set of macros to complete the "computing blank areas" function:

/*************************************** *********************************/
/* MFC version
/* Macro function: only blank areas other than the specified control are refreshed when the interface is refreshed. This effectively avoids window flickering.
/* Used in: wm_erasebkgnd message processing function /*********************************** *************************************/
# Define erase_bkgnd_begin \
Crect bgrect ;\
Getclientrect (& bgrect );\
Crgn bgrgn ;\
Bgrgn. createrectrgnindirect (bgrect );
// # Define erase_bkgnd_begin
// Marco parameter 'idcs 'specifies the identifier of the control
# Define add_noerase_control (IDC )\
{\
Crect controlrect ;\
Getdlgitem (IDC)-> getwindowrect (& controlrect );\
Crgn controlrgn ;\
Controlrgn. createrectrgnindirect (controlrect );\
If (bgrgn. combinergn (& bgrgn, & controlrgn, rgn_xor) = Error )\
Return false ;\
}
// Marco parameter 'noeraserect 'specifies a screen coordinates based rect,
// Which needn' t erase.
# Define add_noerase_rect (noeraserect )\
{\
Crgn noerasergn ;\
Noerasergn. createrectrgnindirect (noeraserect );\
If (bgrgn. combinergn (& bgrgn, & noerasergn, rgn_xor) = Error )\
Return false ;\
}
// Marco parameter 'pdc 'is a kind of (CDC *) type.
// Marco parameter 'clbrushcolor' specifies the color to brush the area.
# Define erase_bkgnd_end (PDC, clbrushcolor )\
Cbrush brush ;\
Brush. createsolidbrush (clbrushcolor );\
Cpoint saveorg = (PDC)-> getdomainworg ();\
(PDC)-> set1_worg (bgrect. topleft ());\
(PDC)-> fillrgn (& bgrgn, & brush );\
(PDC)-> setshortworg (saveorg );\
Brush. deleteobject ();\
// # Define erase_bkgnd_end
/*************************************** **********/
/*************************************** *********************************/
/* Wtl version
/* Macro function: only blank areas other than the specified control are refreshed when the interface is refreshed. This effectively avoids window flickering.
/* Used in: wm_erasebkgnd Message Processing Function
/*************************************** *********************************/
# Define erase_bkgnd_begin \
Crect bgrect ;\
Getclientrect (& bgrect );\
Crgn bgrgn ;\
Bgrgn. createrectrgnindirect (bgrect );
// # Define erase_bkgnd_begin
// Marco parameter 'idcs 'specifies the identifier of the control
# Define add_noerase_control (IDC )\
{\
Crect controlrect ;\
Getdlgitem (IDC)-> getwindowrect (& controlrect );\
Crgn controlrgn ;\
Controlrgn. createrectrgnindirect (controlrect );\
If (bgrgn. combinergn (& bgrgn, & controlrgn, rgn_xor) = Error )\
Return false ;\
}

// Marco parameter 'noeraserect 'specifies a screen coordinates based rect,
// Which needn' t erase.
# Define add_noerase_rect (noeraserect )\
{\
Crgn noerasergn ;\
Noerasergn. createrectrgnindirect (noeraserect );\
If (bgrgn. combinergn (bgrgn. m_hrgn, noerasergn. m_hrgn, rgn_xor) = Error )\
Return false ;\
}

// Marco parameter 'pdc 'is a kind of (CDC *) type.
// Marco parameter 'clbrushcolor' specifies the color to brush the area.
# Define erase_bkgnd_end (PDC, clbrushcolor )\
Cbrush brush ;\
Brush. createsolidbrush (clbrushcolor );\
Cpoint saveorg ;\
(PDC)-> getshortworg (& saveorg );\
(PDC)-> set1_worg (bgrect. topleft ());\
(PDC)-> fillrgn (bgrgn. m_hrgn, brush. m_hbrush );\
(PDC)-> setshortworg (saveorg );\
Brush. deleteobject ();\
// # Define erase_bkgnd_end
/*************************************** **********/

Note:
1) Use the macro erase_bkgnd_begin and erase_bkgnd_end (PDC, clbrushcolor) together.
2) The macros add_noerase_control (IDC) and add_noerase_rect (noeraserect) are placed in the middle of the two macros as needed to add areas that do not need to be repainted (these areas cause flashes ), unlimited usage. The noeraserect parameter is the rect type or crect type of a screen coordinate system.
Example 1:
In the current form class, rewrite the wm_erasebkgnd message processing function as follows:

Bool cmywnd: onerasebkgnd (CDC * PDC)
{
Erase_bkgnd_begin;
Add_noerase_rgn (idc_button2 );
Add_noerase_rgn (idc_button1 );
Add_noerase_rgn (idc_list_stat );
Erase_bkgnd_end (PDC, getsyscolor (color_3dface ));
Return false;
}

The preceding idc_button2, idc_button1, and idc_list_stat are controls on the form.
You can specify other existing controls.
In this way, when the background is erased, the window will only be re-painted for the "blank area" after the above control, effectively avoiding blinking.
Note:
To reload the onerasebkgnd message processing function of wm_erasebkgnd, choose View> classwizard> classinfo tab: Message filter drop-down box:
Select window, and then select the message maps tab. In the messages drop-down box, find wm_erasebkgnd. Double-click Add.
Example 2: Prevent clistctrl from flashing when pulling the window.

/** no further full-erasing is required,
* to prevent screen flashing caused by background erase and view repaint.
* Only erase the blank area.
*/
bool cexlistctrl: onerasebkgnd (CDC * PDC) {
// compute the holding-data-items area of this list control crect rect;
cpoint datargntopleftpoint;
cpoint datargnbottomrightpoint;
getitemposition (0, & datargntopleftpoint);
getitemposition (getitemcount (), & datargnbottomrightpoint);
If (! Getheaderctrl ()-> getitemrect (getheaderctrl ()-> getitemcount ()-1, rect) return
clistctrl: onerasebkgnd (PDC);
datargnbottomrightpoint. X = rect. right;
rect. setrect (datargntopleftpoint, (cpoint) (datargnbottomrightpoint-cpoint (2, 2);
clienttoscreen (datargnrect);
// compute and erase the blank area. using the Marco. erase_bkgnd_begin;
add_noerase_rect (datargnrect);
erase_bkgnd_end (PDC, getbkcolor ();
return false;
}

Note: When clistctrl is pulling, the background will be refreshed with the background color before the meeting, and the items with data will be drawn on it, while the background color will be kept for areas without data. Therefore, if you simply return false in the bool cexlistctrl: onerasebkgnd (CDC * PDC) function, the area without data will be abnormal. Therefore, in example 2, we first calculate the items region with data, which is a region that does not need to be replayed with the background. Using the macro in this article can effectively avoid the flash of clistctrl during pulling.

 

From: http://www.cppblog.com/eday/archive/2007/03/19/20106.html

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.