duilib的所有控件均绘制在唯一的真实窗口之中,本篇就具体看下这个绘制的过程。所有的绘制过程均在WM_PAINT消息处理过程中完成。由窗口及消息篇可以看到,窗口消息处理最终流到了CPaintManagerUI::MessageHandler中。包括WM_PAINT在内消息均在此函数中处理,我们仅关注WM_PAINT消息

     case WM_PAINT:
{
// Should we paint?
RECT rcPaint = { };
if( !::GetUpdateRect(m_hWndPaint, &rcPaint, FALSE) ) return true;
if( m_pRoot == NULL ) {
PAINTSTRUCT ps = { };
::BeginPaint(m_hWndPaint, &ps);
::EndPaint(m_hWndPaint, &ps);
return true;
}
// Do we need to resize anything?
// This is the time where we layout the controls on the form.
// We delay this even from the WM_SIZE messages since resizing can be
// a very expensize operation.
if( m_bUpdateNeeded ) {
m_bUpdateNeeded = false;
RECT rcClient = { };
::GetClientRect(m_hWndPaint, &rcClient);
if( !::IsRectEmpty(&rcClient) ) {
if( m_pRoot->IsUpdateNeeded() ) {
m_pRoot->SetPos(rcClient);
if( m_hDcOffscreen != NULL ) ::DeleteDC(m_hDcOffscreen);
if( m_hDcBackground != NULL ) ::DeleteDC(m_hDcBackground);
if( m_hbmpOffscreen != NULL ) ::DeleteObject(m_hbmpOffscreen);
if( m_hbmpBackground != NULL ) ::DeleteObject(m_hbmpBackground);
m_hDcOffscreen = NULL;
m_hDcBackground = NULL;
m_hbmpOffscreen = NULL;
m_hbmpBackground = NULL;
}
else {
CControlUI* pControl = NULL;
while( pControl = m_pRoot->FindControl(__FindControlFromUpdate, NULL, UIFIND_VISIBLE | UIFIND_ME_FIRST) ) {
pControl->SetPos( pControl->GetPos() );
}
}
// We'll want to notify the window when it is first initialized
// with the correct layout. The window form would take the time
// to submit swipes/animations.
if( m_bFirstLayout ) {
m_bFirstLayout = false;
SendNotify(m_pRoot, _T("windowinit"), , , false);
}
}
}
// Set focus to first control?
if( m_bFocusNeeded ) {
SetNextTabControl();
}
//
// Render screen
//
// Prepare offscreen bitmap?
if( m_bOffscreenPaint && m_hbmpOffscreen == NULL )
{
RECT rcClient = { };
::GetClientRect(m_hWndPaint, &rcClient);
m_hDcOffscreen = ::CreateCompatibleDC(m_hDcPaint);
m_hbmpOffscreen = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
ASSERT(m_hDcOffscreen);
ASSERT(m_hbmpOffscreen);
}
// Begin Windows paint
PAINTSTRUCT ps = { };
::BeginPaint(m_hWndPaint, &ps);
if( m_bOffscreenPaint )
{
HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(m_hDcOffscreen, m_hbmpOffscreen);
int iSaveDC = ::SaveDC(m_hDcOffscreen);
if( m_bAlphaBackground ) {
if( m_hbmpBackground == NULL ) {
RECT rcClient = { };
::GetClientRect(m_hWndPaint, &rcClient);
m_hDcBackground = ::CreateCompatibleDC(m_hDcPaint);;
m_hbmpBackground = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
ASSERT(m_hDcBackground);
ASSERT(m_hbmpBackground);
::SelectObject(m_hDcBackground, m_hbmpBackground);
::BitBlt(m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top, ps.hdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
}
else
::SelectObject(m_hDcBackground, m_hbmpBackground);
::BitBlt(m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top, m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
}
m_pRoot->DoPaint(m_hDcOffscreen, ps.rcPaint);//绘制控件
for( int i = ; i < m_aPostPaintControls.GetSize(); i++ ) {
CControlUI* pPostPaintControl = static_cast<CControlUI*>(m_aPostPaintControls[i]);
pPostPaintControl->DoPostPaint(m_hDcOffscreen, ps.rcPaint);
}
::RestoreDC(m_hDcOffscreen, iSaveDC);
::BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top, m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
::SelectObject(m_hDcOffscreen, hOldBitmap); if( m_bShowUpdateRect ) {
HPEN hOldPen = (HPEN)::SelectObject(ps.hdc, m_hUpdateRectPen);
::SelectObject(ps.hdc, ::GetStockObject(HOLLOW_BRUSH));
::Rectangle(ps.hdc, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
::SelectObject(ps.hdc, hOldPen);
}
}
else
{
// A standard paint job
int iSaveDC = ::SaveDC(ps.hdc);
m_pRoot->DoPaint(ps.hdc, ps.rcPaint);//绘制控件
::RestoreDC(ps.hdc, iSaveDC);
}
// All Done!
::EndPaint(m_hWndPaint, &ps);
}
// If any of the painting requested a resize again, we'll need
// to invalidate the entire window once more.
if( m_bUpdateNeeded ) {
::InvalidateRect(m_hWndPaint, NULL, FALSE);
}
return true;

在::BeginPaint(m_hWndPaint, &ps)和::EndPaint(m_hWndPaint, &ps)中间是窗口绘制部分,duilib包含了两种方式:双缓存方式(解决闪烁问题)和标准方式,默认为双缓存方式。两种方式最终都调用了m_pRoot->DoPaint,m_pRoot为控件容器,且DoPaint为虚函数,实际调用了CContainerUI::DoPaint

 void CContainerUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
RECT rcTemp = { };
if( !::IntersectRect(&rcTemp, &rcPaint, &m_rcItem) ) return; CRenderClip clip;
CRenderClip::GenerateClip(hDC, rcTemp, clip);
CControlUI::DoPaint(hDC, rcPaint); if( m_items.GetSize() > ) {
RECT rc = m_rcItem;
rc.left += m_rcInset.left;
rc.top += m_rcInset.top;
rc.right -= m_rcInset.right;
rc.bottom -= m_rcInset.bottom;
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) rc.right -= m_pVerticalScrollBar->GetFixedWidth();
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight(); if( !::IntersectRect(&rcTemp, &rcPaint, &rc) ) {
for( int it = ; it < m_items.GetSize(); it++ ) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
if( !pControl->IsVisible() ) continue;
if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
if( pControl ->IsFloat() ) {
if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
pControl->DoPaint(hDC, rcPaint);
}
}
}
else {
CRenderClip childClip;
CRenderClip::GenerateClip(hDC, rcTemp, childClip);
for( int it = ; it < m_items.GetSize(); it++ ) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
if( !pControl->IsVisible() ) continue;
if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
if( pControl ->IsFloat() ) {
if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
CRenderClip::UseOldClipBegin(hDC, childClip);
pControl->DoPaint(hDC, rcPaint);
CRenderClip::UseOldClipEnd(hDC, childClip);
}
else {
if( !::IntersectRect(&rcTemp, &rc, &pControl->GetPos()) ) continue;
pControl->DoPaint(hDC, rcPaint);
}
}
}
} if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() ) {
if( ::IntersectRect(&rcTemp, &rcPaint, &m_pVerticalScrollBar->GetPos()) ) {
m_pVerticalScrollBar->DoPaint(hDC, rcPaint);
}
} if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {
if( ::IntersectRect(&rcTemp, &rcPaint, &m_pHorizontalScrollBar->GetPos()) ) {
m_pHorizontalScrollBar->DoPaint(hDC, rcPaint);
}
}
}

