GDI中,动画闪烁的原因及解决方案

动画闪烁的根本原因是动画背景和动画元素的交替输出。解决方案是使用双缓冲技术。
所谓双缓冲就是将每一帧要显示的动画,都放到一个内存DC里,每一帧都是一张动画。这样就避免了动画元素交替输出的问题。

下面的代码中,我把所有要输出的动画都放到了m_dc中,最后绘制完整的m_dc。每一帧都是m_dc动画,就不存在动画交替输出的问题了。

void Butterfly::OnPaint()
{
CPaintDC dc(this); // 创建设备上下文对象

m_dc.DeleteDC(); // 删除原有的设备上下文对象
if (!m_dc.CreateCompatibleDC(NULL)) { // 创建与屏幕兼容的设备上下文对象
	m_dc.DeleteDC();
	return;
}
CBitmap tmpBmp{}; // 创建临时位图对象
tmpBmp.CreateCompatibleBitmap(&CClientDC(NULL), m_winRect.Width(), m_winRect.Height()); // 创建与屏幕兼容的位图对象
m_dc.SelectObject(tmpBmp); // 将临时位图对象选入设备上下文对象

tmp_dc.CreateCompatibleDC(&dc); // 创建与设备上下文对象兼容的临时设备上下文对象
tmp_dc.SelectObject(m_grass); // 将草地位图对象选入临时设备上下文对象

// 加载背景
m_dc.StretchBlt(0, 0, m_winRect.Width(), m_winRect.Height()
	, &tmp_dc, 0, 0, m_grassSize.cx, m_grassSize.cy, SRCCOPY);

//m_dc.DeleteDC();
m_bf_dc.CreateCompatibleDC(&m_dc); // 创建与设备上下文对象兼容的蝴蝶设备上下文对象
m_bf_dc.SelectObject(m_butterfly[bf_index]); // 将蝴蝶位图对象选入蝴蝶设备上下文对象

CRect FillRect{ 50,50,800,800 }; // 创建填充矩形对象
m_dc.FillSolidRect(FillRect, RGB(0, 0, 0)); // 使用黑色填充矩形区域

int numStr = 0; // 用于标记蝴蝶数量的变量
// 设置透明色
COLORREF transColor = RGB(255, 0, 255);
POSITION pos = bfList.GetHeadPosition(); // 获取蝴蝶列表的头位置迭代器
while (pos != NULL) {
	bf& tmp = bfList.GetNext(pos); // 获取蝴蝶对象的引用
	m_dc.TransparentBlt(tmp.moveRect.left, tmp.moveRect.top, m_bfSize.cx, m_bfSize.cy
		, &m_bf_dc, 0, 0, m_bfSize.cx, m_bfSize.cy, transColor); // 使用透明色绘制蝴蝶

	CheckDirection(tmp); // 检查蝴蝶的移动方向

	// 标记蝴蝶数量
	CString str;
	str.Format(_T("%d"), numStr++);
	m_dc.SetBkColor(RGB(255, 255, 255));
	m_dc.TextOutW(tmp.moveRect.left, tmp.moveRect.top, str); // 在蝴蝶位置绘制标记文字
}

dc.BitBlt(0, 0, m_winRect.Width(), m_winRect.Height()
	, &m_dc, 0, 0, SRCCOPY); // 将内存设备上下文对象中的图像拷贝到屏幕上

tmp_dc.DeleteDC(); // 删除临时设备上下文对象
m_dc.DeleteDC(); // 删除设备上下文对象
m_bf_dc.DeleteDC(); // 删除蝴蝶设备上下文对象
return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值