MFC "MFC" Draws a dynamic curve, using double-buffered drawing technology to prevent flicker

Source: Internet
Author: User
Tags textout

Excerpt from: http://zhy1987819.blog.163.com/blog/static/841427882011614103454335/

MFC draws dynamic curves and uses double-buffered drawing techniques to prevent flicker

2011-07-14 10:34:54|  Category: Learning Notes | Tags: double buffering drawing technology MFC Dynamic Curve | report | font size Subscription

First, as time goes on, the curve shifts to the right, while the x-axis time coordinates are updated accordingly. First, how to draw the dynamic curve.

The so-called animation, is a frame of the image of a continuous display in front of the user formed. So if you have mastered how to draw a static curve, then learn to draw the dynamic curve is not far away, just need to create a timer (such as calling MFC Settimmer function), every time (such as 1ms), call OnPaint or OnDraw function, draw the current frame image can be.
It is important to note that the code that paints the image needs to be written in the OnPaint or OnDraw function, because when the window is invalidated (such as minimized), the current window is redrawn and the self-plotting image before the window is lost. and write the drawing code in OnPaint or OnDraw in order to let the window redraw each time can also redraw the image of your own painting, to avoid the window to minimize the recovery after the image of their own picture lost embarrassing situation.
In addition to drawing the current frame image, remember to use the InvalidateRect function to clear the previous frame image, or the frame image will be stacked background.
For example, I want to clear the image in the window (0,0) and (100,100) the two-point rectangle, the code is as follows: CRect Rect;    rect.top = 0;    Rect.left = 0;    Rect.bottom = 100;    Rect.right = 100; InvalidateRect (Rect); According to the above idea, we draw an image every time, but if each drawing is exactly the same, then the image looks static. How do you make the curve move up? We need to design an input for the code of our own drawing, that is, the coordinate information of each point on the curve at the current moment. As time goes on, the coordinates of each point on the curve change so that each drawing is drawn based on the current moment's curve coordinates, controlling the change in the coordinate of the curve and allowing the curve you draw to move nicely.

The above refers to the coordinates of the points on the curve, this information can be stored in a variety of data structures, but I recommend the use of STL deque data structure storage. Why is it? The need to decide the choice. Let's first think about what we need to do with this data in the process of drawing an image.
1, needs to traverse this data, obtains the coordinates of each point to draw, therefore the choice data structure must have the high traversal efficiency.
2. When the point on the curve is horizontally filled with the display range provided by the horizontal axis, you need to remove the coordinates of the rightmost point of the curve, and then add the coordinates of the next new point on the leftmost side of the curve to achieve the effect of translating the curve to the right. So the data structure you choose needs to support the addition and deletion of front-end and back-end elements, so it's natural to think of queues.
The list container in the STL can also easily implement the queue function, but the list also supports the addition and deletion of arbitrary location elements, the redundancy of the function determines that the list takes more time to achieve our requirements, in fact traversing a deque is often dozens of times times faster than traversing a list, The reason is not to dwell on it here.

So, the author constructs this kind of data structure deque<pair<time, value>> m_dqdisplaydata; Each element in the queue is a pair,pair that holds the coordinates. The core code for maintaining this data structure is as follows:

If the queue length exceeds the number of all points that can be plotted in the x-axis direction if (M_dqdisplaydata.size () >= xpointnum) {
Remove the coordinates of the front of the queue M_dqdisplaydata.pop_front ();
Add a new coordinate M_dqdisplaydata.push_back (Make_pair (time, value)) at the back end of the queue.    M_dqdisplaydata.push_back (Make_pair (Tiem, value)); }

Here's how to get a static curve moving, and here's a description of the main skills for drawing a static image.

