duilib制作窗体动画效果

简介: 转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/49026605        最近一段时间没写博客了,感觉最近没有遇到什么必须解决的bug。

转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/49026605


        最近一段时间没写博客了,感觉最近没有遇到什么必须解决的bug。在一年前我把自己写的仿酷狗音乐播放器Demo写到博客时,我在博客末尾写过以后会做异形窗体和窗体动画的功能。异形窗体在半年前大概做完并且集成到我的库里了,但是窗体动画Demo没有写到博客。之前就有网友问我窗体动画的制作方法,一直懒着没写,不好意思···。

 

       今天把窗体动画的制作思路和Demo说明一下。实际上,异形窗体写完了,也就可以说窗体动画功能也写完了,因为窗体动画效果只是在使用半透明异形窗体技术基础上的一个应用。关于异形窗体的博客:使用duilib开发半透明异形窗体程序(附源码和demo)


        首先把效果图展示一下,本来是有79个特效,但是由于csdn博客的图片限制,只能录一小部分了···:



       这里特别声明,我使用的这个动画特效算法不是自己写的,而是使用了开源的界面库UiFeature的特效算法组件,非常感觉UiFeature作者的开源(UiFeature的下载地址:http://yunpan.cn/cZLr5zDIdW8ZT (提取码:ec84)),这同样是个很不错的界面库,UiFeature的动画特效是其一大亮点,而动画特效是个独立的DLL,我这里直接移植到我的Duilib窗体动画Demo里。


       说明一下窗体动画的开发步骤和注意点:

        1、开启窗体半透明异形功能(原生DuiLib不支持,不过包括我在内的不少维护Duilib的朋友的库都支持,其他的很多界面库也都支持),这个是根本,因为使用UpdateLayeredWindow函数使窗体拥有半透明异形功能后,就可以使用位图来绘制出窗体,而动画实际上就是有规律变化的连续位图。所以把动画位图定时贴到异形窗体上,就是窗体动画了~~。

       2、自定义一个容器控件,作为窗体的根容器

       3、开始动画时,截取自定义控件的渲染位图,用来计算动画效果

       4、为自定义容器增加一个定时器来用动画算法定时计算动画效果

       5、重写控件的DoPaint方法,把计算后的动画位图绘制出来


      实际上窗体动画是属于控件动画的范畴,在半透明异形窗体中,根容器的效果无疑就是窗体的效果,所以窗体动画的开发实际就转变为了控件动画的开发。把上述方法的根容器改为控件,那就是控件动画的开发步骤。


代码讲解:

     

       首先我的库支持透明异性功能,这满足了第一个要求。接下来定义一个容器控件,只要把他作为窗体xml的根容器,就可以做出窗体动画

class AnimLayout : public CVerticalLayoutUI, public IUIEffectCallBack
{
public:
	AnimLayout();
	~AnimLayout();

	virtual LPCTSTR GetClass() const override;
	virtual LPVOID GetInterface(LPCTSTR pstrName) override;
	virtual void DoPaint(HDC hDC, const RECT& rcPaint) override;
	virtual void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) override;

	bool StartEffect();
	void OnTimer(int iCurFrame);

public:
	// 每一 个 动画开始时回调
	virtual void OnUiEffectBegin(WPARAM effectKey, DWORD animaType) override;
	// 每一 个 动画结束时回调
	virtual void OnUiEffectEnd(WPARAM effectKey, DWORD animaType) override;
	// 每一 帧 动画绘制时回调
	virtual void OnUiEffectDraw() override;

private:
	bool				m_bPlaying;
	HDC					m_hMemDc;
	HBITMAP				m_hOldBitmap;
	HBITMAP				m_hTransBitmap;

	DWORD						m_dwEffectNum;
	IUiEffectManagerImpl*		m_pEffectManager;
	IUIEffect*					m_pEffect;

public:
	static const LPCTSTR kAnimLayoutClass;
	static const LPCTSTR kAnimLayoutInterface;
};

        当需要使用动画特效时,调用StartEffect函数,函数源码为:

