NM__CustomDraw消息中如何实现双缓冲绘制防止闪烁

qq_29720391 2019-05-09 05:22:09

现在派生了一个列表框控件实现对其重绘,使用NM_CustomDraw消息对其进行重绘,但是发现NM_CustomDraw消息每次只是绘制一个
控件或者图形,而如果用双缓冲来绘制的话每次只能贴上一个CDC memDc,位图,导致无法进行双缓冲绘制完全部控件,那么该如何在该消息中实现双缓冲绘制的方法对空间进行重绘?
...全文
2632 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
luj_1768 2019-05-12
  • 打赏
  • 举报
回复
你先用单一窗口实现一下:只显示那个显示不了的窗口。
sinat_41671772 2019-05-10
  • 打赏
  • 举报
回复
双缓冲原理在awt和swing厉害
hurryboylqs 2019-05-10
  • 打赏
  • 举报
回复
不闪烁表示跟双缓冲没什么关系了,之所以卡顿是你影响到了UI的CPU时间,比如你绘制的时候循环太久,所以刷新的时候尽量局部刷新,不要全局刷
schlafenhamster 2019-05-10
  • 打赏
  • 举报
回复
不必 你不是 有 void CReportCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 吗?
OnPaint 会不断 调用 他 直到 paint 完
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 11 楼 schlafenhamster 的回复:
注意 // Let the control draws the tree. DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0 ); 这是 原控件的 WN_PAINT (dc 用的是 memDC) ,对于 CustomDraw 的 控件 OnPaint 中 将 调用 “DrawItem”
意思是我还是得重载DrawItem来进行重绘? 那可能CustomDraw的机制注定有这种限制吧
weixin_44146892 2019-05-10
  • 打赏
  • 举报
回复
双缓冲原理在awt和swing中实现消除闪烁的
schlafenhamster 2019-05-10
  • 打赏
  • 举报
回复
注意
// Let the control draws the tree.
DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0 );

这是 原控件的 WN_PAINT (dc 用的是 memDC) ,对于 CustomDraw 的 控件 OnPaint 中 将 调用 “DrawItem”
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 9 楼 hurryboylqs 的回复:
[quote=引用 8 楼 qq_29720391 的回复:] [quote=引用 4 楼 hurryboylqs 的回复:] https://blog.csdn.net/hurryboylqs/article/details/5858997
我已经实现了在CustomDraw消息里重绘列表控件,但我想问的是如何采用双缓冲绘制来防止闪烁。[/quote] 我给你的例子最下面有,你仔细看下这段代码: DWORD dwExtentStyle = m_list.GetExtendedStyle(); m_list.SetExtendedStyle(dwExtentStyle|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER); 加上LVS_EX_DOUBLEBUFFER这个扩展样式就可以了,你所在CustomDraw的东西都是在内存缓冲中绘制,然后被ListCtrl一次性显示到屏幕DC,这个过程你不需要代码干预的[/quote] 这个扩展样式我用过了,因为我会在某一项中绘制一段曲线,所以虽然不闪了 但是当数据量大的时候,还是在点击选择、切换的时候还是会很明显的感到卡顿的现象,使用感有些差。
hurryboylqs 2019-05-10
  • 打赏
  • 举报
回复
引用 8 楼 qq_29720391 的回复:
[quote=引用 4 楼 hurryboylqs 的回复:] https://blog.csdn.net/hurryboylqs/article/details/5858997
我已经实现了在CustomDraw消息里重绘列表控件,但我想问的是如何采用双缓冲绘制来防止闪烁。[/quote] 我给你的例子最下面有,你仔细看下这段代码: DWORD dwExtentStyle = m_list.GetExtendedStyle(); m_list.SetExtendedStyle(dwExtentStyle|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER); 加上LVS_EX_DOUBLEBUFFER这个扩展样式就可以了,你所在CustomDraw的东西都是在内存缓冲中绘制,然后被ListCtrl一次性显示到屏幕DC,这个过程你不需要代码干预的
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 4 楼 hurryboylqs 的回复:
https://blog.csdn.net/hurryboylqs/article/details/5858997
我已经实现了在CustomDraw消息里重绘列表控件,但我想问的是如何采用双缓冲绘制来防止闪烁。
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 3 楼 zgl7903 的回复:
最有效的办法就是自己处理 WM_ERASEBKGND 和 WM_PAINT 消息
重载 WM_ERASEBKGND 和 WM_PAINTI消息? 能否说下怎么重载来防止闪烁呢。
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 2 楼 schlafenhamster 的回复:
"给 OnPaint 加个 HDC 参数"
我使用CustomDraw消息重绘就是为了LPNMLVCUSTOMDRAW lplvcd = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);这个参数来获取绘制的行和列还有绘制的模式,如果采用OnPaint如何获取呢?而且如何一次性获取到设置的全部的行列来在双缓冲的位图上进行绘制呢?我又不太想重新绘制列表控件的全部过程,这太麻烦了,应该如何实现呢
心语&星愿 2019-05-10
  • 打赏
  • 举报
