问题描述:
在MFC中在对话框上绘图时, 要求按下按钮绘制相关图形, 写好绘制函数调用调试时,发现若是改变对话框的界面大小或者最小化/最大化或者有隐藏时会导致图形消失。
原因分析:
改变对话框的界面大小或者最小化/最大化或者有隐藏时会让整个对话框重新加载,而控件是会自己显示的,而手动绘制的图形则不会重新绘制,因此需要做这样一个事情:在改变对话框的界面大小等操作时,对要画的图形做一次重绘。
解决方法:
针对这些问题,MFC有自己的重绘机制来解决,即ON_WM_PAINT消息和OnPaint函数。
当对话框进行某些特定操作引起对话框重绘时,会发送WM_PAINT消息, ON_WM_PAINT可以捕获此消息,并自己调用OnPaint()函数来实现对某些要素图形的重新绘制;如此,只需要把要绘制的内容写进OnPaint()函数里面,并且在消息队列里加上ON_WM_PAINT即可时候特定操作下的重绘来保证图形一直显示在界面上。
代码如下:
BEGIN_MESSAGE_MAP(CDlg, CDialogEx)ON_WM_PAINT()
END_MESSAGE_MAP()void CDlg::OnPaint()
{CPaintDC dc(this);CPen pen;pen.CreatePen(PS_SOLID,10, RGB(0, 0, 0));Dc.SelectObject(pen);Dc.MoveTo(0, 0);Dc.LineTo(20, 20);
}
需要注意的是,如果绘图设备不使用CPaintDC,则会引起onpaint在没有操作的情况下也一直重绘的问题,关于这个问题的原因引用自:OnPaint不停刷新的问题_wuzoujing的博客-CSDN博客自定义控件响应WM_PAINT消息,在OnPaint中,默认有CPaintDC dc(this); 如果注释掉CPaintDC dc(this);则程序不停地刷新(计数器不停地飞涨!!),可是如果保留CPaintDC dc(this);,如下: void COpenGLControl::OnPaint() { CPaintDC dc(this); // device contexthttps://blog.csdn.net/wuzoujing/article/details/4942470
大概原因是:
CPaintDC为窗口的OnPaint函数所使用的设备环境类。该类的构造函数会自动调用BeginPaint函数,析构函数自动调用EndPaint函数。BeginPaint函数的作用就是将窗口需要重绘的区域设置为空(也就是Update Region置空)。在正常情况下,我们接收到了WM_PAINT消息后,窗口的Update Region都是非空的(如果为空就不需要发送WM_PAINT消息了)。而当你响应这个消息的时候又不调用BeginPaint来清空,窗口的Update Region就一直是非空的,系统就会一直发送WM_PAINT消息。这样就形成了一个处理WM_PAINT消息的死循环。
如上便是自动重绘的过程, 若要使得按下按钮才开始绘制,并且在改变大小窗口后仍然显示图形的话,我是如下操作:
BEGIN_MESSAGE_MAP(CDlg, CDialogEx)ON_BN_CLICKED(IDOK, &CDlg::OnBnClickedOk)ON_WM_PAINT()
END_MESSAGE_MAP()void CDlg::OnBnClickedOk()
{m_needDraw = true; //此处m_needDraw是成员变量, 用来判断是否按下按钮Invalidate(); //使得客户区无效, 进行一次重绘
}void CDlg::OnPaint()
{CPaintDC dc(this);if(m_needDraw==false)return;CPen pen;pen.CreatePen(PS_SOLID,10, RGB(0, 0, 0));Dc.SelectObject(pen);Dc.MoveTo(0, 0);Dc.LineTo(20, 20);
}