使用CPaintDC时减少闪烁

时间:2013-07-04 07:01:38

标签: visual-studio-2010 visual-studio visual-c++ mfc visual-c++-2010

我需要使用MFC制作交互式图表

它有点像均衡器控制,用户应该能够点击均衡器上的一个点来拖动它来改变它的y轴值

我也刚刚开始学习MFC

到目前为止,我已在CPaintDC函数中使用OnPaint()在对话框中绘制图形。目前,图形非常简单,矩形边框,填充白色,图形上有4个点。我使用OnMouseMove()函数来了解光标是否在图形区域内,OnLButtonDown()函数知道用户点击的位置。如果用户点击了一个意味着我想要更改该位置图形点的y轴值的位置,我会使用Invalidate()重新绘制该图并在OnPaint()内调用OnLButtonDown()。但是,每次图表必须更新时,我都会看到闪烁。它现在不是问题,但是我需要扩展这个图形,使它至少有64个可变点,能够通过拖动改变点的y轴值,而不是仅仅点击我想要的位置。随着我增加点数和图形外观的复杂性,闪烁问题会增加吗?该图表稍后需要有轴,网格线,标签等。闪烁的东西我应该关注吗?有什么方法可以阻止它吗?

----更新----
这就是我根据我对CodeDreamer建议的理解来更新我的OnPaint()函数的方法

void Cgraph_on_dlgboxDlg::OnPaint()
{
     CPaintDC dc_blt(this);
     CDC dc;
     CBitmap bmpDC;

     CRect rcClient;
     GetClientRect(rcClient);

    if (IsIconic())
    {
        // CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }

     dc.CreateCompatibleDC(&dc);
     bmpDC.CreateCompatibleBitmap(&dc, theGraph.width,theGraph.height );
     dc.SelectObject(&bmpDC);

    CPen pen;
    COLORREF pencolour = RGB(0, 0, 0);
    COLORREF brushcolour = RGB(0, 0, 255);
    COLORREF graphColour = RGB(0, 0, 150);

    // Draw boarder
    pen.CreatePen(PS_SOLID, 3, pencolour);
    // CBrush brush(HS_CROSS, brushcolour);
    dc.SetBkMode(TRANSPARENT);
    dc.SetMapMode(MM_TEXT);
    dc.SetViewportOrg(theGraph.x1, theGraph.y1);
     dc.SelectObject(&pen);

    // Draw graph boundary
    CPoint point1(0,0);
    point1.x = 0;
    point1.y = 0;
    CPoint point2(0,0);
    point2.x = point1.x + theGraph.width;
    point2.y = point1.y + theGraph.height;
    dc.Rectangle(CRect(point1, point2));
    pen.DeleteObject();

    // Draw Horizontal at 0
    pen.CreatePen(PS_SOLID, 1, pencolour);
    dc.SelectObject(&pen);
    dc.MoveTo(0, theGraph.height - ORG_DIST_FROM_BOTTOM);
    dc.LineTo(theGraph.width, theGraph.height - ORG_DIST_FROM_BOTTOM);
    pen.DeleteObject();

    dc.SetViewportOrg(theGraph.x1, theGraph.y1 + theGraph.height - ORG_DIST_FROM_BOTTOM); // dc.SetViewportOrg() always works relative to the clinet origin

    // Draw graph line
    pen.CreatePen(PS_SOLID, 2, graphColour);
    dc.SelectObject(&pen);
    for(int i = 0; i<NUM_OF_SECTIONS_IN_GRAPH; i++){
        dc.MoveTo(graphSamplePoints[i].x, graphSamplePoints[i].y);
        dc.LineTo(graphSamplePoints[i+1].x, graphSamplePoints[i+1].y);
    }

    // draw circles at graph sample points
    for(int i = 0; i<NUM_OF_POINTS_IN_GRAPH; i++){
        CIRCLE(dc, graphSamplePoints[i].x, graphSamplePoints[i].y, GRP_SMP_RAD);        
    }

    // dc_blt.BitBlt(0,0,rcClient.Width(), rcClient.Height(), &dc, 0, 0, SRCCOPY);
    dc_blt.BitBlt(theGraph.x1,theGraph.y1,theGraph.width, theGraph.height, &dc, 0, 0, SRCCOPY);

}

我需要多次更改视口的来源,我的猜测是这可能是错误的原因之一。欢迎提出任何建议 这是我的输出看起来没有双缓冲的情况 enter image description here
这是我尝试双缓冲时的样子

enter image description here

2 个答案:

答案 0 :(得分:1)

在这种情况下,一般的解决方案是“双缓冲”。 原理是它可以提前创建一个兼容的内存直流用于绘图,当绘图结束时,它会在屏幕直流输出。

代码示例如下。

//in OnPaint() function
CPaintDC dc(this);    
CDC dcMem;
CBitmap bmpDC;

CRect rcClient;
GetClientRect(&rcClient);

dcMem.CreateCompatibleDC(pDC);
bmpDC.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());
dcMem.SelectObject(&bmpDC);

CRect rect(0, 0, 100, 200);
dcMem.Rectangle(rect);

dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);

下面有几个参考文献。

introduction

another reference

我希望这对你有所帮助。

答案 1 :(得分:0)

尝试CMemDC MFC课程。

在OnPaintFunction中你会得到:

  CPaintDC   DC(this);
  CMemDC mDC(&DC, this);
  // now use mDC instead of DC

另请查看here更多样本和解释。