1, drawing first need to find a painter, MFC is so to get a painter.
CDC *PDC = GetDC ();
Remember the painter finished painting this frame image, send him to leave, idler we can't afford to raise.
That is, you must use the ReleaseDC (PDC); Release the resource, otherwise it will cause a memory leak because GetDC (); The function is assigned some resources that are associated in the memory that the PDC points to, and if ReleaseDC is not called, when the PDC is out of scope, Just the PDC this 32-bit pointer variable (which can also be said to be an integer variable) of memory is freed up, and the memory that the PDC points to has no chance of being freed. Here also reflects a principle of MFC, get to need release after, these two functions are often paired definition good.

In addition, GETDC and ReleaseDC are the member functions of CWnd, we need to draw on which window, in that window class of OnPaint or OnDraw function to create a painter who will draw in the window, in fact, GetDC implicit operation is to create a painter, Give the painter the drawing area of the window where you are, and then return the painter to the user. When we build the CDC object directly (for example: CDC MEMDC;), we need to use other methods (such as the SelectObject function) to select the paper for it. 2, the painter before drawing, first must prepare the drawing tool.
MFC provides many drawing tools, such as brushes (CBrush), brushes (CPen), and so on. (hehe, actually I also did not use several)
The following is an example of a solid line, a width of 1, a color of RGB (0, 128, 64) Brush CPen Penfordrawaxis (ps_solid, 1, RGB (0, 128, 64));
The painter uses SelectObject skills to hold the brush in his hand pdc->selectobject (Penfordrawaxis);

Another point: If you need to call Penfordrawaxis.deleteobject () when the brush is no longer in use, the issue of releasing resources is different on the Internet. In each major book, the authors often subconsciously explicitly invoke the DeleteObject function to reflect the action of releasing the resource.

If you need to release memory resources in a timely manner, clearing the barrier for subsequent programs, the explicit invocation of the DeleteObject function is no problem. I suspect, however, that if you do not call the DeleteObject function, the resources allocated by the CPen object cannot be freed, which can cause a memory leak.

Because the resources of the CPen object are allocated in the constructor, naturally there should be a corresponding deallocation function in its destructor, because as an MFC user, when using CPen, it is not known whether the resources that need to be explicitly freed are assigned. The object should be responsible for itself and should not be handed over to the user for redundancy, which is the basic principle of designing C + + classes. The popular saying is, oneself did what good self psychology clear, leave of time oneself to clean up. Microsoft doesn't bullying in code (though it's often rogue elsewhere).

The exact words on MSDN are: When an application no longer requires a given pen, it should call the CGdiObject::D eleteobject member function or destroy the CPen object so the resource are no longer in use. An application should isn't delete a pen when the pen was selected in a device context.
To release CPen resources, Microsoft has pointed to us two Ming Road, the first is: Call the CGdiObject::D eleteobject member function, the second is: Destroy the CPen object. What is destroy the CPen object, one way is to let the object out of scope, and automatically call the destructor to terminate itself.
It can be seen that the CPen object frees up resources even if it does not call DeleteObject, while destroying itself out of scope by C + +.

Pull away, pull away ... Continue below.

3, the painter began to swipes ~
Move the pen to (60,220) The position indicated by this coordinate (just select place, not pen) Pdc->moveto (60, 220);
Pull the pen on the paper from (60,220) to (520,550), a straight line was born Pdc->lineto (520, 220);
Move the pen on paper from (520,220) to (510,223), and another line leap off Pdc->lineto (510, 223);

How can you only draw a straight line?
What is a curve? It's just an endless line of small pieces.

In addition, MoveTo and LineTo do not need to appear in pairs, generally a continuous curve only need to call once moveto.

Second, how to use double buffering technology to prevent screen flicker

The above shows how to draw a dynamic curve, but the problem of flickering is often seen when the dynamic curve is drawn.

No matter what the language of the frame drawing, the root cause of the flicker is that the picture is inconsistent.

