在上一节中,我简单介绍了控件随父LAYOUT自由移动的设置。在这一节,我将介绍一种常见的情况:嵌入窗口。

在项目中,我们很少会100%的编写一个软件,特别是界面相关的,我们会使用以前已经编写好的窗口,或网上的开源模块。举一个简单的例子来说,如果你要编写一个视频播放器,关于视频的播放窗口,就用不着用DUI来实现,我们完全可以使用网上的开源库,嵌入一个播放的WND即可(当然有的库也支持回调的方式,用户可以在自己的窗口中将回调出来的图片进行自由绘制)。

我们需要在窗口大小改变时,即时地改变播放窗口的大小。也许你会说这非常简单,直接重载OnSize,然后获取占位控件(使用占位控件才是最正确的选择,如果在程序中判断左边距、右边距,就做不到UI、CODE分离了)的大小,然后设置即可。但是当你真正使用的时候,发现并没有那么简单。来看代码:

UIManager.cpp 第750行:

    case WM_SIZE:{if( m_pFocus != NULL ) {TEventUI event = { 0 };event.Type = UIEVENT_WINDOWSIZE;event.pSender = m_pFocus;event.dwTimestamp = ::GetTickCount();m_pFocus->Event(event);}if( m_pRoot != NULL ) m_pRoot->NeedUpdate();}return true;

我们看到,窗口大小改变,ROOT只是简单的 NeedUpdate,重绘而已,它的大小并没有设置为与窗口一样的大小。

在WinImplBase.cpp 第214 行:

LRESULT WindowImplBase::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){SIZE szRoundCorner = m_PaintManager.GetRoundCorner();#if defined(WIN32) && !defined(UNDER_CE)if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {CDuiRect rcWnd;::GetWindowRect(*this, &rcWnd);rcWnd.Offset(-rcWnd.left, -rcWnd.top);rcWnd.right++; rcWnd.bottom++;HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);::SetWindowRgn(*this, hRgn, TRUE);::DeleteObject(hRgn);}#endifbHandled = FALSE;return 0;}

也是啥也没做。

所以在OnSize里面设置窗口位置,并不会达到效果。

那么DUILIB是在哪里设置ROOT的大小呢?UIManager.cpp 第 615行,即在WM_PAINT中进行设置。

m_pRoot->SetPos(rcClient);

1.SetPos

当你看到这里时,我想你已经知道第一种方法了。即在 OnSize中,

RECT rc;GetClientRect (m_hWnd, &rc);m_PaintManager.GetRoot()->SetPos (rc);const RECT& rc_pos = targer_ui_->GetPos ();::MoveWindow (move_wnd, rc_pos.left, rc_pos.top, rc_pos.right – rc_pos.left, rc_pos.bottom – rc_pos.top, TRUE);

即我们主动设置大小,ROOT设置了POS后,会将它的子控件也设置POS,详情请看源码。所以,我们就能够得到正确的位置信息了。

但是这并不是最好的方式,原因很简单,OnSize会被频繁的调用,特别是在程序初始化的时候,OnSize被调用N次,而且在最小化的时候也会被调用。而且当你看1.SetPos时,你也猜到了会有第二种方式了。

2.委托 OnSize

假设我们的占位控件为 target_ui_,它有一个委托成员变量:OnSize。直接看代码吧:

target_ui_->OnSize += MakeDelegate (this, &CYourWnd::OnTargetSizeChanged);bool CYourWnd:: OnTargetSizeChanged (void* param){const RECT& rc_pos = targer_ui_->GetPos ();::MoveWindow (move_wnd, rc_pos.left, rc_pos.top, rc_pos.right – rc_pos.left, rc_pos.bottom – rc_pos.top, TRUE);}

如此简单,又如此优美的代码。

注意使用的是 +=

在这里,我们也看到了作者自己实现了委托的编写(我不清楚是不是使用了开源库),可见作者的C++功底是相当深厚的。

看CControlUI的源码,你会发现如下委托对象:

public:CEventSource OnInit;CEventSource OnDestroy;CEventSource OnSize;CEventSource OnEvent;CEventSource OnNotify;

顾名思义,无需赘述。

这里说一下Event和Notify的区别。

Event是控件自己收到的消息,比如鼠标左键按下、弹起、双击等,DUILIB先向控件自己发一个事件。

Notify通知,是向WND发送的通知消息,类似MFC中对话框收到控件的NOTIFY(包括按钮的单击),它默认情况下是由窗口接收的,在窗口的Notify函数中进行响应。

DUILIB的处理流程是,先向CONTROL发送事件,然后向WND发送通知。

OnNotify相当有用,因为你可以定制每个控件的响应,而不需要在WND的Notify中进行一大堆的if..else..了。

OnEvent用处也很大,看情况使用了。

Duilib教程-自动布局2相关推荐

  1. Duilib教程-自动布局3-分隔条

    先看一个常用的图,如下: 左边是导航栏,右边是信息区. 中间可以自由拉伸. XML如下: <?xml version="1.0" encoding="utf-8&q ...

  2. Duilib教程-自动布局1

    我们要实现一个带标题栏和状态栏的程序,同时要支持拉伸,即包括最小化.最大化,图如下: XML: <?xml version="1.0" encoding="utf- ...

  3. Duilib教程-控件练习

    一.控件消息的响应. 在HelloDuilib例子中,程序不能退出,在这里,我将添加一个关闭按钮,当点击它时,调用PostQuitMessage进行退出. 首先在界面的右上角添加一个关闭按钮,并取名为 ...

  4. DuiLib教程--下载和生成

    下载和生成 DuiLib的下载可前往 https://github.com/duilib/duilib ,我个人更推荐直接使用git clone https://github.com/duilib/d ...

  5. Duilib教程-非DUI控件

    DUILIB并不是真正的DUI,至少有部分控件不是完全DUI的.其实包括: 1.EDIT. 它的实现原理是,CEditUI包含一个窗口CEditWnd,流程如下: 1)鼠标单击,创建窗口见 EditU ...

  6. Duilib教程-HelloDuilib及DuiDesigner的简单使用

    一.HelloDuilib 1. 首先理解DUILIB显示的一个基本流程,如下图: 在Duilib中,WindowImplBase 这个类代表了图中 "CWndClass". 所以 ...

  7. Duilib教程-简单介绍

    在读这篇博客的时候,可能您已经对duilib有一定的了解.所以,我并不打算对duilib进行过多的介绍.它的内核首先由外国人编写,后来由国人一个小组接过来继续编写,于是就有了现在的Duilib. 1. ...

  8. duilib 子窗口位置_duilib入门简明教程 -- 界面布局(9)

    上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...

  9. duilib教程之duilib入门简明教程9.界面布局

    上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...

