• 一步一步实现自己的模拟控件(4)——根控件


    窗口、控件驱动、根控件之间的关系

    前面我们已经说了,一个窗口只能关联一个控件驱动,一个控件驱动也同样对应一个根控件。为什么呢?因为我们的驱动需要作用于一个控件体系,一个控件体系具有一个根控件,这个根控件管理了整个窗口的客户区。这样我们才能在这个根控件下创建任意的控件,并活动在窗口客户区。

    生命周期控制

    基于上面的关系,控件驱动和根控件的生命息息相关,那么我们让其相互制约。既然是他们自身相互制约,那么用户就不应该管理其生命周期,我们特意引入一个简单的对象池来管理,并用访问控制来避免外部直接构造。

    private:
    explicit Widget(widget::Driver* pDriver);
    ~Widget();
    Widget(
    const Widget&);
    Widget
    & operator =(const Widget&);

    // 让对象池能够创建Widget对象
    friend class ObjectPool<Widget>;
    #pragma warning(push)
    #pragma warning(disable:4396)
    friend
    void std::_Destroy(Widget _FARQ *);
    #pragma warning(pop)

    public:
    static Widget* Create(HWND hWnd); // 创建根控件
    void Destroy();

    我们提供了一个静态接口Create用于创建根控件,可以注意到的一点是参数是窗口句柄。其实用户对于什么驱动、什么过滤的都不关心,用户只关心控件体系,所以说我们可以通过这个接口透明的创建根组件,实现中会自动的去驱动此窗口。

    Widget* Widget::Create(HWND hWnd)
    {
    return GetWidgetPool_().Construct(widget::Driver::Create(hWnd));
    }

    驱动构造时会创建根控件,析构时销毁根控件

    Driver::Driver(HWND hWnd)
    : pImpl_(
    new DriverImpl(hWnd))
    {
    // 创建根控件
    pImpl_->SetRootWidget(Widget::Create_(this));
    }
    ~DriverImpl()
    {
    // 销毁根控件
    Widget* pOldRootWidget = GetRootWidget();
    pRootWidget_
    = 0;
    if (pOldRootWidget)
    {
    pOldRootWidget
    ->Destroy();
    }
    }

    同样,根控件析构时也销毁控件驱动

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

    这样,用户其实有两个入口可以进入到我们的控件系统,一个是通过控件驱动,一个是通过控件本身。我们提倡用户不去关心控件驱动。那么甚至我们可以隐藏Driver这个类,目前我没有这样做。

    下载测试工程源码

    By Evil.Ghost
  • 相关阅读:
    Ionic2 自学须知的基本知识点
    Ionic2 启动加载优化总结
    Ionic2使用TypeScript调用自定义JavaScript脚本
    GPS坐标转百度地图坐标
    友情链接
    Python学习之路目录(收藏整理)
    基于Docker构建Jenkins CI平台
    KeepLived + nginx 高可用
    k8s-1.16 二进制安装
    Ansible自动化部署K8S集群
  • 原文地址:https://www.cnblogs.com/EvilGhost/p/Abstract_Widget_4.html
Copyright © 2020-2023  润新知