MFC drawing picture Flicker in detail

Source: Internet
Author: User
Tags clear screen

How to draw effectively with MFC
Show how graphics avoid flickering, how to improve the display efficiency is a lot of questions asked.
And most people think that MFC's drawing function is inefficient, and is always looking for other solutions.
MFC's drawing efficiency is really not high but also not bad, and its drawing function is very simple to use,
As long as the use of the appropriate method, coupled with some techniques, MFC can be used to obtain a high efficiency of the drawing program.
I want to talk about my long-term (hehe of course also only 2 years) using MFC drawing Experience
Some of my points of view.
1. Why does the displayed graphics blink?
Most of our drawing processes are placed in OnDraw or OnPaint functions, OnDraw in the screen
is called by OnPaint when the screen is displayed. When the window needs to be redrawn for any reason,
Always use the background color to clear the display area before calling OnPaint, and the background color is often associated with the drawing content
The contrast is so large that the background color and the display graph alternately appear in a short period of time, making the display window look
In a flash. If you set the background brush to NULL, no matter how you redraw the graphic, it will not flash.
Of course, this will make the window display mess, because there is no background color when redrawing the original
The drawing is cleared, and a new shape is superimposed on it.
Some people will say that flashing is because the speed of the drawing is too slow or the graphics displayed are too complex to create,
In fact, this is not true, the display speed of the drawing of the effect of flicker is not fundamental.
For example, in OnDraw (CDC *PDC) This writes:
Pdc->moveto (0,0);
Pdc->lineto (100,100);
This drawing process should be very simple, very fast, but you will still see when the pull window changes
Flashing. In truth, the more complicated the process of drawing, the more slowly the flicker should be less, because the drawing
Time and the proportion of time spent in clearing the screen with the background the more the adults will feel the flicker is less obvious.
For example: clear screen time for 1s drawing time is also 1s, so that in 10s of continuous re-painting will flash
5 times, if the screen time is clear 1s, and the drawing time is 9s, so that the continuous re-painting in 10s
will only blink once. This can also be tested, in the OnDraw (CDC *PDC) write:
for (int i=0;i<100000;i++)
{
Pdc->moveto (0,i);
Pdc->lineto (1000,i);
}
Oh, the program is a bit perverted, but can explain the problem.
Speaking of which, there might be someone else to say, why a simple graphic doesn't look like a complex graphic.
Where's The flash? This is because the complex graphics occupy a large area, re-painting caused by the contrast is relatively large, so feel to
Flash a bit more, but the flicker frequency is low.
So why is the animation's redraw frequency high, but it doesn't look like it's flashing? Here, I'm going to stress again,
What is flashing? Flashing is the contrast, the greater the contrast, the more sharp flashes. Because the animation is between two frames in a row
The difference is small so it doesn't look like it's flashing. If you do not believe, you can add a white frame in the middle of each frame of the animation,
It's weird not to blink.

2. How to avoid flashing
After knowing the cause of the flicker in the graphics, the right remedy is good. First of all, of course, remove MFC
Provides a background drawing process. There are many ways to achieve this,
* You can pay NULL for the background brush of the window's registration class when the window is formed
* You can also modify the background after forming
Static CBrush Brush (RGB (255,0,0));
Setclasslong (This->m_hwnd,gcl_hbrbackground, (LONG) (hbrush) brush);
* To be simple or overload onerasebkgnd (cdc* PDC) directly returns True
So the background is gone, and the result is really not flashing, but the display is the same as before,
Become a mess. What to do? This will use the method of double caching. Double buffering is except on the screen
Graphics are displayed, and graphics are drawn in memory. We can draw the graphics that we want to display first in memory, and then once again make the in-memory graphics overlay to the screen one point at a time (the process is very fast, because it is a very structured memory copy). This way, when drawing in memory, it is not clear to use any contrasting background color, because it is invisible. When posted on the screen, because the final graphics in memory are very different from the onscreen graphics (if there is no movement, of course there is no difference), it does not look like a flash.

3. How to realize double buffering
First give the implementation of the program, and then explain, the same is in the OnDraw (CDC *PDC):
CDC MEMDC; First define a display device object
CBitmap membitmap;//defining a Bitmap object
A memory display device that is compatible with the screen display is then established
Memdc.createcompatibledc (NULL);
There is no drawing at this time because there is no place to draw ^_^
The following is a screen display compatible with the bitmap, as for the size of the bitmap, you can use the size of the window
Membitmap.createcompatiblebitmap (Pdc,nwidth,nheight);

To select a bitmap into a memory display device
Only the memory display device in which the bitmap is selected has a place to draw, drawing on the specified bitmap
CBitmap *poldbit=memdc.selectobject (&AMP;MEMBITMAP);
Clean the bitmap with the background color first, here I use white as background
You can also use the color you should use
Memdc.fillsolidrect (0,0,nwidth,nheight,rgb (255,255,255));
Drawing
Memdc.moveto (...);
Memdc.lineto (...);

Copy the in-memory diagram to the screen for display
Pdc->bitblt (0,0,nwidth,nheight,&memdc,0,0,srccopy);
Cleanup after drawing is complete
Membitmap.deleteobject ();
Memdc.deletedc ();
The comments above should be exhaustive, and the nonsense will not be said much.