最新文章

  1. springmvc 将post转换为delete,put
  2. MySQL — 索引的慢查询优化与 B+ 树
  3. Tensorflow: 保存和复原模型(save and restore)
  4. 4服务器内存和普通内存_关于服务器内存的选择
  5. Win7系统十个不能关闭的服务
  6. linux 查看进程id对应的路径,Linux中怎么通过PID号找到对应的进程名及所在目录方法...
  7. cifar10数据集测试有多少张图_基于特定数据集的Oracle、ClickHouse、ES测试报告
  8. this的用法this.name=name 这个什么意思
  9. mac服务器证书失效,Mac OS X Server:软件更新证书过期
  10. 软件工程导论 07章软件测试
  11. Linux下学习进程控制
  12. 什么是java cdm_Java-ORM数据库框架CDM介绍
  13. html5虚拟摇杆,关于前端:babylonjs-第三方-nipplejs虚拟摇杆
  14. 怎么做自媒体,这份入门攻略,建议收藏
  15. Python-pandas对excel筛选(分组)查询
  16. LitePal使用踩坑指南
  17. 如何使用计算机中的导出,微信里的文件导入电脑(如何用数据线导出微信文件)...
  18. node+ npm + yarn 安装及上手
  19. 与传统媒体相比新媒体传播所具备的特点与优势!
  20. bugku 奇怪的密码

热门文章

  1. SpringBoot高级-缓存-RedisTemplate序列化机制
  2. 元素的选中问题 元素选中的问题 切换复选框选中 全选和全不选
  3. 解决GitHub中头像显示异常、设置不了头像、README图片无法显示等问题
  4. sq语句报错Parameter index out of range (2 > number of parameters, which is 1).
  5. Cortex‐M3-存储器保护单元(MPU)
  6. 直流无刷电机制动的三种方式
  7. Android--批量插入数据到SQLite数据库
  8. 物联网核心协议—消息推送技术演进
  9. Linux运维系统工程师与java基础学习系列-6
  10. 设计模式(创建型)之原型模式