优化Duilib图片属性解析代码,提升绘制效率

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/51245751         好长时间没写duilib博客了,最近在写毕业设计,毕设的软件界面自然就用比较熟悉的Duilib来搞了,正好把Duilib的一些地方一起改改。

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


         好长时间没写duilib博客了,最近在写毕业设计,毕设的软件界面自然就用比较熟悉的Duilib来搞了,正好把Duilib的一些地方一起改改。


         Duilib的图片绘制代码中有个影响性能的地方,所有的控件的图片绘制都是调用CControlUI的DrawImage函数,而此函数调用了CRenderEngine的DrawImageString函数。在绘制图片时,DrawImageString会解析图片字符串的属性,然后找到对片的HBITMAP资源,最后调用真正的绘图函数去绘制。问题就在于每绘制一个图片都会再次解析一次字符串,当界面比较复杂,而且图片字符串也比较复杂时,这个解析的过程就影响了程序效率。


         实际上这个字符串在被赋值后,只需要解析一次,然后缓存起来就可以了,在绘制图片时直接用缓存好的图片属性数据。使用内存换效率的方法可以进一步提高Duilib的效率。


        写了一个图片属性解析类,代替原本的图片字符串,并且去掉了原本的DrawImageString函数。


class UILIB_API CImageAttribute
{
public:
	CImageAttribute();
	CImageAttribute(const CImageAttribute&);
	const CImageAttribute& operator=(const CImageAttribute&);
	virtual ~CImageAttribute();

    CDuiString GetAttributeString() const;
	void SetAttributeString(LPCTSTR pStrImageAttri);
	void ModifyAttribute(LPCTSTR pStrModify);
	bool LoadImage(CPaintManagerUI* pManager);
	bool IsLoadSuccess();

	operator LPCTSTR() const;
	bool operator ==(LPCTSTR pStrImage) const;
	const CDuiString& operator=(const CDuiString& src);
	const CDuiString& operator=(const TCHAR ch);
	const CDuiString& operator=(LPCTSTR pstr);
private:
	void Clone(const CImageAttribute&);
	void Clear();
	void ParseAttribute(LPCTSTR pStrImageAttri);

protected:
	friend class CRenderEngine;
	CDuiString	m_sImageAttribute;

	CDuiString	m_sImage;
	CDuiString	m_sResType;
	TImageInfo	*m_imageInfo;
	bool		m_bLoadSuccess;

