控件树

一步一步实现自己的模拟控件(1)中的图上我们可以看到,我们的控件体系其实就是一个控件树。每一个窗口关联一个根控件,所有控件都在这个根控件之下,父控件包容并管理子控件,那么我们的Widget就应该是一个树结点。一个树结点至少有对Parent和Chilren的设置和访问接口:

void SetParent(Widget* const pNewParent);
Widget* GetParent() const;

bool InsertChild(Widget* const pChild);
bool RemoveChild(Widget* const pChild);

在父控件销毁的时候它要负责销毁其下所有的子控件(类似窗口销毁也会销毁其子窗口):

Widget::~Widget()
{
// 销毁所有子控件
WidgetSet temp(std::move(pImpl_->children_));
std::for_each(temp.begin(), temp.end(), std::mem_fn(&Widget::Destroy));

if (IsRoot())
{
// 作为根控件,同时销毁驱动
delete pImpl_->pDriver_;
}
else
{
// 不是根控件,则脱离父控件
SetParent(0);
}

delete pImpl_;
}

实现中我们使用std::set来保存子控件,这样便于防止子控件重复设置,也便于移除子控件,缺点就是不能对子控件进行排序。如果以后我们提供控件的z-order概念,那么我们就会使用能够进行排序的容器来容纳子控件。

控件区域:

windows下,我们使用RECT结构来保存控件自身相对于窗口客户区的区域,那么窗口客户区尺寸改变时也就是我们控件进行布局的时机,那我们就要在消息过滤中处理WM_SIZE消息了。

case WM_SIZE: // 让根控件适应真个客户区
{
RECT clientRect;
::GetClientRect(param.hWnd, &clientRect);
pRootWidget->SetAbsoluteRect(clientRect, false);
}
break;

我们将控件的布局交由父控件管理,也就是说我们只需要更新根控件区域便可。根控件负责对其子控件进行布局,如此递归。

控件更新:

当控件区域改变了,那么相应的其显示也应相应的进行更新,所以我们的SetAbsoluteRect接口有一个update参数用于控制是否让窗口产生无效区域激活绘制。

// 此处的update作用是控制是否立即更新显示。
// 因为模拟控件只是窗口客户区的一个区域,当区域改变时应该产生原区域和新区域or运算后区域的脏矩形
// 以使得窗口去重绘这部分区域。
// 可能有些批量性质的操作会在操作多个控件后进行整体更新,所以在对单个控件设置新区域的时候可能不会想要更新。
// 所以才加上这个是否立即更新的开关。
void SetAbsoluteRect(const RECT& rect, bool update = true);

既然提到了绘制,那么我们也应该让我们的控件展示在窗口上了。

控件绘制:

通常我们的窗口程序都是在WM_PAINT消息中进行绘制,我们的控件系统当然也需要处理此消息。

case WM_PAINT:
{
// 使用内存DC来缓冲绘制
// 目前没有计算脏矩形区域
wnd_msg_assistant::OnPaint opAssistant(param.hWnd);
pRootWidget->Draw(opAssistant.GetMemDC());
}
return S_OK;

这里引入了一个辅助对象帮助我们产生内存DC,优化我们的绘制效率。我们直接return了这个消息,也就是说我们将这个消息过滤掉了。前面WM_SIZE和WM_DESTROY我们都没有过滤,只是在这个时机对控件进行了通知或者操作。之所以要过滤WM_PAINT消息是因为外部的绘制和控件的绘制难以协调,那么我们干脆就接管了窗口客户区的绘制了。

当然,控件也需要负责绘制其子控件,那么Draw接口中便会调用子控件的Draw,如此递归使得每个控件都能够得以绘制。

首次直观的看到我们的控件:

我们在调试版本中,为每个控件生成了一个随机的颜色,根据控件的区域绘制了其边框,这样我们就第一次直观的在窗口中看到了我们的控件。



迫不及待,具有了区域的控件,我们已经急切的想要对其布局进行控制,绘制进行定制了。布局控制和绘制定制当然属于扩展部分,那么下面就将要引入我们的扩展体系了,尽请期待。

下载测试工程源码

转载于:https://www.cnblogs.com/EvilGhost/archive/2011/04/09/Abstract_Widget_6.html

