转载请说明原出处,谢谢~·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