控件容器绘制完自己后,遍历子控件(包括子控件容器)调用其DoPaint,完成子控件绘制

 void CControlUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
if( !::IntersectRect(&m_rcPaint, &rcPaint, &m_rcItem) ) return; // 绘制循序:背景颜色->背景图->状态图->文本->边框
if( m_cxyBorderRound.cx > || m_cxyBorderRound.cy > ) {
CRenderClip roundClip;
CRenderClip::GenerateRoundClip(hDC, m_rcPaint, m_rcItem, m_cxyBorderRound.cx, m_cxyBorderRound.cy, roundClip);
PaintBkColor(hDC);
PaintBkImage(hDC);
PaintStatusImage(hDC);
PaintText(hDC);
PaintBorder(hDC);
}
else {
PaintBkColor(hDC);
PaintBkImage(hDC);
PaintStatusImage(hDC);
PaintText(hDC);
PaintBorder(hDC);
}
}

最终的绘制都是通过渲染引擎CRenderEngine实现的。

这样看来,整个绘制思路还是很清晰的:CPaintManagerUI::MessageHandler(WM_PAINT)--->CContainerUI::DoPaint--->CControlUI::DoPaint--->CRenderEngine。

DuiLib(四)——控件绘制的更多相关文章

  1. ZedGrap控件绘制图表曲线

    问题描述: 使用C#中ZedGrap控件绘制图表曲线图 ZedGrap 介绍说明:     安装ZedGrap控件 ZedGraph控件dll文件: 添加ZedGraph控件,首先在新建立的C#图像工 ...

  2. C# chart控件绘制曲线

    在.NET中以前经常用GDI去绘制,虽然效果也不错,自从.NET 4.0开始,专门为绘制图表而生的Chart控件出现了,有了它,就可以轻松的绘制你所需要的曲线图.柱状图什么的了. using Syst ...

  3. 用Chart控件绘制动态图表

    进行程序设计时,选用一个合适的ActiveX控件,有时可大大减少编程工作量.ActiveX 控件(又称OCX)基于COM技术,作为独立的软件模块,它可以在任何程序设计语言中插入使用.本文仅以VC++为 ...

  4. c# 通过.net自带的chart控件绘制饼图pie chart

    c# 通过.net自带的chart控件绘制饼图pie chart   需要实现的目标是: 1.将数据绑定到pie的后台数据中,自动生成饼图. 2.生成的饼图有详细文字的说明. 具体的实现步骤: > ...

  5. Expression Blend学习四控件

    原文:Expression Blend学习四控件 Expression Blend制作自定义按钮 1.从Blend工具箱中添加一个Button,按住shift,将尺寸调整为125*125; 2.右键点 ...

  6. 增加duilib edit控件的提示功能和多种文字颜色

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41786407 duilib的CEditUI控件内部使用了win32的原生 ...

  7. XE6 FMX之控件绘制与显示

    中午,有个货随手买的2块钱的彩票,尼玛中了540块,这是啥子狗屎气运.稍微吐槽一下,现在开始正规的笔记录入.经常有朋友说为毛我的博客不更新了或者说更新的少了,为啥呢!一来自己懒了,没学习什么新的东西, ...

  8. duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复

    转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42264673 关于这个bug的修复我之前写过一篇博客,连接为:http:/ ...

  9. 修复duilib CEditUI控件和CWebBrowserUI控件中按Tab键无法切换焦点的bug

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41556615 在duilib中,按tab键会让焦点在Button一类的控 ...

