Duilib教程-自动布局2

在上一节中,我简单介绍了控件随父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);

         }

#endif

         bHandled = 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.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用处也很大,看情况使用了。

时间: 2024-12-18 13:08:35

Duilib教程-自动布局2的相关文章

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

先看一个常用的图,如下: 左边是导航栏,右边是信息区. 中间可以自由拉伸. XML如下: <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <Window size="695,542"> <HorizontalLayout width="695" height="542" bkcolor=&qu

Duilib教程-自动布局1

我们要实现一个带标题栏和状态栏的程序,同时要支持拉伸,即包括最小化.最大化,图如下: XML: <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <Window size="695,542"> <VerticalLayout width="657" height="517" bkcolor=&q

Duilib教程-控件练习

一.控件消息的响应. 在HelloDuilib例子中,程序不能退出,在这里,我将添加一个关闭按钮,当点击它时,调用PostQuitMessage进行退出. 首先在界面的右上角添加一个关闭按钮,并取名为“btnClose”. 然后在 CHelloDuilibWnd 中重载 WindowImplBase::Notify (); 代码如下: void CHelloDuilibWnd::Notify( TNotifyUI& msg ) { if (msg.sType == DUI_MSGTYPE_CLI

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

一.HelloDuilib 1. 首先理解DUILIB显示的一个基本流程,如下图: 在Duilib中,WindowImplBase 这个类代表了图中 “CWndClass”. 所以我们需要做的是: 1)生成一个XML. 2)生成一个WindowImplBase对象. 3)加载XML. 4)显示窗口. 但是编写的时候,WindowImplBase已经帮我们做了许多工作,我们只需要指定XML路径,它就能够帮助我们自动加载,非常方便. 但是一般我不喜欢先编写XML,我喜欢先写MAIN函数,再编写占位函

Duilib教程-非DUI控件

DUILIB并不是真正的DUI,至少有部分控件不是完全DUI的.其实包括: 1.EDIT. 它的实现原理是,CEditUI包含一个窗口CEditWnd,流程如下: 1)鼠标单击,创建窗口见 EditUI.cpp第217行,在第223行有创建的代码: m_pWindow = new CEditWnd(); ASSERT(m_pWindow); m_pWindow->Init(this); 2)失去焦点时,删除自己,见EditUI.cpp第103行和第131行, LRESULT CEditWnd::

2013 duilib入门简明教程 -- 结合win32和MFC (16)

http://www.cnblogs.com/Alberl/p/3352696.html 虽然duilib自带在MFC中使用duilib的Demo,但只是MFC窗口和duilib窗口不重叠的情况.如果要在MFC窗口中嵌入duilib控件,或者在duilib控件中嵌入MFC的控件的话,就没有Demo可以看了,其实Alberl开始也不知道怎么办,看了下ActiveXUI控件,这个就是结合HWND的,但是由于接触duilib不久,所以一时无法看懂ActiveXUI到底是怎么将win32的HWND画上去

(翻译)开始iOS 7中自动布局教程(二)

这篇教程的前半部分被翻译出来很久了,我也是通过这个教程学会的IOS自动布局.但是后半部分(即本篇)一直未有翻译,正好最近跳坑翻译,就寻来这篇教程,进行翻译.前半部分已经转载至本博客,后半部分即本篇.学习IOS自动布局的朋友可以看看.自动布局很强大. 这篇教程绝对的最好的学习IOS自动布局的文章,没有之一 原文地址:Beginning Auto Layout Tutorial in iOS 7: Part 2 正文如下: 请注意: 团队成员Matthijs Hollemans (IOS学徒系列的作

【转】开始iOS 7中自动布局教程(一)

原文网址:http://www.cocoachina.com/industry/20131203/7462.html 原文:Beginning Auto Layout Tutorial in iOS 7: Part 1 感谢翻译小组成员@answer-huang(博客)热心翻译.如果您有不错的原创或译文,欢迎提交给我们,更欢迎其他朋友加入我们的翻译小组(联系qq:2408167315). ======================================================

duilib进阶教程 -- 响应windows原生消息和自定义消息(13)

duilib进阶教程 -- 响应windows原生消息和自定义消息(13) 一.windows原生消息 同样,入门教程只是给出了响应windows原生消息的方法,并没给出例子,这里以自适应屏幕分辨率为例.迅雷播放器虽然可以在启动的时候自动调整窗口大小,但是当屏幕分辨率实时改变时并没有调整窗口,所以我们给播放器加上实时调整大小的功能,很明显,应该响应WM_DISPLAYCHANGE消息,而duilib自己处理windows消息的函数是在HandleMessage里,因此我们重载HandleMess