在做界面开发时,相信大家都遇到过界面闪烁问题。一般有一下几种情况:
1、 移动窗口
2、 在窗口上绘制大量的图片
3、 在绘制子窗口
以上3种情况是窗口出现闪烁概率比较高(不是说一定会出现,主要看CPU的处理速度)。
第一种情况,在移动窗口时系统会先给窗口发送一个WM_ERASEBKGND之后才是WM_PAINT 消息。我们只要在处理WM_ERASEBKGND消息直接返回就可以了。
LRESULT WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
switch(wMsg)
{
……………………………
case WM_ERASEBKGND:
return 0;
…………………………….
}
return DefWindowProc(hWnd,wMsg,wParam,lParam);
}
第二种情况,在绘制大量图片时如果CPU处理速度不够的话就会出现窗口闪烁。这种情况,我们可以采用双缓存机制。首先,我们可以在内存DC然后把图片先绘制到内存DC上最后将内存DC复制到窗口DC上。
//Create a DC that matches the device
m_hdcMem = CreateCompatibleDC(hdc);
if(m_hdcMem == NULL)
{
return;
}
m_hBitmap = CreateCompatibleBitmap(hdc,m_Size.cx,m_Size.cy);
if(m_hBitmap == NULL)
{
return;
}
//Select the bitmap into to the compatible device context
m_hOldSel = SelectObject(m_hdcMem,m_hBitmap);
……………
//将图片绘制到m_hdcMem上
……………
//将m_hdcMem复制到hdc上
BitBlt(hdc,0,0,size.cx,size.cy,m_hdcMem,0,0,SRCCOPY);
SelectObject(m_hdcMem,m_hOldSel);
DeleteObject(m_hBitmap);
DeleteDC(m_hdcMem);
第三种情况,当窗口拥有子窗口时系统先将WM_PAINT 发送到父窗口消息队列中,父窗口处理完WM_PAINT后系统才发送到子窗口消息队列中。如果CPU的处理速度不够的话就必将出现窗口闪烁。这情况,我们必须在绘制父窗口时将子窗口中的内容绘制到父窗口上。
//Create a DC that matches the device
m_hdcMem = CreateCompatibleDC(hdc);
if(m_hdcMem == NULL)
{
return;
}
m_hBitmap = CreateCompatibleBitmap(hdc,m_Size.cx,m_Size.cy);
if(m_hBitmap == NULL)
{
return;
}
//Select the bitmap into to the compatible device context
m_hOldSel = SelectObject(m_hdcMem,m_hBitmap);
………………
//绘制子窗口到m_hdcMem
……………
//将m_hdcMem复制到hdc上
BitBlt(hdc,0,0,size.cx,size.cy,m_hdcMem,0,0,SRCCOPY);
SelectObject(m_hdcMem,m_hOldSel);
DeleteObject(m_hBitmap);
DeleteDC(m_hdcMem);
编译运行后发现还是有闪烁的情况,怎么回事?仔细查看开发文档,发现有这么一句话:
All windows implicitly have the WS_CLIPSIBLINGS and WS_CLIPCHILDREN styles。
意思说,在WINCE 下所有的窗口都WS_CLIPSIBLINGS 和WS_CLIPHILDREN属性。所以在绘制父窗口时,先将子窗口隐藏,绘制完后再显示子窗口。
备注:
WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。
WS_CLlPBLINGS:排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。