随机推荐

  1. Arc Engine 中添加气泡提示框

    一.在ArcMap中的定位操作 已知若干点的经纬度坐标,要求在地图中进行定位: 1.通过Tool >Add X Y data 定位点,注意选择地理坐标系下的wgs 1984坐标系: 2.定位后的 ...

  2. mybatis返回HashMap结果类型与映射

    <!-- 返回HashMap结果 类型--> <!-- 如果想返回JavaBean,只需将resultType设置为JavaBean的别名或全限定名 --> <!-- T ...

  3. 如何清除win7开机密码

    一.电脑已经登录到系统,但是忘记了密1对于这种情况是最简单的,其实只需要将密码取消就可以了右键单击桌面上我的电脑,选择管理即可进入计算机管理界面2依次展开系统工具--本地用户和组--用户,在右侧选择要 ...

  4. (原创)LAMP教程6-使用SecureCRTPortable工具远程连接centos

    (原创)LAMP教程6-使用SecureCRTPortable工具远程连接centos 是的,今天老柯就给大家介绍一款可以远程连接centos的工具,是的这个就是目前,最夯实的,最多人使用的Secur ...

  5. [Tommas] 测试用例覆盖率(三)

    三.测试数据的设计 每一个测试思路最终都要转化成具体的数据才能来执行.关于测试数据设计的方法也不外乎那几种,就不再赘述了.此处单就一些经常易犯的错误,提出一些注意点,作为用例数据设计时的参考: 1.尽 ...

  6. [GRYZ2015]Graph

    题目描述 给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点. 输入格式 第 1 行,2 个整数 N,M. 接下来 M 行,每行 2 个整数 Ui ...

  7. 如果你喜欢Python 那么你不得不知的几个开源项目

    1.Trac Trac拥有强大的bug管理 功能,并集成了Wiki 用于文档管理.它还支持代码管理工具Subversion ,这样可以在 bug管理和Wiki中方便地参考程序源代码. Trac有着比较 ...

  8. kobo boot scripts

    #!/bin/sh pkill nickel eink_enable_autoupdate rm -rf /debian/tmp/* /debian/tmp/.* 2>/dev/null mou ...

  9. 定位程序问题的方法 -- clwu

    原本的标题的<定位程序代码的方法>,但问题有时候超出了自己代码的范围,而是别人的程序,所以今天想分享的是一个通用的分析问题(程序)的思路. 先来说一下在使用别人的程序(Vim)过程中遇到问 ...

  10. Junit3.8 Stack测试

    package test; public class MyStack { private String[] elements; private int nextIndex; public MyStac ...