MFC 双缓存绘图时移动系统控件导致重影如何解决?

sty_app 2019-05-06 08:35:26
正常来说双缓存绘图速度快,可以创建内存DC,先在内存DC上绘制好图形
然后绘制的时候直接使用Bitblt一次性将绘制好的DC复制到窗口DC上。

但是系统控件无法执行绘制到内存DC上去,只能将系统控件的区域,从在内存DC上的区域中,使用SelectClipRgn,强行挖除。

执行滚动操作时,由于绘制区域的变化,界面需要不断重绘,同时系统控件需要进行位置移动操作MoveWindow:


可以看到双缓存绘制图形的速度要比系统控件快很多,产生重影无法消除。
有人说MoveWindow的操作本身就比较慢:来源http://www.debugease.com/vc/1838830.html

要想不重影具体该怎么操作呢?
...全文
1527 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
千里送人头 2019-05-08
  • 打赏
  • 举报
回复
楼主,你这个场景,鼠标是一直按下不放的,往这个方向找一下原因看看能不能解决问题,之前我做的场景也有鼠标的操作,但场景是像上下左右的方向操作,会将鼠标释放
sty_app 2019-05-07
  • 打赏
  • 举报
回复
引用 1 楼 schlafenhamster 的回复:
"但是系统控件无法执行绘制到内存DC上去" 可以这样

case IDC_SCROLLBAR1:// "H bar"
m_hBar.SendMessage(WM_PAINT,(WPARAM)dcMem.m_hDC,0);
prompt="\"Horizontal\" scrollbar has been copied to clipbroad!";
break;


回答给的SendMessage给了关键的提示,一直以为MoveWindow需要使用UpdateWindow才可以刷新绘制,忘记了SendMessage和PostMessage是直接跳过消息队列的操作,提高了系统控件的绘制速度。避免了重影。
sty_app 2019-05-07
  • 打赏
  • 举报
回复

自绘对话框中添加的系统控件,闪烁以及重影问题基本解决。效果基本可以接受
关键代码如下:
在内存DC中绘制自绘控件的同时,将系统控件移动位置
BOOL CColorLightControl::InitControlEnd(SDrawControlShow *pDrawControlShow, CWnd *pWnd, CONTROL_INIT_STATUS initType)
{
if( initType==cis_status_dlg_init)
{
pDrawControlShow->dlgInitialized = TRUE;
return TRUE;
}
else if( initType==cis_status_control_init )
{
pDrawControlShow->controlInitialized = TRUE;
return TRUE;
}
if( !pDrawControlShow->dlgInitialized || !pDrawControlShow->controlInitialized)
return FALSE;

pDrawControlShow->SystemControls.RemoveAll();

int ClipRgnCount = 0;
for( int i=0; i<pDrawControlShow->IDCount; i++ ) //循环所有控件,定位所有系统控件
{
RECT boundRect;
BOOL bRes = FALSE;
if( m_CustomEdit.GetBoundControlPos(pDrawControlShow->pDrawControlInfo, i, &boundRect))
{
bRes = TRUE;
ClipRgnCount++;
}
else if(m_CustomControl.GetBoundControlPos(pDrawControlShow->pDrawControlInfo, i, &boundRect,pWnd))
{
bRes = TRUE;
ClipRgnCount++;
}
if(bRes)
{
//解析扩展部分
STranExpandInfo Temp;
CWnd *pCtrlWnd = pWnd->GetDlgItem(pDrawControlShow->pDrawControlInfo[i].boundID);
if(pCtrlWnd != NULL && IsWindow(pCtrlWnd->GetSafeHwnd()))
{
Temp.nID = i;
Temp.pWnd = pWnd;
Temp.pCtrlWnd = pCtrlWnd;
Temp.boundRect = boundRect;
Temp.pDrawControlInfo = &(pDrawControlShow->pDrawControlInfo[i]);
m_TranExpandManager.TranExpand(Temp);
//移动控件
pCtrlWnd->MoveWindow(&boundRect,FALSE); //系统控件移动位置,但不重绘
pDrawControlShow->SystemControls.Add(pCtrlWnd); //将系统控件加入需要重绘的控件集
if( pDrawControlShow->pDrawControlInfo[i].enable && pDrawControlShow->pDrawControlInfo[i].visible)
{
if( !pCtrlWnd->IsWindowVisible() /*|| initType!=cis_status_update*/)
pCtrlWnd->ShowWindow(SW_SHOWNORMAL);
}
else
{
if(pCtrlWnd->IsWindowVisible()/* || initType!=cis_status_update*/)
pCtrlWnd->ShowWindow(SW_HIDE);
}
}
}

}
CreateClipRgn(pDrawControlShow,pWnd);//取得屏幕背景刷新区域(将系统控件的区域从背景区域中挖除)
return TRUE;
}