Perhaps you have to ask, every time I draw a frame of the image is just on the basis of the frame image changes a little bit, how is not coherent. That's true, but don't forget that we've also called InvalidateRect to clear the previous frame before we draw each frame, so the so-called clear is to fill the specified rectangular area with the default background color of the window, which is equivalent to a solid background of blot for every two frames of images.

Finally, we think of a way, do not use InvalidateRect to clear the previous frame of the image, directly re-invite a painter who will draw in memory, draw the frame image in memory of a new paper, and then draw on the window painter using his ultimate skill bool BitBlt (int x , int y, int nwidth, int nheight, cdc* psrcdc, int xsrc, int ysrc, DWORD dwrop); The paintings in the hands of the honest painter who paints in memory are copied directly (it's shameful, but it works). So, the problem is solved, love to pack B's program to this method took a very windy name------double buffering technology.

This approach involves the following key skills:
1, who will draw on the memory?    Create an artist who will draw in memory CDC MEMDC; Memdc.createcompatibledc (NULL);

2. What kind of new paper is in memory?    Create an in-memory sheet CBitmap membitmap; Membitmap.createcompatiblebitmap (PDC, 800, 600);
Why is there a PDC in the current window class that gets passed GetDC?
Because CreateCompatibleBitmap Initializes a bitmap that is compatible with the device context specified by the PDC, the bitmap has the same number of color bits or the same number of bits per pixel as the specified device context. You can try, if the incoming &AMP;MEMDC here, finish the finished, painter how to draw, the picture is gray lines, depressed dead.
As for the following two parameters of the CreateCompatibleBitmap, specify the size of the drawing, specifically, you can determine the size of your own window, such as the actual situation, big does not matter, use the back of the copy can be intercepted when the specified size.    3, how to let the painter draw on this piece of paper? Hehe, Jiangzi is done ~ memdc.selectobject (&AMP;MEMBITMAP);

4. How does an in-memory painter draw?
Exactly the same, just MEMDC in swipes.     Memdc.moveto (60, 220);    Memdc.lineto (520, 220); Memdc.lineto (510, 223);
Yes, the warm hint, most people want to fill the specified rectangular area with a color, because invalidaterect is dry, you squeeze people down, nature this thing you have to do.
Memdc.fillsolidrect (0, 0, 580, +, RGB (1,4,1));
The above function indicates that a rectangle with a color of RGB (1,4,1), a length of 580, and a width of 250 is drawn as the upper-left coordinate of the rectangle in the (0,0) position of the sheet, which is the top-left corner of the drawing. Size what you don't have to be too tangled, according to their own window size, try several sizes and coordinates, you can find the most appropriate parameters.
It is important to note that MEMDC is drawing on membitmap, so the coordinates that the MEMDC call function passes in are membitmap the coordinates on the sheet, not the coordinates on the window.    4, how to let the painter in the window camp directly from the memory painter hand copy drawings? The following function means: On the memdc hand of the paper, with (0,0) as the upper-left corner of the rectangle box coordinates, pull a long 580, a width of 250 copy of the Rectangle box, the box inside the frame of the image copied to the window, copy the upper left corner of the rectangle and the window (20,50) coincident.    580,250 determines the size of the Copy box, (0,0) determines the position of the Copy box on the Membitmap, and (20,50) determines the position of the Copy box on the window. Pdc->bitblt (580, &AMP;MEMDC, 0, 0, srccopy);

The following is part of the drawing code, removed a lot of peripheral features, if not careful to delete what also please everyone haihan, mainly to keep a look at the idea and framework.

1, draw the function of the axis, you see, I just let "memory Painter"---memdc painting, said with a double cushion oh, hehe.     void Cxxxdlg::D rawaxis (CDC &memdc, LPTSTR Titleforx, LPTSTR titlefory)     // Select the paint axis brush     cpen Penfordrawaxis (ps_solid, 1, RGB (0, +));    memdc.selectobject ( Penfordrawaxis);    //plot x axis     memdc.moveto (.);    memdc.lineto ( 520,;    //draw arrows     memdc.lineto (510, 223);    memdc.lineto (510, 217);    memdc.lineto (520);    //draw y-axis     memdc.moveto (60, 220);     memdc.lineto (;  )  //draw arrows     memdc.lineto (max.);     memdc.lineto (;  )  memdc.lineto;    //Set the color of the text     colorref Oldcolor = Memdc.settextcolor (RGB (255, 255, 0));    //Draw Callout      Memdc.textout (480, Titleforx);  &nBsp  memdc.textout (titlefory);    //Restore text color     memdc.settextcolor (oldcolor); 2, drawing example of the function void Cxxxdlg::D rawlegend (CDC &memdc, CPen &penfordraw, CPen &penfordrawab, CPen &penfordrawbe)     //Set the color of the text     colorref oldcolor = Memdc.settextcolor (RGB (0, +));   & nbsp;//Drawing Legends     memdc.selectobject (Penfordraw);    memdc.textout (530, _T, "Global" ));    memdc.moveto (530,);    memdc.lineto (570,);     Memdc.selectobject (penfordrawab);    memdc.textout (530, _t ("AB"));     Memdc.moveto (530,;  )  memdc.lineto (570);    memdc.selectobject (PenForDrawBE) ;    memdc.textout (530, _t ("be"));    memdc.moveto (530,  );   Memdc.lineto (570,;  )  //restore text color     memdc.settextcolor (OldcoloR);}

3, draw the function of the curve void Cxxxdlg::D rawdynamiccurve (CDC &memdc, CPen &pen, Deque<pair<time, Value>> & Displaydata, double proportion)     //Select Brush     memdc.selectobject (Pen);    //entering the critical section     entercriticalsection (& (m_ccontrollingparameters.m_ccriticalsection));     //plot curve     if (displaydata.size () >= 2)         coordinate XPos = 6 0;        for (UINT PointIndex = 1; PointIndex! = displaydata.size ();             pointindex++)             memdc.moveto (xpos++, +-(coordinate) ((double) (Displaydata[pointindex-1].second)/ Proportion);            memdc.lineto (XPos, +-(coordinate) ((double) (displaydata [Pointindex].second]/proportion));    //leave the critical section     leavecriticalsection (& (m_ Ccontrollingparameters. m_ccriticalsection));    //Restore text color     memdc.settextcolor (oldcolor);}

4, the emphasis comes, the OnPaint function, has the double buffering technology the main course void Cxxxdlg::onpaint () CDC *PDC = GetDC ();    Create an in-memory display device CDC MEMDC;     Memdc.createcompatibledc (NULL);    Create an in-memory image CBitmap Membitmap;    Membitmap.createcompatiblebitmap (PDC, 580, 250);    Defines various types of brushes CPen penfordraw (ps_solid, 1, RGB (0, 232, 255));    CPen penfordrawab (ps_solid, 1, RGB (0, 98, 0));    CPen Penfordrawbe (ps_solid, 1, RGB (221, 0, 221));     Specifies that the memory display device is drawing Memdc.selectobject (&membitmap) on an image in memory; Use a color as the background color of the memory display device first
Memdc.fillsolidrect (0, 0, 580, +, RGB (1,4,1));    Draw Axis Drawaxis (MEMDC, _t ("Time (s)"), _t ("Length (kbit)"));    Draw the legend Drawlegend (MEMDC, Penfordraw, Penfordrawab, PENFORDRAWBE);    Draw Curve Drawdynamiccurve (MEMDC, Penfordraw, M_dqdisplaydata, 1000);     Copy the image in memory directly to the designated area on the screen pdc->bitblt (0, 0, 580, &AMP;MEMDC, srccopy); Release related Resources ReleaseDC (PDC);
}

MFC "MFC" Draws a dynamic curve, using double-buffered drawing technology to prevent flicker

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.