	RECT	m_rcDest;
	RECT	m_rcSource;
	RECT	m_rcCorner;
	BYTE	m_bFade;
	DWORD	m_dwMask;
	bool	m_bHole;
	bool	m_bTiledX;
	bool	m_bTiledY;

};

	CImageAttribute::CImageAttribute()
	{
		Clear();
	}

	CImageAttribute::CImageAttribute(const CImageAttribute& image)
	{
		Clone(image);
	}

	const CImageAttribute& CImageAttribute::operator=(const CImageAttribute& image)
	{
		Clone(image);
		return *this;
	}

	void CImageAttribute::Clone(const CImageAttribute& image)
	{
		m_sImageAttribute = image.m_sImageAttribute;

		m_sImage = image.m_sImage;
		m_sResType = image.m_sResType;
		m_imageInfo = image.m_imageInfo;
		m_bLoadSuccess = image.m_bLoadSuccess;

		m_rcDest = image.m_rcDest;
		m_rcSource = image.m_rcSource;
		m_rcCorner = image.m_rcCorner;
		m_bFade = image.m_bFade;
		m_dwMask = image.m_dwMask;
		m_bHole = image.m_bHole;
		m_bTiledX = image.m_bTiledX;
		m_bTiledY = image.m_bTiledY;
	}

	CImageAttribute::~CImageAttribute()
	{

	}

	CDuiString CImageAttribute::GetAttributeString() const
	{
		return m_sImageAttribute;
	}

	void CImageAttribute::SetAttributeString(LPCTSTR pStrImageAttri)
	{
		if (m_sImageAttribute == pStrImageAttri)
			return;

		Clear();

		m_sImageAttribute = pStrImageAttri;
		m_sImage = m_sImageAttribute;
		ParseAttribute(pStrImageAttri);
	}

	bool CImageAttribute::LoadImage(CPaintManagerUI* pManager)
	{
		if (m_imageInfo != NULL)
			return true;
		if (!m_bLoadSuccess)
			return false;

		const TImageInfo* data = NULL;
		if (m_sResType.IsEmpty())
		{
			data = pManager->GetImageEx((LPCTSTR)m_sImage, NULL, m_dwMask);
		}
		else
		{
			data = pManager->GetImageEx((LPCTSTR)m_sImage, (LPCTSTR)m_sResType, m_dwMask);
		}
		if (data == NULL)
		{
			m_bLoadSuccess = false;
			return false;
		}
		else
		{
			m_bLoadSuccess = true;
		}
		
		if (m_rcSource.left == 0 && m_rcSource.right == 0 && m_rcSource.top == 0 && m_rcSource.bottom == 0)
		{
			m_rcSource.right = data->nX;
			m_rcSource.bottom = data->nY;
		}
		if (m_rcSource.right > data->nX) m_rcSource.right = data->nX;
		if (m_rcSource.bottom > data->nY) m_rcSource.bottom = data->nY;
		m_imageInfo = const_cast<TImageInfo*>(data);

		return true;
	}

	bool CImageAttribute::IsLoadSuccess()
	{
		return !m_sImageAttribute.IsEmpty() && m_bLoadSuccess;
	}

	void CImageAttribute::ModifyAttribute(LPCTSTR pStrModify)
	{
		ParseAttribute(pStrModify);
	}

	void CImageAttribute::Clear()
	{
		m_sImageAttribute.Empty();
		m_sImage.Empty();
		m_sResType.Empty();
		m_imageInfo = NULL;
		m_bLoadSuccess = true;
		ZeroMemory(&m_rcDest, sizeof(RECT));
		ZeroMemory(&m_rcSource, sizeof(RECT));
		ZeroMemory(&m_rcCorner, sizeof(RECT));
		m_bFade = 0xFF;
		m_dwMask = 0;
		m_bHole = false;
		m_bTiledX = false;
		m_bTiledY = false;
	}

	void CImageAttribute::ParseAttribute(LPCTSTR pStrImage)
	{
		if (pStrImage == NULL)
			return;

		// 1、aaa.jpg
		// 2、file='aaa.jpg' res='' restype='0' dest='0,0,0,0' source='0,0,0,0' corner='0,0,0,0' 
		// mask='#FF0000' fade='255' hole='false' xtiled='false' ytiled='false'
		CDuiString sItem;
		CDuiString sValue;
		LPTSTR pstr = NULL;

		while (*pStrImage != _T('\0'))
		{
			sItem.Empty();
			sValue.Empty();
			while (*pStrImage > _T('\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
			while (*pStrImage != _T('\0') && *pStrImage != _T('=') && *pStrImage > _T(' '))
			{
				LPTSTR pstrTemp = ::CharNext(pStrImage);
				while (pStrImage < pstrTemp)
				{
					sItem += *pStrImage++;
				}
			}
			while (*pStrImage > _T('\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
			if (*pStrImage++ != _T('=')) break;
			while (*pStrImage > _T('\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
			if (*pStrImage++ != _T('\'')) break;
			while (*pStrImage != _T('\0') && *pStrImage != _T('\''))
			{
				LPTSTR pstrTemp = ::CharNext(pStrImage);
				while (pStrImage < pstrTemp)
				{
					sValue += *pStrImage++;
				}
			}
			if (*pStrImage++ != _T('\'')) break;
			if (!sValue.IsEmpty())
			{
				if (sItem == _T("file") || sItem == _T("res"))
				{
					m_sImage = sValue;
				}
				else if (sItem == _T("restype"))
				{					
					m_sResType = sValue;
				}
				else if (sItem == _T("dest"))
				{
					m_rcDest.left = _tcstol(sValue.GetData(), &pstr, 10);  ASSERT(pstr);
					m_rcDest.top = _tcstol(pstr + 1, &pstr, 10);    ASSERT(pstr);
					m_rcDest.right = _tcstol(pstr + 1, &pstr, 10);  ASSERT(pstr);
					m_rcDest.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
				}
				else if (sItem == _T("source"))
				{
					m_rcSource.left = _tcstol(sValue.GetData(), &pstr, 10);  ASSERT(pstr);
					m_rcSource.top = _tcstol(pstr + 1, &pstr, 10);    ASSERT(pstr);
					m_rcSource.right = _tcstol(pstr + 1, &pstr, 10);  ASSERT(pstr);
					m_rcSource.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
				}
				else if (sItem == _T("corner"))
				{
					m_rcCorner.left = _tcstol(sValue.GetData(), &pstr, 10);  ASSERT(pstr);
					m_rcCorner.top = _tcstol(pstr + 1, &pstr, 10);    ASSERT(pstr);
					m_rcCorner.right = _tcstol(pstr + 1, &pstr, 10);  ASSERT(pstr);
					m_rcCorner.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
				}
				else if (sItem == _T("mask"))
				{
					if (sValue[0] == _T('#')) m_dwMask = _tcstoul(sValue.GetData() + 1, &pstr, 16);
					else m_dwMask = _tcstoul(sValue.GetData(), &pstr, 16);
				}
				else if (sItem == _T("fade"))
				{
					m_bFade = (BYTE)_tcstoul(sValue.GetData(), &pstr, 10);
				}
				else if (sItem == _T("hole"))
				{
					m_bHole = (_tcscmp(sValue.GetData(), _T("true")) == 0);
				}
				else if (sItem == _T("xtiled"))
				{
					m_bTiledX = (_tcscmp(sValue.GetData(), _T("true")) == 0);
				}
				else if (sItem == _T("ytiled"))
				{
					m_bTiledY = (_tcscmp(sValue.GetData(), _T("true")) == 0);
				}
			}
			if (*pStrImage++ != _T(' ')) break;
		}
	}

	CImageAttribute::operator LPCTSTR() const
	{
		return m_sImageAttribute;
	}

	bool CImageAttribute::operator==(LPCTSTR pStrImage) const
	{
		return m_sImageAttribute == pStrImage;
	}

	const CDuiString& CImageAttribute::operator=(const CDuiString& src)
	{
		SetAttributeString(src);
		return m_sImageAttribute;
	}

	const CDuiString& CImageAttribute::operator=(LPCTSTR lpStr)
	{
		SetAttributeString(lpStr);
		return m_sImageAttribute;
	}

	const CDuiString& CImageAttribute::operator=(const TCHAR ch)
	{
		m_sImageAttribute = ch;
		SetAttributeString(m_sImageAttribute);
		return m_sImageAttribute;
	}

       对CControlUI控件的修改如下:

bool CControlUI::DrawImage(HDC hDC, CImageAttribute& image, const RECT& rcDest, LPCTSTR pStrModify /*= NULL*/)
{
	if (!image.LoadImage(m_pManager))
		return false;

	if (pStrModify != NULL)
	{
		CImageAttribute modifyImage = image;
		modifyImage.ModifyAttribute(pStrModify);
		return CRenderEngine::DrawImage(hDC, m_pManager, rcDest, m_rcPaint, modifyImage);
	}
	return CRenderEngine::DrawImage(hDC, m_pManager, rcDest, m_rcPaint, image);
}

       为CRenderEngine类新增DrawImage函数代替DrawImageString函数:

bool CRenderEngine::DrawImage(HDC hDC, CPaintManagerUI* pManager, const RECT& rcControl, const RECT& rcPaint, CImageAttribute& image)
{
	if ((pManager == NULL) || (hDC == NULL))
		return false;

	if (image.m_sImage.IsEmpty())
		return false;

	TImageInfo* data = image.m_imageInfo;
	if (!data) return false;

	RECT rcDest = image.m_rcDest;
	rcDest.left += rcControl.left;
	rcDest.top += rcControl.top;
	rcDest.right = rcDest.left + rcControl.right;
	if (rcDest.right > rcControl.right)
		rcDest.right = rcControl.right;
	rcDest.bottom = rcDest.top + rcControl.bottom;
	if (rcDest.bottom > rcControl.bottom)
		rcDest.bottom = rcControl.bottom;

	RECT rcTemp;
	if (!::IntersectRect(&rcTemp, &rcDest, &rcControl)) return true;
	if (!::IntersectRect(&rcTemp, &rcDest, &rcPaint)) return true;

	CRenderEngine::DrawImage(hDC, data->hBitmap, rcDest, rcPaint, image.m_rcSource, image.m_rcCorner,
		pManager->IsBackgroundTransparent() ? true : data->alphaChannel,
		image.m_bFade, image.m_bHole, image.m_bTiledX, image.m_bTiledY);

	return true;
}


总结:

        这次修改的内容比较多,因为每个控件原本都有图片字符串,所以我把很多控件的绘制代码对应的修改了,这些就不贴了。所有控件的修改我都提交到我个人的Duilib库中: 点击打开链接


Redrain QQ:491646717 2016.4.26

目录
相关文章
|
27天前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
131 9
|
2月前
|
消息中间件 存储 缓存
十万订单每秒热点数据架构优化实践深度解析
【11月更文挑战第20天】随着互联网技术的飞速发展,电子商务平台在高峰时段需要处理海量订单,这对系统的性能、稳定性和扩展性提出了极高的要求。尤其是在“双十一”、“618”等大型促销活动中,每秒需要处理数万甚至数十万笔订单,这对系统的热点数据处理能力构成了严峻挑战。本文将深入探讨如何优化架构以应对每秒十万订单级别的热点数据处理,从历史背景、功能点、业务场景、底层原理以及使用Java模拟示例等多个维度进行剖析。
66 8
|
14天前
|
人工智能 搜索推荐 API
Cobalt:开源的流媒体下载工具,支持解析和下载全平台的视频、音频和图片,支持多种视频质量和格式,自动提取视频字幕
cobalt 是一款开源的流媒体下载工具,支持全平台视频、音频和图片下载,提供纯净、简洁无广告的体验
157 9
Cobalt:开源的流媒体下载工具,支持解析和下载全平台的视频、音频和图片,支持多种视频质量和格式,自动提取视频字幕
|
22天前
|
自然语言处理 搜索推荐 数据安全/隐私保护
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
鸿蒙登录页面设计展示了 HarmonyOS 5.0(Next)的未来美学理念,结合科技与艺术,为用户带来视觉盛宴。该页面使用 ArkTS 开发,支持个性化定制和无缝智能设备连接。代码解析涵盖了声明式 UI、状态管理、事件处理及路由导航等关键概念,帮助开发者快速上手 HarmonyOS 应用开发。通过这段代码,开发者可以了解如何构建交互式界面并实现跨设备协同工作,推动智能生态的发展。
137 10
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
|
1月前
|
机器学习/深度学习 人工智能 PyTorch
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
本文探讨了Transformer模型中变长输入序列的优化策略,旨在解决深度学习中常见的计算效率问题。文章首先介绍了批处理变长输入的技术挑战,特别是填充方法导致的资源浪费。随后,提出了多种优化技术,包括动态填充、PyTorch NestedTensors、FlashAttention2和XFormers的memory_efficient_attention。这些技术通过减少冗余计算、优化内存管理和改进计算模式,显著提升了模型的性能。实验结果显示,使用FlashAttention2和无填充策略的组合可以将步骤时间减少至323毫秒,相比未优化版本提升了约2.5倍。
63 3
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
|
1月前
|
前端开发 UED
React 文本区域组件 Textarea:深入解析与优化
本文介绍了 React 中 Textarea 组件的基础用法、常见问题及优化方法,包括状态绑定、初始值设置、样式自定义、性能优化和跨浏览器兼容性处理,并提供了代码案例。
67 8
|
2月前
|
缓存 NoSQL Java
千万级电商线上无阻塞双buffer缓冲优化ID生成机制深度解析
【11月更文挑战第30天】在千万级电商系统中,ID生成机制是核心基础设施之一。一个高效、可靠的ID生成系统对于保障系统的稳定性和性能至关重要。本文将深入探讨一种在千万级电商线上广泛应用的ID生成机制——无阻塞双buffer缓冲优化方案。本文从概述、功能点、背景、业务点、底层原理等多个维度进行解析,并通过Java语言实现多个示例,指出各自实践的优缺点。希望给需要的同学提供一些参考。
55 7
|
1月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
1月前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
33 1
|
2月前
|
缓存 并行计算 Linux
深入解析Linux操作系统的内核优化策略
本文旨在探讨Linux操作系统内核的优化策略,包括内核参数调整、内存管理、CPU调度以及文件系统性能提升等方面。通过对这些关键领域的分析,我们可以理解如何有效地提高Linux系统的性能和稳定性,从而为用户提供更加流畅和高效的计算体验。
43 2

推荐镜像

更多