循环绘制所有自绘控件
void CColorLightControl::DrawAllControl(SDrawControlShow *pDrawControlShow, CWnd *pWnd)
{
if( pDrawControlShow->memDC==NULL || pDrawControlShow->memDC.m_hDC==NULL)
return;
CSingleLock SingleLock(&m_CriticalSection);
if(SingleLock.IsLocked())
return;

CString strResPath;
strResPath.Format(_T("%s%s"), g_appPath, g_pCltcontrolstyle->GetResourceDir());
Graphics mGraphics(pDrawControlShow->memDC.m_hDC);
if(pDrawControlShow->pCusBackGroundColor != NULL)
mGraphics.Clear(RgbToArgb(255, *pDrawControlShow->pCusBackGroundColor));
else
mGraphics.Clear(RgbToArgb(255, g_pCltcontrolstyle->GetBackGroundColor()));
pDrawControlShow->memDC.SelectObject(&pDrawControlShow->textFont);
pDrawControlShow->memDC.SetBkMode(TRANSPARENT);

if(pDrawControlShow != NULL && pWnd != NULL)
{
HWND hwnd = pWnd->GetSafeHwnd();
if(pDrawControlShow->pFrontDraw != NULL)
pDrawControlShow->pFrontDraw(hwnd, &pDrawControlShow->memDC);
}

CDrawCustomControl *pControl = NULL;
for(int nID = 0; nID<pDrawControlShow->IDCount; nID++ )
{
pDrawControlShow->memDC.SetTextColor(g_pCltcontrolstyle->GetBackGroundColor());
if( !pDrawControlShow->pDrawControlInfo[nID].visible )
continue;
pControl = GetDlgControl(pDrawControlShow->pDrawControlInfo[nID].controlType);
if(pControl != NULL)
{
pControl->DrawControl(pDrawControlShow, nID, strResPath,pWnd,g_pCltcontrolstyle->GetBackGroundColor()); //在内存DC中绘制自定义控件
}
}

if(pDrawControlShow != NULL && pWnd != NULL)
{
HWND hwnd = pWnd->GetSafeHwnd();
if(pDrawControlShow->pBehindDraw != NULL)
pDrawControlShow->pBehindDraw(hwnd, &pDrawControlShow->memDC);
}

if( pWnd!=NULL)
pWnd->RedrawWindow(); //触发Onpaint,使用双缓存机制
}



在对话框的Onpaint中执行如下操作:
void CColorBaseDlg::OnPaint() 
{
CPaintDC dc(this); // device context for painting
if(!m_baseDlgSetInfo.m_memDCInit)
return ;
m_pIColorLightControl->RePaintSystemControl(&m_cltControlShow); //将需要重绘的系统控件绘制出来
dc.SelectClipRgn(&m_cltControlShow.clientRgn, RGN_COPY); //将挖掉系统控件区域的背景区域选到当前对话框的dc中
dc.BitBlt(m_cltControlShow.clientRect.left, m_cltControlShow.clientRect.top,m_cltControlShow.clientRect.Width(), m_cltControlShow.clientRect.Height(), &m_cltControlShow.memDC, 0, 0, SRCCOPY); //双缓存复制
}


RePaintSystemControl的实现:
void CColorLightControl::RePaintSystemControl( SDrawControlShow *pDrawControlShow )
{
if( !pDrawControlShow->dlgInitialized || !pDrawControlShow->controlInitialized)
return;

for(int i = 0; i < pDrawControlShow->SystemControls.GetCount(); i++)
pDrawControlShow->SystemControls.GetAt(i)->PostMessage(WM_PAINT,0,0); //使用PostMessage发送WM_PAINT消息绘制系统控件
}
sty_app 2019-05-07
  • 打赏
  • 举报
回复
引用 15 楼 Mr_sandman1994 的回复:
[quote=引用 14 楼 sty_app 的回复:]
[quote=引用 13 楼 Mr_sandman1994 的回复:]
直接在主界面上放控件通过movewindow不太好吧


