隐藏驱动类:

为了让用户有更简单的使用接口,我们需要把不必要的东西进行一定的隐藏。前面我就提到WidgetDriver对于用户来说是不关心的东西,那么我们就将其进行隐藏。

  方案1:

  将WidgetDriver放到Widget.cpp中,这样的隐藏方式是最严密的,对于用户来说完全看不到WidgetDriver。但是随着我们的实现膨胀,这会让我们的Widget.cpp变得非常臃肿。

  方案2:

  不改变文件结构,将WidgetDriver私有化,通过友元声明使得只有Widget类对象能够访问WidgetDriver。这样用户虽然能够看到WidgetDriver这个类定义,但是却无法使用,这样对于代码的结构组织也更有利。

我采用了方案2

class Driver_{
friend class Widget;

DriverImpl_* pImpl_;

private:
explicit Driver_(HWND hWnd);
~Driver_();
Driver_(const Driver_&);
Driver_& operator =(const Driver_&);

private:
void SetRootWidget(Widget* pRootWidget);
HWND GetContainerWindow() const;
Widget* GetRootWidget() const;
};

因为我们隐藏了WidgetDriver,那么它的职能就能够进行简化。前面提到的根控件和WidgetDriver之间的关系我们就能够改为当方面控制了。于是我将WidgetDriver放到了根控件中进行管理,我们只需要操作根控件便可。

Widget::Widget(HWND hWnd)
: pImpl_(new WidgetImpl)
{
pImpl_->pDriver = new widget::Driver_(hWnd);
pImpl_->pDriver->SetRootWidget(this);
}

Widget::~Widget()
{
if (IsRoot())
{
delete pImpl_->pDriver;
}
delete pImpl_;
}

前面我们都没有提到应该何时结束我们的系统,但是我们的系统生命周期和窗口是息息相关的,在窗口销毁的时候那么和这个窗口相关联的控件体系就应该销毁。于是我们对消息过滤器做了一点点改动:

LRESULT MessageFilter::Filter(const Param& param, Widget* pRootWidget)
{
assert(param.originalProc);
assert(pRootWidget);
#ifdef _DEBUG
std::stringstream ss;
ss<<"窗口消息: "<<std::showbase<<std::hex<<param.message<<" 进入Widget消息过滤!\r\n";
::OutputDebugStringA(ss.str().c_str());
#endif // _DEBUG

LRESULT ret = ::CallWindowProc(
param.originalProc,
param.hWnd,
param.message,
param.wParam,
param.lParam);

if (WM_DESTROY == param.message)
{
// 销毁根控件
pRootWidget->Destroy();
}

return ret;
}

我们在接收到WM_DESTROY窗口消息的时候销毁根控件,根控件析构的时候又会销毁控件驱动,控件驱动析构的时候会解除和窗口的关联。

下一步我们便要开始对我们的控件进行设计了,我们自始至终都将控件抽象为窗口客户区的一个区域,所以说我们并不打算使用继承来扩展控件。后面会看到我们使用插入式的扩展,这样的方式具备动态替换的能力甚至还能将一个扩展共享给多个控件使用。

下载测试工程源码

转载于:https://www.cnblogs.com/EvilGhost/archive/2011/04/07/Abstract_Widget_5.html

一步一步实现自己的模拟控件(5)——隐藏类相关推荐

  1. 一步一步实现自己的模拟控件(6)——控件树及控件区域

    控件树 一步一步实现自己的模拟控件(1)中的图上我们可以看到,我们的控件体系其实就是一个控件树.每一个窗口关联一个根控件,所有控件都在这个根控件之下,父控件包容并管理子控件,那么我们的Widget就应 ...

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

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

  3. 2023-02-24 Android app java 模拟控件点击事件,使用performClick方法去实现

    一.Android app java 模拟控件点击事件,使用performClick方法去实现. 二.实际使用 private TextView m_bt_connect ;m_bt_connect ...

  4. 简单三步!教你用前端表格控件SpreadJS做购物车

    SpreadJS结合40余年专业控件技术和在电子表格应用领域的经验而推出的纯前端表格控件,基于 HTML5,兼容 450 多种 Excel 公式,具备"高性能.跨平台.与 Excel 高度兼 ...

  5. C# SSH Shell终端模拟控件Rebex SSH Shell详细介绍

    具备终端模拟的SSH Shell.这使您能简单地在Unix/Windows SSH服务器上执行命令或将终端模拟功能添加到您的应用程序之中. 100%可托管的代码 遵循CLS(通用语言规范) 稳定以及彻 ...

  6. 一步一步教你写一个快递查询APP(适合新手)

    前言: 水平:自学Android十五天,以前有过混日子的编程经验. 目标: <第一行代码>学完之后,总想写个APP,天气的APP写了个初版,后面再说,今天演示的是制作快递查询APP的整个经 ...

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

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

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

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

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

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

最新文章

  1. 听妈妈的话-07年感动的延续
  2. Windows10上怎样开启FTP服务
  3. 查询语句中select from where group by having order by的执行顺序
  4. Swift--字符串和字符(一)
  5. 工作118:封装一个带有对话框的button组件
  6. 一种M2M业务的架构及实现M2M业务的方法
  7. java ognl表达式 与struts2标签_Struts2 OGNL表达式实例详解
  8. 第5章 高效的多线程日志
  9. DE9 二阶常系数线性方程
  10. 【PAT乙】1069 微博转发抽奖 (20分) set
  11. PPT:Semi-supervised Classification with Graph Convolutional Networks
  12. nginx SPDY 堆缓冲区溢出
  13. 计算机配件对比,基本参数 尺寸对比 接口对比
  14. 数据可视化—随机漫步
  15. python抓取汇率_09 使用Python爬取中国银行网站选择汇率最坑的一天
  16. 基于OLAP的时间维度设计
  17. 小程序canvas画入圆形图片
  18. 【DDD 8】领域驱动设计实践 —— Application层实现
  19. 动态规划算法二项式计算c语言,动态规划 — 计算二项式系数
  20. 三个数降序排列(汇编)

热门文章

  1. 【slighttpd】基于lighttpd架构的Server项目实战(8)—状态机机制回顾
  2. tomcat端口被占用-----windows下如何查询某个端口被哪个进程占用以及如何杀死进程
  3. GraphQL及元数据驱动架构在后端BFF中的实践
  4. 从FM推演各深度学习CTR预估模型
  5. Hbase总结(三)-Hbase与Hive的区别与联系
  6. TOML-To-Go 更新,支持暗黑模式
  7. 常用排序算法(二)快速排序
  8. JUnit+JMockit单元测试
  9. Xmanager企业版激活成功全过程
  10. Msc系统上的eclipse遇到乱码问题解决方式