一步一步实现自己的模拟控件(6)——控件树及控件区域相关推荐

  1. 一步一步学WF系列(四)——工作流模拟登陆

    1. 摘要 我们之前已经熟悉了关于WF的基本概念,相信各位也都跃跃欲试.想步入真正的WF开发. 从本文开始,我们就先来熟悉在WF中的活动. 2. 活动 WF的核心就是一系列的活动. 而工作流就是多个活 ...

  2. 一步一步实现自己的模拟控件(9)——消息处理

    这次我们将要给Widget增加一些状态,并使其能够接受出消息处理扩展,测试工程中实现了一个按钮的消息处理扩展. Widget状态: 之前的控件只是绘制了一个边框,并且总是会在窗口中显示.实际上我们往往 ...

  3. 【深度学习基础】一步一步讲解卷积神经网络

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送 本文转自:一步一步讲解卷积神经网络 卷积神经网络(Convoluti ...

  4. SQL Server 2008 Analysis Services 多维数据库一步一步从入门到精通

    SQL Server 2008 Analysis Services 多维数据库一步一步从入门到精通(一) 创建 Analysis Services 项目(图) 在开始之前,我的电脑上已经完整的安装了S ...

  5. 手挽手带你学React:四档(上)一步一步学会react-redux (自己写个Redux)

    手挽手带你学React入门四档,用人话教你react-redux,理解redux架构,以及运用在react中.学完这一章,你就可以开始自己的react项目了. 之前在思否看到过某个大神的redux搭建 ...

  6. 一步一步学Silverlight 2系列(12):数据与通信之WebClient

    版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://terrylee.blog.51cto.com/342737/67249 ...

  7. 【Linux】一步一步学Linux——ld命令(256)

    00. 目录 文章目录 00. 目录 01. 命令概述 02. 命令格式 03. 常用选项 04. 参考示例 05. 附录 01. 命令概述 ld命令是GNU的连接器,将目标文件连接为可执行程序. 0 ...

  8. 【Linux】一步一步学Linux——mtools命令(244)

    00. 目录 文章目录 00. 目录 01. 命令概述 02. 命令格式 03. 常用选项 04. 参考示例 05. 附录 01. 命令概述 mtools命令显示mtools支持的指令,mtools为 ...

  9. 【Linux】一步一步学Linux——reboot命令(197)

    00. 目录 文章目录 00. 目录 01. 命令概述 02. 命令格式 03. 常用选项 04. 参考示例 05. 附录 01. 命令概述 reboot命令用于用来重新启动计算机.但是机器重启必须要 ...

最新文章

  1. Last-Modified、If-Modified-Since 实现缓存和 OutputCache 的区别
  2. 实现Nginx https
  3. 类与类之间关系的表示方式
  4. python批量给文件命名为001,002,...【亲测有效】
  5. php 循环链表,PHP实现循环链表功能
  6. Hadoop生态hive(三)Hive QL介绍
  7. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 16丨报告的记录 II【难度中等】
  8. vue监听字符串长度_Vue 的 computed 和 watch 的区别
  9. linux下的dns服务器
  10. Hadoop HIVE 聚合查询
  11. 彩色静电植绒印花工艺的五个方法
  12. 经典!史上最全免费收录网站搜索引擎登录口
  13. matlab运行时间特别长,Matlab运行时间过长
  14. 题解 P1894 【[USACO4.2]完美的牛栏The Perfect Stall】
  15. 偶遇RandomAccessFile
  16. (赴日流程)家属滞在签证
  17. 最简洁的Git的基本操作
  18. 基于神经网络的文字识别,神经网络如何识别图像
  19. SpringSecurity之SecurityContext和Authentication对象
  20. 文本匹配相似度计算---多种距离算法 ,多种相似度计算算法,一看就懂

热门文章

  1. oracle中check约束性别,关于Oracle Check类型约束的导入与启用
  2. oracle10官网下载安装,oracle11g安装(win10)下载安装
  3. dos命令行设置网络优先级_计算机网络故障及其维修方法
  4. wchar_t*和string相互转换
  5. pytorch无法下载或下载缓慢问题
  6. 通过开始关键字和结束关键字,查找所有的邮箱名称记录
  7. java图形界面设计 swing之JTable表格的创建使用-添加鼠标监听
  8. Pixhawk之姿态解算篇(3)_源码姿态解算算法分析
  9. C语言运算符优先级列表
  10. Codeforces Round #529 (Div. 3) F. Make It Connected(最小生成树)