一般都会弄一个子界面贴在主界面上,把这些控件都放子界面里面


软件大部分的控件都是自绘控件,只有edit、list、tree 这几个控件采用的是系统控件。[/quote]
自绘又不影响你放在子界面里[/quote]

界面也是自绘的。
绿色盒子 2019-05-07
  • 打赏
  • 举报
回复
引用 14 楼 sty_app 的回复:
[quote=引用 13 楼 Mr_sandman1994 的回复:]
直接在主界面上放控件通过movewindow不太好吧


一般都会弄一个子界面贴在主界面上,把这些控件都放子界面里面


软件大部分的控件都是自绘控件,只有edit、list、tree 这几个控件采用的是系统控件。[/quote]
自绘又不影响你放在子界面里
sty_app 2019-05-07
  • 打赏
  • 举报
回复
引用 13 楼 Mr_sandman1994 的回复:
直接在主界面上放控件通过movewindow不太好吧


一般都会弄一个子界面贴在主界面上,把这些控件都放子界面里面


软件大部分的控件都是自绘控件,只有edit、list、tree 这几个控件采用的是系统控件。
绿色盒子 2019-05-07
  • 打赏
  • 举报
回复
直接在主界面上放控件通过movewindow不太好吧


一般都会弄一个子界面贴在主界面上,把这些控件都放子界面里面
绿色盒子 2019-05-07
  • 打赏
  • 举报
回复
引用 9 楼 sty_app 的回复:
[quote=引用 8 楼 Mr_sandman1994 的回复:]
把iSet代码贴出来看看


大神,咋知道这软件叫iSet的呢。[/quote]
还知道colorlight呢
schlafenhamster 2019-05-06
  • 打赏
  • 举报
回复
控件内是这样

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 );
sty_app 2019-05-06
  • 打赏
  • 举报
回复
引用 3 楼 schlafenhamster 的回复:
控件的 OnPaint 人口 通常没有 DC , 其实 是可以 指定 DC 的 但 要用 SendMessage 


那什么时候发送消息呢? MoveWindow之后吗
schlafenhamster 2019-05-06
  • 打赏
  • 举报
回复
控件的 OnPaint 人口 通常没有 DC , 其实 是可以 指定 DC 的 但 要用 SendMessage 
sty_app 2019-05-06
  • 打赏
  • 举报
回复
引用 1 楼 schlafenhamster 的回复:
"但是系统控件无法执行绘制到内存DC上去" 可以这样

case IDC_SCROLLBAR1:// "H bar"
m_hBar.SendMessage(WM_PAINT,(WPARAM)dcMem.m_hDC,0);
prompt="\"Horizontal\" scrollbar has been copied to clipbroad!";
break;


这是个什么操作
schlafenhamster 2019-05-06
  • 打赏
  • 举报
回复
"但是系统控件无法执行绘制到内存DC上去" 可以这样

case IDC_SCROLLBAR1:// "H bar"
m_hBar.SendMessage(WM_PAINT,(WPARAM)dcMem.m_hDC,0);
prompt="\"Horizontal\" scrollbar has been copied to clipbroad!";
break;
sty_app 2019-05-06
  • 打赏
  • 举报
回复
附上 优化前的效果:
sty_app 2019-05-06
  • 打赏
  • 举报
回复
引用 5 楼 schlafenhamster 的回复:
控件内是这样

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 );



经过测试,这样对控件影响太大,我这边的操作改成 CEdit控件 MoveWindow的时候选择不重绘,然后直接给控件PostMessage WM_PAINT消息,让控件直接绘制,然后其他操作不变,效果成这个样子了:


效果勉强可以接受。
sty_app 2019-05-06
  • 打赏
  • 举报
回复
引用 8 楼 Mr_sandman1994 的回复:
把iSet代码贴出来看看


大神,咋知道这软件叫iSet的呢。
绿色盒子 2019-05-06
  • 打赏
  • 举报
回复
把iSet代码贴出来看看
伊航 2019-05-06
  • 打赏
  • 举报