bool AnimLayout::StartEffect()
{
	if (m_bPlaying)
		return false;
	if (m_dwEffectNum > 80)
	{
		m_dwEffectNum = 2;
		return false;
	}
		
	//LPDWORD pBmpBits = NULL;
	m_hMemDc = ::CreateCompatibleDC(m_pManager->GetPaintDC());
	m_hTransBitmap = CRenderEngine::GenerateBitmap(m_pManager, this, m_rcItem); 
	if (m_hTransBitmap == NULL)
		return false;
	m_hOldBitmap = (HBITMAP) ::SelectObject(m_hMemDc, m_hTransBitmap);

	BITMAP bmDst;
	GetObject(m_hTransBitmap, sizeof(bmDst), &bmDst);
	SIZE szMemDc = { bmDst.bmWidth, bmDst.bmHeight };

	//修补一下Alpha通道,一些控件(Richedit)会让Alpha为0
	RECT rcRestore = m_rcItem;
	CRenderEngine::RestoreAlphaColor((LPBYTE)bmDst.bmBits, bmDst.bmWidth, &rcRestore);

	// 填充动画参数
	AnimationParam animParam;
	animParam.effectKey = (WPARAM)this;				//控件指针
	animParam.animationEffect = m_dwEffectNum++;	//动画类型,从2-80,1为自定义动画,并没有移植过来
	animParam.animationFrequency = 20;				//动画间隔
	animParam.bShow = TRUE;							//动画顺序
	animParam.hBitmap = m_hTransBitmap;
	animParam.pBmpData = (BYTE*)bmDst.bmBits;
	animParam.bmpSize = szMemDc;
	animParam.hdc = m_hMemDc;

	BOOL bRet = m_pEffect->AppendAnimation(animParam);
	ASSERT(bRet);

	m_bPlaying = true;

	// 这里是同步执行的,Animation函数在动画完毕后返回
	bRet = m_pEffect->Animation(dynamic_cast<IUIEffectCallBack*>(this), 0);
	ASSERT(bRet);

	// 递归演示所有动画效果,这只是为了演示效果,实际开发不要这样做!
	StartEffect();

	return true;
}

        在代码里可以看到,开启动画时,调用CRenderEngine类的GenerateBitmap静态函数,使用这个函数可以获取到某个控件的渲染位图,这就满足了第三个要求。接下来应该是开启定时器来使用算法来定时计算位图,如果要精度要求不高那就可以直接调用CPaintManagerUI类的SetTimer方法,并且在自定义控件里响应定时消息来计算位图, 计算后调用Invalidate函数来刷新控件。


        不过UiFeature的这个特效组件的Animation函数,已经自带了定时功能,并且在填充了参数后会自动计算了位图,只要重写IUIEffectCallBack接口的OnUiEffectDraw方法来刷新窗体就可以了。所以和正常开发步骤有一些区别。


        最后重写DoPaint函数:

void AnimLayout::DoPaint(HDC hDC, const RECT& rcPaint)
{
	if (!m_bPlaying)
	{
		__super::DoPaint(hDC, rcPaint);
		return;
	}

	typedef BOOL(WINAPI *LPALPHABLEND)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION);
	static LPALPHABLEND lpAlphaBlend = (LPALPHABLEND) ::GetProcAddress(::GetModuleHandle(_T("msimg32.dll")), "AlphaBlend");

	BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };

	lpAlphaBlend(hDC, m_rcItem.left, m_rcItem.top, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top, m_hMemDc,
		0, 0, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top, bf);

}

        在函数里,判断如果正在使用动画特效,就不进行控件的正常绘制,而是直接调用AlphaBlend函数把计算后的位图贴到窗体dc上,就完成了第五步。 至此就做完了窗体动画!


总结:


        只要窗体动画的原理弄懂了,其实还是很简单的,几乎是比较固定的步骤,而动画制作的重点就转变为了动画算法。只要能找到或者设计出好的位图变换算法,就能做出很漂亮的窗体动画。

        我在做窗体动画Demo时做了两个,一个是文本提到的79变动画,另一个是仿QQ的窗体翻转动画(道理都是一样的,只是换了算法库,我就不另外说了)文中的Demo我会提交到我个人的Duilib库中:点击打开链接


Redrain QQ:491646717 2015.10.10


