读书人

GDI双缓冲绘图遇到过黑屏或花屏有关

发布时间: 2012-12-15 15:16:03 作者: rapoo

GDI双缓冲绘图,遇到过黑屏或花屏问题吗?
最近和老师做一个系统,界面需要频繁的更新,刚开始出现闪屏的现象,后来采用双缓冲方法解决了这个问题,但是程序开了一段时间后就黑(花)屏了(程序黑了不是操作系统黑了)。后来我又查了一下程序,发现我每一次绘制完界面,少释放了一个字体,会不会是因为少释放这一个字体,导致频繁的内存泄露,最后导致黑(花)屏,有这种可能吗?
[最优解释]
检查是否资源泄漏的办法之一:
在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象
让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资源泄漏!

比如少调用类似以下API:
ReleaseXXX或XXX.Release
CloseXXX或XXX.Close
DestroyXXX或XXX.Destroy
DisposeXXX或XXX.Dispose



[其他解释]
有这种可能性,不过更有可能的是指针和数组操作越界。

引用:
最近和老师做一个系统,界面需要频繁的更新,刚开始出现闪屏的现象,后来采用双缓冲方法解决了这个问题,但是程序开了一段时间后就黑(花)屏了(程序黑了不是操作系统黑了)。后来我又查了一下程序,发现我每一次绘制完界面,少释放了一个字体,会不会是因为少释放这一个字体,导致频繁的内存泄露,最后导致黑(花)屏,有这种可能吗?

[其他解释]
有代码就最好了,
BOOL CTestDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值

return TRUE;
}
是不是刷背景刷掉了
[其他解释]
后来我又查了一下程序,发现我每一次绘制完界面,少释放了一个字体,会不会是因为少释放这一个字体,导致频繁的内存泄露,最后导致黑(花)屏

只要不是蓝屏。就和内存泄露没有关系。
黑屏主要是因为刷新没有绘制到。花屏,是一般内存乱了。比如后面的改了前面内存的东西。
[其他解释]
//采用双缓冲技术
//内存设备内容,内存缓存块
CDCmemDC ;
CBitmap memBitmap, * pOldBit ;
CFont fontCompetitionTitle, fontPlayerInfo, fontDigit, fontTimeover, fontPlayerTitle, fontPlayerSubTitle ;
CString strPlayerTitle, strPlayerSubTitle, strPlayerName, strPlayerAcademy,
strPlayerIntro, strDigit, strNum, bmpPath, appearNum, currentType, allInfo, titlePicPath ;
COLORREF crStr ;
_bstr_t strSql ;//数据库查询语句

//变量初始化
/************/
//创建字体
/************/
//点的大小,例如120点可以看为12磅
//cCompetitionTitle竞赛主题字体
fontCompetitionTitle.CreatePointFont (35 * 10, FONT_WORD, &cdc) ;
//cPlayerTitle选手参赛主题字体
//暂时
//fontPlayerTitle.CreatePointFont (50 * 10, FONT_WORD, &cdc) ;
fontPlayerTitle.CreatePointFont (40 * 10, FONT_WORD, &cdc) ;
//副标题字体
fontPlayerSubTitle.CreatePointFont (40 * 10, FONT_WORD, &cdc) ;
//cPlayerInfo选手信息字体
fontPlayerInfo.CreatePointFont (25 * 10, FONT_WORD, &cdc) ;
//倒计时数字字体
fontDigit.CreatePointFont (130 * 10, FONT_NUM, &cdc) ;
//时间到字体
fontTimeover.CreatePointFont (70 * 10, FONT_WORD, &cdc) ;

//创建内存设备内容,通过缓存防止界面闪烁
memDC.CreateCompatibleDC (&cdc) ;
memBitmap.CreateCompatibleBitmap (&cdc, m_rcWnd.Width (), m_rcWnd.Height ()) ;
pOldBit = memDC.SelectObject (&memBitmap) ;

//绘制背景
this->PaintBk (memDC) ;