回复
不是所有问题都能有完美解的,凑合能用就差不多了。不然就是你的思路走歪了。
一、VS2010/MFC编程入门教程之目录 第一部分:VS2010/MFC开发环境 VS2010/MFC编程入门之前言 VS2010/MFC编程入门之一(VS2010与MSDN安装过程图解) 第二部分:VS2010/MFC应用程序框架 VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架) VS2010/MFC编程入门之三(VS2010应用程序工程中文件的组成结构) VS2010/MFC编程入门之四(MFC应用程序框架分析) VS2010/MFC编程入门之五(MFC消息映射机制概述) 第三部分:对话框 VS2010/MFC编程入门之六(对话框:创建对话框模板和修改对话框属性) VS2010/MFC编程入门之七(对话框:为对话框添加件) VS2010/MFC编程入门之八(对话框:创建对话框类和添加件变量) VS2010/MFC编程入门之九(对话框:为件添加消息处理函数) VS2010/MFC编程入门之十(对话框:设置对话框件的Tab顺序) VS2010/MFC编程入门之十一(对话框:模态对话框及其弹出过程) VS2010/MFC编程入门之十二(对话框:非模态对话框的创建及显示) VS2010/MFC编程入门之十三(对话框:属性页对话框及相关类的介绍) VS2010/MFC编程入门之十四(对话框:向导对话框的创建及显示) VS2010/MFC编程入门之十五(对话框:一般属性页对话框的创建及显示) VS2010/MFC编程入门之十六(对话框:消息对话框) VS2010/MFC编程入门之十七(对话框:文件对话框) VS2010/MFC编程入门之十八(对话框:字体对话框) VS2010/MFC编程入门之十九(对话框:颜色对话框) 第四部分:常用件 VS2010/MFC编程入门之二十(常用件:静态文本框) VS2010/MFC编程入门之二十一(常用件:编辑框Edit Control) VS2010/MFC编程入门之二十二(常用件:按钮件Button、Radio Button和Check Box) VS2010/MFC编程入门之二十三(常用件:按钮件的编程实例) VS2010/MFC编程入门之二十四(常用件:列表框件ListBox) VS2010/MFC编程入门之二十五(常用件:组合框件Combo Box) VS2010/MFC编程入门之二十六(常用件:滚动条件Scroll Bar) VS2010/MFC编程入门之二十七(常用件:图片件Picture Control) VS2010/MFC编程入门之二十八(常用件:列表视图件List Control 上) VS2010/MFC编程入门之二十九(常用件:列表视图件List Control 下) VS2010/MFC编程入门之三十(常用件:树形件Tree Control 上) VS2010/MFC编程入门之三十一(常用件:树形件Tree Control 下) VS2010/MFC编程入门之三十二(常用件:标签件Tab Control 上) VS2010/MFC编程入门之三十三(常用件:标签件Tab Control 下) 第五部分:菜单、工具栏与状态栏 VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解) VS2010/MFC编程入门之三十五(菜单:菜单及CMenu类的使用) VS2010/MFC编程入门之三十六(工具栏:工具栏资源及CToolBar类) VS2010/MFC编程入门之三十七(工具栏:工具栏的创建、停靠与使用) VS2010/MFC编程入门之三十八(状态栏的使用详解) 第六部分:文档、视图和框架 VS2010/MFC编程入门之三十九(文档、视图和框架:概述) VS2010/MFC编程入门之四十(文档、视图和框架:各对象之间的关系) VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口) 第七部分:MFC常用类 VS2010/MFC编程入门之四十二(MFC常用类:CString类) VS2010/MFC编程入门之四十三(MFC常用类:CTime类和CTimeSpan类) VS2010/MFC编程入门之四十四(MFC常用类:定器Timer) VS2010/MFC编程入门之四十五(MFC常用类:CFile文件操作类) VS2010/MFC编程入门之四十六(MFC常用类:MFC异常处理) 第八部分:字体和文本输出 VS2010/MFC编程入门之四十七(字体和文本输出:CFont字体类) VS2010/MFC编程入门之四十八(字体和文本输出:文本输出) 第九部分:图形图像 VS2010/MFC编程入门之四十九(图形图像:CDC类及其屏幕绘图函数) VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen) VS2010/MFC编程入门之五十一(图形图像:GDI对象之画刷CBrush) 第十部分:Ribbon界面开发 VS2010/MFC编程入门之五十二(Ribbon界面开发:创建Ribbon样式的应用程序框架) VS2010/MFC编程入门之五十三(Ribbon界面开发:为Ribbon Bar添加件) VS2010/MFC编程入门之五十四(Ribbon界面开发:使用更多件并为件添加消息处理函数) 本文来源于鸡啄米 http://www.jizhuomi.com/ , 原文地址:http://www.jizhuomi.com/software/257.html

15,978

社区成员

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

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