4, how to improve the efficiency of the drawing
I mainly do is the Power system network Graphics CAD software, in a window often to display thousands of power components, and each component is composed of points, lines, circles and other basic graphics. If you really want to redraw so many components during a redraw process, it is conceivable that the process is very long. If you add a graphical browse function, the mouse drag graphics scrolling requires a lot of repainting, the speed will be slow so that users will be unbearable. What to do? Only after studying the drawing process of MFC.
In fact, the graphs drawn in OnDraw (CDC *PDC) are not all displayed, for example: you
Two rectangles were drawn in the OnDraw, although the drawing functions of both rectangles are executed in a single redraw, it is likely that only one is shown, because MFC itself sets the cropping area for the sake of improving the redraw efficiency. The role of the clipping zone is that only the drawing process in this area is really valid and is not valid outside the zone, even if the plotting function is not displayed outside the area. Because most of the window redraw is caused mostly because the window part is obscured or the window is scrolled, the changed area is not the entire graph but only a small part, this part needs to change is the cutting area in the PDC. Because the display (to memory or video is called display) than the calculation of the drawing process is much more time-consuming, with the clipping area after the display is just the part that should be displayed, greatly improving the display efficiency. But this clipping zone is set by MFC, it has improved the display efficiency for us, how to further improve the efficiency of the drawing of complex graphics? That's the only way to get rid of the drawing process outside the clipping area. You can first use Pdc->getclipbox () to get the clipping area, and then at the time of drawing to determine whether your graphic is in this area, if you are in the picture, do not draw.
If your drawing process is not complex, doing so may not improve your drawing efficiency

==============================================================================

In OnEraseBkgnd, if you do not call the original default
The ONERASEBKGND only redraw the background without blinking. And in OnPaint,
Because it implicitly calls the OnEraseBkgnd, and you're not dealing with OnEraseBkgnd
function, which is related to the window's default background brush. Default
OnEraseBkgnd operation use the default background of the window to brush the new background (general case
White brush), and then you re-draw the background yourself causing the screen to blink.
Another problem is that ONERASEBKGND is not always called. If you
Call Invalidate when the argument is true, then in the OnPaint inside the implicit
The WM_ERASEBKGND message is generated when the beginpaint is called, if the parameter
is false, the background is not re-brushed.

So the solution is three and a half:
1. Implement with ONERASEBKGND, do not call the original OnEraseBkgnd function.
2. Implemented with OnPaint, while overloading OnEraseBkgnd, which is returned directly.
3. Implement with OnPaint, set the background brush to empty when creating the window
4. Implemented with OnPaint, but requires invalidate (FALSE) when refreshing
The function. (However, in this case, the refresh caused by the window overlay is still going to flash a
Under, so not a thorough solution)
It's all quite simple.
------------------------------------------------------
The drawing of any window component in MFC is placed in these two member function
OnEraseBkgnd () is used to draw a basemap and OnPaint () is used to draw the main object.
For example, a button is gray and there's text on it.
What OnEraseBkgnd () does is to paint the button gray.
And what OnPaint () does is to draw words.

Since these two member function are used to draw components
So why divide OnPaint () and OnEraseBkgnd ()?
In fact, OnPaint () and onerasebkgnd () characteristics are poor
1. ONERASEBKGND () The requirement is that the quick in-process drawing program is best not to take too much time between
Because every time the window component has any small changes, it will call OnEraseBkgnd immediately.
2. OnPaint () is called only when the program is idle
3. OnEraseBkgnd () is called before OnPaint ()
So OnPaint () may call OnEraseBkgnd () several times before being called once


If we are a person who is working on a graphical user interface
We often need to set a beautiful picture as our dialog basemap.
Putting the program code of the drawing in the OnPaint () may often encounter some problems
Let's say drag a window on top of the dialog we're doing.
The dialog will turn gray until the action stops.
This is because the program will call ONERASEBKGND () every time a redraw is required.
OnEraseBkgnd () painted the dialog gray
The program calls OnPaint only after the action is stopped () and then the basemap we're going to paint is pasted up.


The way to solve this problem is to rewrite OnEraseBkgnd () into a function that does not work.
As shown below
BOOL cmydlg::onerasebkgnd (cdc* PDC)
{
return TRUE;
}
The above would have been called CDIALOG::ONERASEBKGND () but if we don't call,
The program will not draw a gray background.


It is good practice to move the drawing program directly from OnPaint () to OnEraseBkgnd () to do
As shown below

M_bmpbkgnd is a CBitmap object and has already loaded our basemap in advance
The size of the basemap is the same size as our window client


BOOL cmydlg::onerasebkgnd (cdc* PDC)
{
CRect RC;
GetUpdateRect (&RC);
CDC SRCDC;
Srcdc.createcompatibledc (PDC);
Srcdc.selectobject (M_BMPBKGND);

Pdc->bitblt (RC.LEFT,RC.TOP,RC. GetWidth (),
Rc. GetHeight (), &srcdc,rc.left,rc.top,srccopy);
return TRUE;
}

It is especially important to note that getting a redraw size is using getupdaterect () instead of GetClientRect ()
If you use GetClientRect (), repaint the place where it should not be redrawn.

MFC drawing picture Flicker in detail

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.