MFC OnPaint 绘图概率性出现绘图全黑的问题

San_Wolf 2014-09-03 04:33:04
开发一个公司内部使用的字体工具生成,主要流程是选择字体,加载到dc上在用textout绘制出来,获取上面的数据,再转化成内部需要的数据格式。
现在的问题是把内部使用的数据格式转化成图片格式,加入到CBitMap中,再用dc双缓冲绘制,结果数据越大,越容易出现绘制为黑的情况,多刷新(调用onpaint)几次可以显示正常,再刷新大概率还是黑色。(左边为正常情况,右边为异常情况)


代码流程是按键触发show,show设置bmp图片,调用RedrawWindow 刷新待绘制区域,然后在onpaint里面绘制。相关代码如下:

void CFontDlg::OnPaint()
{
CDialog::OnPaint();
//CPaintDC dc(this); // device context for painting
if (m_bmpF.m_hObject != NULL)
{
// CPaintDC dcClient(this);
CClientDC dcClient(this);
CDC cdc;
// 创建一个内存DC
cdc.CreateCompatibleDC(&dcClient);
HGDIOBJ pOldmap = cdc.SelectObject(&m_bmpF);

//cdc.FillSolidRect(m_rcGraphy,dcClient.GetBkColor());//按原来背景填充客户区,不然会是黑色
dcClient.BitBlt(m_rcGraphy.left,m_rcGraphy.top,m_rcGraphy.Width(),m_rcGraphy.Height(),&cdc,0,0,SRCCOPY); //直接将原DC的图像贴到内存D
// 绘制字体边框
dcClient.MoveTo(m_rcGraphy.left - 1, m_rcGraphy.top - 1);
dcClient.LineTo(m_rcGraphy.left - 1, m_rcGraphy.bottom);
dcClient.LineTo(m_rcGraphy.right , m_rcGraphy.bottom);
dcClient.LineTo(m_rcGraphy.right , m_rcGraphy.top - 1);
dcClient.LineTo(m_rcGraphy.left - 1, m_rcGraphy.top - 1);
cdc.SelectObject(pOldmap);
DeleteObject(&m_bmpF);
// 删除DC
cdc.DeleteDC();
}
}

// 处理字符显示
void CFontDlg::Show(Graphy &graphy )
{
Graphy graphyEnLarge;
// 放大字体
_FontLogic.EnlargeGraphy(graphy ,graphyEnLarge);
// 设定中心点
static CPoint poCenter(720,70);

CRect rcGraphy(poCenter.x - (graphyEnLarge.Width +1) / 2,poCenter.y - (graphyEnLarge.Height +1) / 2,
poCenter.x + graphyEnLarge.Width / 2 ,poCenter.y + graphyEnLarge.Height / 2 );
m_rcGraphy = rcGraphy;
if (m_bmpF.m_hObject != NULL)
{
m_bmpF.DeleteObject();//删除位图
}
CClientDC dcClient(this);
CDC cdc;
cdc.CreateCompatibleDC(&dcClient); //创建一个内存DC

m_bmpF.CreateCompatibleBitmap(&cdc,m_rcGraphy.Width(),m_rcGraphy.Height()); //创建一个内存位图

UINT uCount = m_rcGraphy.Height() * m_rcGraphy.Width();
UINT usize = chCEIL(uCount *4, 8) /8;

Graphy graphyCopy = graphyEnLarge;
_FontLogic.DealGraphy2BmpData(graphyCopy);

m_bmpF.SetBitmapBits(uCount,graphyCopy.p_data);

cdc.DeleteDC(); //删除DC

// 使整个区域失效,系统重画
ClearRectWindows( graphyEnLarge );
}