目录
相关文章
|
机器学习/深度学习 存储 传感器
【路径规划】基于Dijkstra算法求解机器人栅格地图路径规划及避障附Matlab代码
【路径规划】基于Dijkstra算法求解机器人栅格地图路径规划及避障附Matlab代码
|
28天前
|
人工智能 IDE 开发工具
编程范式的下一次跃迁:深度解析全新的 GitHub Copilot 独立桌面应用
2026年5月,GitHub发布Copilot独立桌面App技术预览版,标志着AI编程从IDE插件迈向原生智能体开发环境。它以Issue/PR为起点,提供隔离会话、内置终端与浏览器、自动合并PR等能力,实现“输入问题→输出通过CI的PR”闭环,推动开发者角色向高阶审查者演进。
932 2
|
2月前
|
机器学习/深度学习 搜索推荐 算法
Java+AI实战:从零构建智能推荐系统(二)
教程来源 https://tmywi.cn/category/jiaju.html 本节详解推荐系统核心模块:第三部分“召回算法”涵盖协同过滤(ItemCF)、向量召回(Embedding+ANN)及多路融合策略;第四部分“排序模型”介绍DeepFM——融合FM低阶交叉与DNN高阶特征的CTR预估模型,兼顾可解释性与表达能力。
|
前端开发 算法 NoSQL
前端uin后端php社交软件源码,快速构建属于你的交友平台
这是一款功能全面的社交软件解决方案,覆盖多种场景需求。支持即时通讯(一对一聊天、群聊、文件传输、语音/视频通话)、内容动态(发布、点赞、评论)以及红包模块(接入支付宝、微信等第三方支付)。系统采用前后端分离架构,前端基于 UniApp,后端使用 PHP 框架(如 Laravel/Symfony),配合 MySQL/Redis 和自建 Socket 服务实现高效实时通信。提供用户认证(JWT 集成)、智能匹配算法等功能,助力快速上线,显著节约开发成本。
516 2
前端uin后端php社交软件源码,快速构建属于你的交友平台
|
安全 算法 中间件
OASA 厂商三未信安完成与 Anolis OS 及其衍生版适配,密码卡性能与稳定性获验证
验证了 Anolis OS 能够满足用户对于数据保护和隐私安全的高标准要求,可以为广大用户提供更可靠的数据保护。
|
数据采集 供应链 API
实战指南:通过1688开放平台API获取商品详情数据(附Python代码及避坑指南)
1688作为国内最大的B2B供应链平台,其API为企业提供合法合规的JSON数据源,直接获取批发价、SKU库存等核心数据。相比爬虫方案,官方API避免了反爬严格、数据缺失和法律风险等问题。企业接入1688商品API需完成资质认证、创建应用、签名机制解析及调用接口四步。应用场景包括智能采购系统、供应商评估模型和跨境选品分析。提供高频问题解决方案及安全合规实践,确保数据安全与合法使用。立即访问1688开放平台,解锁B2B数据宝藏!
|
机器人 数据安全/隐私保护
基于PID控制器的六自由度串联机器人控制系统的simulink建模与仿真
本课题基于MATLAB2022a的Simulink环境,对六自由度串联机器人控制系统进行建模与仿真,采用PID控制器实现关节的位置、速度或力矩控制。PID控制器通过比例、积分、微分三种策略有效减小系统误差,提高响应速度和稳定性。仿真结果显示系统运行良好,无水印。尽管PID控制简单实用,但在复杂动力学环境下,常结合其他控制策略以增强鲁棒性。
|
数据采集 自然语言处理 搜索推荐
通义千问赋能CACA指南:构建智慧肿瘤诊疗新生态
本文探讨了如何利用阿里云通义千问大模型,结合中国抗癌协会(CACA)编撰的《中国肿瘤整合诊治指南》,打造新一代智能化临床决策支持系统。该系统通过分层架构设计,实现智能问答、临床决策支持和患者管理等功能,显著提升了医生的工作效率和治疗方案的科学性。
1097 1
|
Web App开发 前端开发 JavaScript
Web前端项目的跨平台桌面客户端打包方案之——CEF框架
Chromium Embedded Framework (CEF) 是一个基于 Google Chromium 项目的开源 Web 浏览器控件,旨在为第三方应用提供嵌入式浏览器支持。CEF 隔离了底层 Chromium 和 Blink 的复杂性,提供了稳定的产品级 API。它支持 Windows、Linux 和 Mac 平台,不仅限于 C/C++ 接口,还支持多种语言。CEF 功能强大,性能优异,广泛应用于桌面端开发,如 QQ、微信、网易云音乐等。CEF 开源且采用 BSD 授权,商业友好,装机量已超 1 亿。此外,GitHub 项目 CefDetector 可帮助检测电脑中使用 CEF
4417 3
|
存储 算法 NoSQL
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
1380 1

热门文章

最新文章