Duilib教程-自动布局2
在上一节中,我简单介绍了控件随父LAYOUT自由移动的设置。在这一节,我将介绍一种常见的情况:嵌入窗口。
在项目中,我们很少会100%的编写一个软件,特别是界面相关的,我们会使用以前已经编写好的窗口,或网上的开源模块。举一个简单的例子来说,如果你要编写一个视频播放器,关于视频的播放窗口,就用不着用DUI来实现,我们完全可以使用网上的开源库,嵌入一个播放的WND即可(当然有的库也支持回调的方式,用户可以在自己的窗口中将回调出来的图片进行自由绘制)。
我们需要在窗口大小改变时,即时地改变播放窗口的大小。也许你会说这非常简单,直接重载OnSize,然后获取占位控件(使用占位控件才是最正确的选择,如果在程序中判断左边距、右边距,就做不到UI、CODE分离了)的大小,然后设置即可。但是当你真正使用的时候,发现并没有那么简单。来看代码:
UIManager.cpp 第750行:
case WM_SIZE:
{
if( m_pFocus != NULL ) {
TEventUI event = { };
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 != || szRoundCorner.cy != ) ) {
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);
}
#endif
bHandled = FALSE;
return ;
}
也是啥也没做。
所以在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的更多相关文章
- Duilib教程-自动布局3-分隔条
先看一个常用的图,如下: 左边是导航栏,右边是信息区. 中间可以自由拉伸. XML如下: <?xml version="1.0" encoding="utf-8&q ...
- Duilib教程-自动布局1
我们要实现一个带标题栏和状态栏的程序,同时要支持拉伸,即包括最小化.最大化,图如下: XML: <?xml version="1.0" encoding="utf- ...
- Duilib教程-控件练习
一.控件消息的响应. 在HelloDuilib例子中,程序不能退出,在这里,我将添加一个关闭按钮,当点击它时,调用PostQuitMessage进行退出. 首先在界面的右上角添加一个关闭按钮,并取名为 ...
- Duilib教程-HelloDuilib及DuiDesigner的简单使用
一.HelloDuilib 1. 首先理解DUILIB显示的一个基本流程,如下图: 在Duilib中,WindowImplBase 这个类代表了图中 “CWndClass”. 所以我们需要做的是: 1 ...
- Duilib教程-非DUI控件
DUILIB并不是真正的DUI,至少有部分控件不是完全DUI的.其实包括: 1.EDIT. 它的实现原理是,CEditUI包含一个窗口CEditWnd,流程如下: 1)鼠标单击,创建窗口见 EditU ...
- Duilib教程-简单介绍
在读这篇博客的时候,可能您已经对duilib有一定的了解.所以,我并不打算对duilib进行过多的介绍.它的内核首先由外国人编写,后来由国人一个小组接过来继续编写,于是就有了现在的Duilib. 1. ...
- 2013 duilib入门简明教程 -- 界面布局(9)
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayou ...
- duilib入门简明教程 -- 界面布局(9)
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayou ...
- duilib入门简明教程 -- 界面布局(9) (转)
原文转自:http://www.cnblogs.com/Alberl/p/3343806.html 上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的 ...
随机推荐
- Android Exception 10(server)' ~ Channel is unrecoverably broken and will be disposed!)
08-11 19:22:35.028: W/MemoryDealer(2123): madvise(0x43e16000, 12288, MADV_REMOVE) returned Operation ...
- Ansible远程执行脚本示例
首先创建一个shell脚本 cat /tmp/df.sh #!/bin/bash df -h|grep vda|awk '{print $5}' 然后把该脚本分发到各个机器上 ansible comp ...
- Linux-《Linux命令行与shell脚本编程大全》阅读笔记
1.内核负责的主要功能 系统内存管理.软件程序管理.硬件设备管理.文件系统管理 2.GNU工具链 Linux内核是系统的核心,控制着内存.程序和硬件等是如何与对方交互的.内核还需要工具链来执行一些标准 ...
- LaTex的注释
在LaTex中的注释有以下3种 1.注释一行:使用%注释一行文字, 在%后的文字都不予编译: 2.注释一段:使用\iffalse .... \fi 包含一段文字,被包含的文字被注释掉了: 3.注释一段 ...
- 【POJ 3140】 Contestants Division(树型dp)
id=3140">[POJ 3140] Contestants Division(树型dp) Time Limit: 2000MS Memory Limit: 65536K Tot ...
- PowerShell---Operators 介绍
1.Arithmetic operators(算术运算符) 算术运算符包括加.减.乘.除.取模 此外,加法运算符 (+) 和乘法运算符 (*) 还可对字符串.数组和哈希表进行运算.加法运算符将输入连接 ...
- php对xml文件的增删改查
源文件<?xml version="1.0" encoding="utf-8"?><root> <endTime>2016 ...
- .Net并行编程高级教程(二)-- 任务并行
前面一篇提到例子都是数据并行,但这并不是并行化的唯一形式,在.Net4之前,必须要创建多个线程或者线程池来利用多核技术.现在只需要使用新的Task实例就可以通过更简单的代码解决命令式任务并行问题. 1 ...
- 李洪强iOS开发之iOS工具收集
李洪强iOS开发之iOS工具收集 项目 简述 日期 我是怎么慢慢变懒的 : Jenkins + 蒲公英 使用Jenkins + 蒲公英使得项目打包给测试人员自动化,大大节省了劳动力 2015.04.1 ...
- 基于C#和Asp.NET MVC开发GPS部标视频监控平台
基于C#和Asp.NET MVC开发GPS部标监控平台 目前整理了基于.NET技术的部标平台开发文章,可以参考: 1.部标Jt808协议模拟终端的设计和开发 2.C#版的808GPS服务器开发-> ...