回复
xxx谢谢好人
yaonan33 2019-05-10
  • 打赏
  • 举报
回复
https://blog.csdn.net/hurryboylqs/article/details/5858997
schlafenhamster 2019-05-10
  • 打赏
  • 举报
回复
CTreeCtrl 的例子 :

void cTree::OnPaint()
{
CPaintDC dc(this);
// get size
CRect rc;
GetClientRect(&rc);
// Create a compatible memory DC
CDC memDC;
memDC.CreateCompatibleDC(&dc);
// Select a compatible bitmap into the memory DC
CBitmap bitmap;
bitmap.CreateCompatibleBitmap( &dc, rc.Width(), rc.Height());
HBITMAP oldBmp=(HBITMAP)memDC.SelectObject(&bitmap);
// Let the control draws the tree.
DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
// 'and' to the background,
dc.BitBlt(0,0,rc.Width(),rc.Height(),&memDC,0,0,SRCAND);
// set back
memDC.SelectObject(oldBmp);
// free
DeleteObject(bitmap.m_hObject);
DeleteObject(memDC);
}


注意
// Let the control draws the tree.
DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
schlafenhamster 2019-05-10
  • 打赏
  • 举报
回复

// CustomDraw uses 2 buffers = LVS_EX_DOUBLEBUFFER
void CReportCtrl::OnPaint()
{
#define HEAD 24
#if 1 //
CPaintDC dc(this); // device context for painting
// get size
CRect rc;
GetClientRect(&rc);
// Create a compatible memory DC
CDC memDC;
memDC.CreateCompatibleDC(&dc);
// Select a compatible bitmap into the memory DC
CBitmap bitmap;
bitmap.CreateCompatibleBitmap( &dc, rc.Width(), rc.Height());
HBITMAP oldBmp=(HBITMAP)memDC.SelectObject(&bitmap);
// Let the control draws the tree.
DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
#if 0 // to see
OpenClipboard();
EmptyClipboard();
SetClipboardData(CF_BITMAP,(HBITMAP)bitmap);
CloseClipboard();
#endif
// to dc ! bitmap without HeaderCtrl !
dc.BitBlt(0,HEAD,rc.Width(),rc.Height(),&memDC,0,HEAD,SRCCOPY);
// set back
memDC.SelectObject(oldBmp);
// free
DeleteObject(bitmap.m_hObject);
DeleteObject(memDC);
#else
CListCtrl::OnPaint();// for painting messages
#endif
}
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
谢谢大家的建议,结贴了,最后决定还是采用 DWORD dwExtentStyle = m_list.GetExtendedStyle(); m_list.SetExtendedStyle(dwExtentStyle|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER); 设置扩展样式为DOUBLEBUFFER的方法来防止闪烁了。不过数据量过大时UI界面会出现卡顿等情况。
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 14 楼 hurryboylqs 的回复:
不闪烁表示跟双缓冲没什么关系了,之所以卡顿是你影响到了UI的CPU时间,比如你绘制的时候循环太久,所以刷新的时候尽量局部刷新,不要全局刷
应该是这样吧,暂时先这么用着,以后再实现的时候还是决定不使用CustomDraw消息来重绘了
qq_29720391 2019-05-10
  • 打赏
  • 举报
回复
引用 13 楼 schlafenhamster 的回复:
不必 你不是 有 void CReportCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 吗? OnPaint 会不断 调用 他 直到 paint 完
我测试了一下采用你的这种方法重绘的话还是会闪烁。
hurryboylqs 2019-05-09
  • 打赏
  • 举报
回复
https://blog.csdn.net/hurryboylqs/article/details/5858997
加载更多回复(3)

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