void CFontDlg::ClearRectWindows( const Graphy &graphy)
{
static int iStWidth = 0 , iStHeitht = 0;
// 设定中心点
static CPoint poCenter(720,70);

if ( iStWidth < graphy.Width)
{
iStWidth = graphy.Width;
}
if ( iStHeitht < graphy.Height)
{
iStHeitht = graphy.Height;
}
// 增加边框的刷新区域// 边框为1个像素宽
CRect rcRedraw(poCenter.x - 1 - (iStWidth + 1) / 2,poCenter.y - 1 - (iStHeitht +1) / 2,
poCenter.x + 1 + iStWidth / 2 ,poCenter.y + 1 + iStHeitht / 2 );
RedrawWindow(rcRedraw);
}
...全文
305 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
阿呆_ 2014-09-04
  • 打赏
  • 举报
回复
注意你调用的DeleteObject是Win32 API, 原型是 BOOL DeleteObject( _In_ HGDIOBJ hObject ); 传入参数是一个HANDLE,也就是说这里传入的是CBitmap内部的HBITMAP变量,这个变量是你CBitmap中具体保存的图片,第一次OnPaint中你把它删除了却没有把这个无效HBITMAP清0,第二次OnPaint时cdc::SelectObject妄图选的就是一个已不存在的图片,结果就是这个cdc是空的compatible dc,只有设备描述(比如长,宽,颜色深度等)却没有关联具体储存图片的内存。然后你将它作为源dc去画目的dc,这个结果是无法预测的,运气好就是什么都不做,目的dc还是原来的内容(上次OnPaint的内容),运气不好就会清空目的dc的图像。
San_Wolf 2014-09-04
  • 打赏
  • 举报
回复
引用 3 楼 Idle_ 的回复:
处理WM_PAINT消息时你OnPaint的内容不一定会显示到屏幕上,具体更新屏幕是根据BeginPaint时paintstruct中的裁剪区决定的。如果裁剪去为空,那么即使你OnPaint中画了再复制的图它也不会显示到屏幕。
HGDIOBJ pOldmap = cdc.SelectObject(&m_bmpF); ... cdc.SelectObject(pOldmap); DeleteObject(&m_bmpF); 这个原来的写法只有cdc.SelectObject(&m_bmpF); 没有重新选会原来的对象,也没有删除图片的对象。 但是这两个都会导致概率性的绘制区域为黑……我想知道绘制区域为黑的来源,或者说解决办法。
阿呆_ 2014-09-03
  • 打赏
  • 举报
回复
引用 2 楼 u011222307 的回复:
我通过切换标签(tab Control)测试,断点只触及onpaint,绘制一切正常。(TRACE了返回值,是0,看来是删除失败。这句执行失败,后面应该要注释掉了。) DeleteObject(&m_bmpF);是早上看到selectobject没有及时deleteobject,会导致内存泄露才加的,这个跟绘制全黑无关啊。
处理WM_PAINT消息时你OnPaint的内容不一定会显示到屏幕上,具体更新屏幕是根据BeginPaint时paintstruct中的裁剪区决定的。如果裁剪去为空,那么即使你OnPaint中画了再复制的图它也不会显示到屏幕。
San_Wolf 2014-09-03
  • 打赏
  • 举报
回复
引用 1 楼 Idle_ 的回复:
DeleteObject(&m_bmpF); ??? 你把m_bmpF的hbitmap删除了,第二次OnPaint时cdc.SelectObject(&m_bmpF);选中的就是一个非法handle啊,等于cdc中还是原来的值(不存在相关的bitmap),然后你bitblt一个空的dc到屏幕上..., 你期望得到什么?
我通过切换标签(tab Control)测试,断点只触及onpaint,绘制一切正常。(TRACE了返回值,是0,看来是删除失败。这句执行失败,后面应该要注释掉了。) DeleteObject(&m_bmpF);是早上看到selectobject没有及时deleteobject,会导致内存泄露才加的,这个跟绘制全黑无关啊。
阿呆_ 2014-09-03
  • 打赏
  • 举报
回复
DeleteObject(&m_bmpF); ??? 你把m_bmpF的hbitmap删除了,第二次OnPaint时cdc.SelectObject(&m_bmpF);选中的就是一个非法handle啊,等于cdc中还是原来的值(不存在相关的bitmap),然后你bitblt一个空的dc到屏幕上..., 你期望得到什么?

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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