OnPaint 更新太频繁

Posted

技术标签:

【中文标题】OnPaint 更新太频繁【英文标题】:OnPaint is updated too often 【发布时间】:2013-08-12 09:08:36 【问题描述】:

我对 CFrameWnd 的 OnPaint 方法有疑问,我似乎无法弄清楚发生了什么。 OnPaint 大约每 10 毫秒调用一次,这会导致计算机死机。检查CPU使用率,这个应用程序占用了50%!

该应用程序是一个非常简单的 MFC 应用程序,它写在一个文件中。

// Includes are done here...

class MFC_Tutorial_Window : public CFrameWnd

std::string data;

public:
    MFC_Tutorial_Window()
    
         this->data = "";
         Create(NULL, "Data Win");  // Create window
    

    void OnPaint()
       
        CDC* pDC = GetDC();

        CString s = CString(this->data.c_str());
        RECT rc;

        HWND hwnd = this->m_hWnd;
        if(hwnd != NULL) 
            ::GetWindowRect(hwnd, &rc);

            rc.top = rc.bottom/2;

            if(pDC != NULL && pDC->m_hDC != NULL) 
                pDC->DrawText(s, &rc, DT_CENTER);
            
        
    

    void UpdateWithNewData(std::string up) 
        this->data = up;
        Invalidate();
    


    DECLARE_MESSAGE_MAP()
;

BEGIN_MESSAGE_MAP(MFC_Tutorial_Window, CFrameWnd)
    ON_WM_PAINT()       
END_MESSAGE_MAP()

// App class
class MyApp :public CWinApp

    MFC_Tutorial_Window *wnd;

    BOOL InitInstance()
    
        wnd = new MFC_Tutorial_Window();
        m_pMainWnd = wnd;
        m_pMainWnd->ShowWindow(3);

                       wnd->UpdateWithNewData("Hello world!");          
             return 1;
    
;

有人知道为什么 OnPaint 会被系统发送垃圾邮件吗?一直盯着这段代码很久了,我就是找不到。

【问题讨论】:

请注意,您几乎总是希望使用 View 类,在这种情况下,您在 OnDraw 中进行绘图,框架会处理导致当前问题。 【参考方案1】:

必须调用 CPaintDC 析构函数才能重置重绘标志。您需要在您的CDC 上调用beginPaint();endPaint();,这实际上应该更改为CPaintDC。更重要的是,不调用endPaint(); 无论如何都会导致上下文被重新绘制。

【讨论】:

非常感谢!现在就像一个魅力! :D @Phoenix 不错!很高兴我能帮忙:) EndPaint 似乎清除了我想绘制的区域。有没有办法确保绘制的区域保持不变,直到下一次我想重绘,并且仍然保持 EndPaint? @Pphoenix CPaintDC::m_ps 有一个 rcPaint 成员来保存更新区域。您可以在拨打EndPaint 后拨打InvalidateRect。但这会使您回到最初问题的相同情况。你能更详细地解释你想要达到的目标吗? @Pphoenix 我误读了您的问题,我猜您指的是 contents,而不是区域。为防止擦除背景,您可以覆盖 CWnd::OnEraseBkgnd 并将实现留空。无论您返回 0 还是非零值都没有区别。【参考方案2】:

只要消息队列中没有其他消息并且窗口的更新区域(请参阅InvalidateRect)非空,就会生成WM_PAINT 消息。当处理WM_PAINT 消息时,应用程序会通过调用EndPaint 发出更新区域已被重新绘制的信号。未能调用EndPaint 不会将更新区域标记为已处理,因此下次应用程序请求消息时,WM_PAINT 是有效的候选者。

在 MFC 中,调用 BeginPaintEndPaint 的功能封装在 CPaintDC Class 中。 WM_PAINT 的标准 MFC 消息处理程序如下所示:

void OnPaint()

    CPaintDC dc(this);  // calls BeginPaint()
    // Perform rendering operations on dc
    // ...
 // CPaintDC::~CPaintDC() calls EndPaint()

有关使用设备上下文的更多详细信息,请访问Device Contexts。

【讨论】:

以上是关于OnPaint 更新太频繁的主要内容,如果未能解决你的问题,请参考以下文章

MFC中ONPAINT、ONDRAW、ONERASEBKGND等绘图函数的使用场合和作用、区别是啥啊?

为啥在 UI 线程上输入锁会触发 OnPaint 事件?

MFC OnPaint()函数中最先调用CDialog::OnPaint()和最后调用CDialog::OnPaint()的巨大区别

通过单击按钮调用 onPaint()

MFC OnPaint被不断调用的问题

OnPaint 自定义渲染