//获取文本
/************/
try
{
m_ado.OpenDB () ;
strSql = "select * from StudentInfo where Id = '" + strId + "'" ;
m_ado.GetRecordset (strSql) ;

if (m_ado.isEmpty ())
{
return ;
}

strPlayerName.Format ("姓名:" + _bstr_t (m_ado.m_pRecordset->Fields->GetItem ("Name")->Value)) ;


strPlayerAcademy.Format ("学院:" + _bstr_t (m_ado.m_pRecordset->Fields->GetItem ("Grade")->Value) + "级"
+ _bstr_t (m_ado.m_pRecordset->Fields->GetItem ("Academy")->Value)) ;
strPlayerIntro.Format ("学号:" + _bstr_t (m_ado.m_pRecordset->Fields->GetItem ("Id")->Value)) ;
appearNum.Format ("出场编号:%d号", m_ado.m_pRecordset->Fields->GetItem ("AppearNum")->Value.uintVal) ;

//根据比赛形式区分题目
if (!styleId)
{
//定题
currentType.Format ("类型:定题演讲") ;
strPlayerTitle.Format (_bstr_t (m_ado.m_pRecordset->Fields->GetItem ("Title")->Value)) ;
strPlayerSubTitle.Format ("-%s ", (char *) ((_bstr_t) m_ado.m_pRecordset->Fields->GetItem ("Subtitle")->Value)) ;
}
else
{
//随机题目
currentType.Format ("类型:即兴演讲") ;
strNum.Format ("%d", styleId) ;
strSql = "select SelectTitle from SelectTitle where Id = '" + _bstr_t (styleId) + "'" ;
m_ado.GetRecordset (strSql) ;
strPlayerTitle.Format (_bstr_t (m_ado.m_pRecordset->Fields->GetItem ("SelectTitle")->Value)) ;
strPlayerSubTitle = "" ;
}
}
catch (_com_error &e)
{
//关闭记录集和数据库连接

m_ado.CloseRecordset () ;
m_ado.CloseDB () ;
::WaitForSingleObject (NULL, NULL) ;
//异常日志
CString err ;
err.Format ("%s发生异常,%s", __FUNCDNAME__, (char *) e.Description ()) ;
writeLog ("错误日志", err) ;
//为了保证现场气氛,特意注释这句话
//::PostQuitMessage (0) ;
}

//绘制选手图片
bmpPath.Format ("data\\students\\%s.bmp", (char *) strId) ;
this->PaintBmp (memDC, m_rcWnd.Width () / 5 - 50, m_rcWnd.Height () / 5 - 15, bmpPath) ;

//绘制文本
/************/
//绘制竞赛主题
this->PaintString (memDC, m_strCompetitionTitle, fontCompetitionTitle, m_rcWnd.Width () / 2, 52, TA_CENTER, WHITE) ;

//绘制选手信息
allInfo = appearNum + "\r" + currentType + "\r" + strPlayerIntro + "\r"
+ strPlayerName + "\r" + strPlayerAcademy ;
this->PaintString (memDC, allInfo, fontPlayerInfo,
CRect (m_rcWnd.Width () / 5 + 100, m_rcWnd.Height () / 5 - 20,
m_rcWnd.Width () / 5 + 100 + 500, m_rcWnd.Height () / 5 + 200)) ;

//绘制选手参赛题目
if (!styleId)
//定题演讲为文字标题
this->PaintString (memDC, strPlayerTitle, fontPlayerTitle,
CRect (0, m_rcWnd.Height () / 2, m_rcWnd.Width (), m_rcWnd.Height () - 60),
DT_CENTER) ;
else
{
//即兴演讲为图片题目
titlePicPath.Format ("data\\titlePictures\\%d.bmp", (char *) styleId) ;
if (!this->PaintBmp (memDC, m_rcWnd.Width () / 5, m_rcWnd.Height () / 2, titlePicPath, BMP_TITLEPICTURE))
//如果没有图片,就绘制文字题目。
this->PaintString (memDC, strPlayerTitle, fontPlayerTitle,
CRect (0, m_rcWnd.Height () / 2, m_rcWnd.Width (), m_rcWnd.Height () - 60),


DT_CENTER) ;;
}
this->PaintString (memDC, strPlayerSubTitle, fontPlayerSubTitle,
CRect (0, m_rcWnd.Height () / 2 + 240, m_rcWnd.Width (), m_rcWnd.Height () - 60),
DT_RIGHT) ;

