约定:红色字体显示为重点阅读/////红色加大字体(中号字体)显示为最重点阅读
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://topic.csdn.net/u/20080620/15/1D8E30FD-584A-4551-B93A-DA97D5F6423C.html#r_50392023
Mackz:正如我猜想的,因为你调用了CDialog::OnPaint();
你把这句注释掉就可以了。
所以说凡事总有因果,CDialog::OnPaint()调用默认的窗口过程来绘制,也会调用BeginPaint/EndPaint()。而这两个函数的作用,是获取DC、剪裁区域和从消息队列中移走WM_PAINT消息。这两个函数,必须在WM_PAINT消息中调用,而且只能调用一次!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://topic.csdn.net/u/20100801/11/40897468-807e-445a-a817-ede00dfd406e.html
xxd_qd:如果自己的OnPaint代码什么也没做的话(至少没有声明过CPaintDC类型的变量),还必须调用一下CDialog::OnPaint,否则BeginPaint和EndPaint就没有办法被调用了。总之,在响应WM_PAINT消息的时候,必须调用一遍BeginPaint和EndPaint。调用的方法有三种:
1、声明一个CPaintDC类型的变量(即使你什么也不画),CPaintDC的构造函数就是调用BeginPaint,析构函数就是调用EndPaint。
2、调用基类的OnPaint(实际上就是调用API的DefWindowProc,它会自动调用BeginPaint和EndPaint)。
3、自己直接调用BeginPaint和EndPaint。
上述三种方法,必须选择其一,而且也只能选择其一(因为在一个WM_PAINT消息内不能调用两次BeginPaint和EndPaint)。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://topic.csdn.net/t/20050122/18/3746336.html
eachout:
eachout:
补充一下,空刷子和空EreaseBKnd的方法还有一个办法可以解决刷新的问题,就是在所有有可能导致背
景刷新的消息处理中手动刷新控件,比如Invalidate()。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://topic.csdn.net/u/20090512/22/D770F0DE-7412-4C93-A56A-D6A0038F9244.html
A:如果有一个父窗口,在这个父窗口上有很多控件,例如自定义按钮对象,自定义的画图区域对象,
当我对这些控件进行了类似InvalidateRect处理,那么对于父窗口是不是也会触发
wm_paint消息,还是说只会对控件本身产生wm_paint,
如果我在父窗口进行了类似InvalidateRect处理,那么会不会把消息对孩子传递下去,使父窗口和所有的
孩子控件都进行重新绘制。
cnzdgs:刷新子窗口通常不会导致父窗口刷新,除非子窗口在刷新过程中主动刷新其父窗口。
刷新父窗口时,如果父窗口具有WS_CLIPCHILDREN风格,则不会引起子窗口刷新,否则会刷新该区域内的子窗口。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://topic.csdn.net/u/20090312/19/18218E18-A8EE-422A-B335-7747097BA040.html
A:窗口是使用标准API创建的。主窗口内包含若干子控件,其中有一个Picture Control。
如果能处理这个(Picture Control)子控件的WM_PAINT消息呢?
因为不光这个控件有WM_PAINT消息,其它子控件也有可能有WM_PAINT消息,我如何区分这个WM_PAINT消息是由Picture Control产生的?
case WM_PAINT:
if(GetDlgCtrlID(hwndDlg)==IDC_DVC_VCPIC)
{
//这里执行重画
}
//意思就是,如果控件ID是Picture control的话则执行自己的重绘代码。
xiaopoy:windows提供的纯粹控件可以认为是没有自己的消息循环的,只相当于一个中转。
PAINT放主窗口的消息循环中中处理即可。
根据无效区域判断所属的窗口,win下没有这种API。但控件隶属主窗体的范围,它需要重绘时主窗体的消息循环都可以接收到PAINT。
必须只在图片无效时才重绘可以自己获取无效区域的范围,以及得到目标控件的范围并判断。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://topic.csdn.net/u/20091012/14/2B948708-6D7B-498A-9806-A2ADBD000C5D.html
A:OnEraseBkGnd与OnPaint的联系是什么?
Tr0j4n:问题是这样产生的.在OnEraseBkGnd中,如果你不调用原来缺省
的OnEraseBkGnd只是重画背景则不会有闪烁.而在OnPaint里面,
由于它隐含的调用了OnEraseBkGnd,而你又没有处理OnEraseBkGnd
函数,这时就和窗口缺省的背景刷相关了.缺省的
OnEraseBkGnd操作使用窗口的缺省背景刷刷新背景(一般情况
下是白刷),而随后你又自己重画背景造成屏幕闪动.
另外一个问题是OnEraseBkGnd不是每次都会被调用的.如果你
调用Invalidate的时候参数为TRUE,那么在OnPaint里面隐含
调用BeginPaint的时候就产生WM_ERASEBKGND消息,如果参数
是FALSE,则不会重刷背景.
所以解决方法有三个半:
1.用OnEraseBkGnd实现,不要调用原来的OnEraseBkGnd函数.
2.用OnPaint实现,同时重载OnEraseBkGnd,其中直接返回.
3.用OnPaint实现,创建窗口时设置背景刷为空
4.用OnPaint实现,但是要求刷新时用Invalidate(FALSE)这样
的函数.(不过这种情况下,窗口覆盖等造成的刷新还是要闪一
下,所以不是彻底的解决方法)
都挺简单的.
------------------------------------------------------
在MFC中 任何一个window组件的绘图 都是放在这两个member function中
在设定上 OnEraseBkgnd()是用来画底图的 而OnPaint()是用来画主要对象的
举例说明 一个按钮是灰色的 上面还有文字
则OnEraseBkgnd()所做的事就是把按钮画成灰色
而OnPaint()所做的事 就是画上文字
既然这两个member function都是用来画出组件的
那为何还要分OnPaint() 与 OnEraseBkgnd() 呢
其实OnPaint() 与 OnEraseBkgnd() 特性是有差的
1. OnEraseBkgnd()的要求是快速 在里面的绘图程序最好是不要太耗时间
因为 每当window组件有任何小变动 都会马上呼叫OnEraseBkgnd()
2. OnPaint() 是只有在程序有空闲的时候才会被呼叫
3. OnEraseBkgnd() 是在 OnPaint() 之前呼叫的
所以 OnPaint()被呼叫一次之前 可能会呼叫OnEraseBkgnd()好几次
如果我们是一个在做图形化使用者接口的人
常会需要把一张美美的图片设为我们dialog的底图
把绘图的程序代码放在OnPaint() 之中 可能会常碰到一些问题
比方说拖曳一个窗口在我们做的dialog上面一直移动
则dialog会变成灰色 直到动作停止才恢复
这是因为每次需要重绘的时候 程序都会马上呼叫OnEraseBkgnd()
OnEraseBkgnd()就把dialog画成灰色
而只有动作停止之后 程序才会呼叫OnPaint() 这时才会把我们要画的底图贴上去
这个问题的解法 比较差点的方法是把OnEraseBkgnd() 改写成不做事的function
如下所示
BOOL CMyDlg::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
以上本来是会呼叫CDialog::OnEraseBkgnd() 但是如果我们不呼叫的话
程序便不会画上灰色的底色了
比较好的做法是直接将绘图的程序从OnPaint()移到OnEraseBkgnd()来做
如下所示
// m_bmpBKGND 为一CBitmap对象 且事先早已加载我们的底图
// 底图的大小与我们的窗口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;
}
特别要注意的是 取得重画大小是使用GetUpdateRect() 而不是GetClientRect()
如果使用GetClientRect() 会把不该重画的地方重画
adrom:首先,tr0j4n是好心人,写得这么长。但好像不对哦。
应该是这样的吧,当Windows确定客户区需要重绘时,它首先发送WM_ERASEBKGND消息给窗口过程,由WM_ERASEBKGND消息的默认处理用白色画刷刷除背景,然后再发送WM_PAINT消息给窗口过程,由WM_PAINT消息的响应程序负责绘画客户区内容。或者说,当Windows确定客户区需要重绘时,它分别发送WM_ERASEBKGND和WM_PAINT消息,由这两个消息的响应程序分别负责刷除背景和重画客户内容。
至闪烁的问题,是由于刷除背景以后,在WM_PAINT未执行完成之前,windows已把视频卡的缓存输出到屏幕上了。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一般来说,自己的程序会有一个主窗口,然后里面可能又有很多子窗口,现在的问题出来了,一般来说,每一个窗口都是有它自己的窗口过程函数的,但是为什么在我们实际编写sdk程序的时候,只有一个过程函数呢?难道所有的窗口都共享一个过程函数?
=====================
你自己注册的窗口处理程序只是你自己写的主窗口来用,子窗口一般都是系统已经注册好的了,它有自己内置的窗口处理函数。
还有就是窗口的重绘问题,onpaint消息一般是发给主窗口的,那么,发给子窗口的那些onpaint消息呢?他们是怎么处理的呢?
========================================
WM_PAINT消息并不是只发给主窗口,哪个窗口出现无效区就会向哪个窗口发WM_PAINT消息,发给子窗口的WM_PAINT消息当然由子窗口自己的窗口处理函数来处理了。
那我的问题是,比如我在主窗口里面加入了一个按钮,这个是windows已经注册的窗口类了,也就是不需要我再提供一个窗口处理函数给它了,windows已经有默认的了,但是奇怪的是,比如我按了按钮,怎么会在主窗口里面收到消息的呢?纳闷
==================================
按钮是系统注册好的,它自己有窗口处理函数,你按了一下之后,按钮这个窗口的内部处理函数会向它所在的父窗口发送WM_COMMAND消息,这个消息是按钮自己发送给主窗口的。