//选择倒计时颜色
switch (iTime / 30)
{
default :
crStr = GREEN ;
break ;

case 1 :
crStr = YELLOW ;
break ;

case 0 :
crStr = RED ;
break ;

}

if (iTime)
{
//用3个%d是因为要显示3位数,否则当秒数为个位时,0无法显示
strDigit.Format (TEXT ("%d:%d%d"), iTime / 60, iTime % 60 / 10, iTime % 60 % 10) ;
//字符串坐标暂不提供修改配置
//还没较好的公式计算
//绘制倒计时没看之前痕迹的原因是,每一次执行onPaint,都会绘制一次bm,使得原来的痕迹被覆盖
this->PaintString (memDC, strDigit, fontDigit, 3 * m_rcWnd.Width () / 5, m_rcWnd.Height () / 8, TA_LEFT, crStr) ;
}
else
{
strDigit = TEXT ("时间到") ;
this->PaintString (memDC, strDigit, fontTimeover, 3 * m_rcWnd.Width () / 5, m_rcWnd.Height () / 6, TA_LEFT, crStr) ;
}

cdc.BitBlt (0, 0, m_rcWnd.Width (), m_rcWnd.Height (), &memDC, 0, 0, SRCCOPY) ;

//清理内存
memDC.SelectObject (pOldBit) ;
memBitmap.DeleteObject () ;
pOldBit->DeleteObject () ;
//手动删除字体
fontCompetitionTitle.DeleteObject () ;
fontPlayerInfo.DeleteObject () ;
fontDigit.DeleteObject () ;
fontTimeover.DeleteObject () ;
fontPlayerTitle.DeleteObject () ;
//后来发现漏掉的那一个字体
fontPlayerSubTitle.DeleteObject () ;
//关闭记录集和数据库连接
m_ado.CloseRecordset () ;
m_ado.CloseDB () ;


倒数第三行是后来加的。
OnEraseBkgnd(CDC* pDC)我已经加了
[其他解释]
异常捕获那里的::WaitForSingleObject (NULL, NULL) ;忘了注释
[其他解释]
{,}
open,close
malloc、free
new、delete
CreateFont,DeleteObject
CreateCompatibleDC,DeleteDC
CreateFile、CloseHandle
生、死
……

虎头蛇尾是俗人的习惯,
有始有终是君子的操守。


[其他解释]
引用:
检查是否资源泄漏的办法之一:
在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象
让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资……

以前还不知道任务管理器有这功能
[其他解释]
引用:
后来我又查了一下程序,发现我每一次绘制完界面,少释放了一个字体,会不会是因为少释放这一个字体,导致频繁的内存泄露,最后导致黑(花)屏

只要不是蓝屏。就和内存泄露没有关系。
黑屏主要是因为刷新没有绘制到。花屏,是一般内存乱了。比如后面的改了前面内存的东西。

内存泄露不一定会导致要蓝屏啊
[其他解释]
引用:
引用:后来我又查了一下程序,发现我每一次绘制完界面,少释放了一个字体,会不会是因为少释放这一个字体,导致频繁的内存泄露,最后导致黑(花)屏

只要不是蓝屏。就和内存泄露没有关系。
黑屏主要是因为刷新没有绘制到。花屏,是一般内存乱了。比如后面的改了前面内存的东西。
内存泄露不一定会导致要蓝屏啊

没有说一定啊。
------其他解决方案--------------------


引用:
引用:引用:后来我又查了一下程序,发现我每一次绘制完界面,少释放了一个字体,会不会是因为少释放这一个字体,导致频繁的内存泄露,最后导致黑(花)屏

只要不是蓝屏。就和内存泄露没有关系。
黑屏主要是因为刷新没有绘制到。花屏,是一般内存乱了。比如后面的改了前面内存的东西。
内存泄露不一定会导致要蓝屏……

那我可能误解你那句话(“只要不是蓝屏。就和内存泄露没有关系”)了。

读书人网 >C++

热点推荐