您的位置:首页 > 产品设计 > UI/UE

direct UI总结---发文于2013.11.17

2016-01-15 23:24 423 查看
http://blog.csdn.net/wangchyz/article/details/6795419   简单的dui例子实现
http://bbs.csdn.net/topics/340239295  dui的简单帖子总结
http://bbs.pediy.com/showthread.php?t=124957 dui的例子实现
http://www.buguw.com/%e8%bd%ac-directui%e7%9a%84%e5%88%9d%e6%ad%a5%e5%88%86%e6%9e%90.html dui的函数总结
http://sogoodlife.blog.163.com/blog/static/45850260201261154229868/   dui对xml文件的解析过程
http://sogoodlife.blog.163.com/blog/static/458502602012610508332/ dui的消息处理过程
http://blog.csdn.net/jofranks/article/details/11853507  dui的处理流程
http://blog.sina.com.cn/s/blog_4c3b2dc20100s8w6.html dui的处理流程

以viksoe的duilib为例总结下。

分两步分析direct ui的原理,dui程序的启动和对xml布局文件的解析

一。dui程序的启动

窗口create之后,进入CPaintManagerUI::MessageLoop.这个消息类似mfc的消息循环机制。

先在 CPaintManagerUI::TranslateMessage中取出本窗口的消息,然后进入所有的CPaintManagerUI::PreMessageHandler函数,过滤出快捷按键,alt键

的消息.接着进入大窗口注册的CWindowWnd::__WndProc窗口过程,处理WM_NCCREATE消息。在这个窗口过程中进入每个窗口注册的MessageHandler函数消息,即每个类重载的HandleMessage函数,比如duilib的例子

  LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)

    {

        if( uMsg == WM_CREATE ) {

            m_pm.Init(m_hWnd);

            CDialogBuilder builder;

            CControlUI* pRoot = builder.Create(_T("test1.xml"), (UINT)0, NULL, &m_pm);

            ASSERT(pRoot && "Failed to parse XML");

            m_pm.AttachDialog(pRoot);

            m_pm.AddNotifier(this);

            Init();

            return 0;

        }
xxxx

    }

可以看到这里调用CDialogBuilder::Create用来加载解析xml布局文件。

在这个HandleMessage最后调用CPaintManagerUI::MessageHandler来处理各种WM_CLOSE,WM_PAINT,WM_SIZE,

WM_MOUSEMOVE,WM_LBUTTONDOWN等各种按键和鼠标消息。比如处理WM_LBUTTONDOWN,

先获取鼠标坐标位置,根据这个坐标通过FindControl找到拥有鼠标位置的控件。找到后,给找到的控件设置焦点,

然后通过 pControl->Event,给控件发一个消息,类似mfc的msg,包含type、ptMouse、wParam、chKey、lParam等。

接着进入控件的CButtonUI::DoEvent函数,

void CButtonUI::DoEvent(TEventUI& event)

{

    if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {

        if( m_pParent != NULL ) m_pParent->DoEvent(event);

        else CLabelUI::DoEvent(event);

        return;

    }

    xxxx

    if( event.Type == UIEVENT_BUTTONUP )

    {

        if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {

            if( ::PtInRect(&m_rcItem, event.ptMouse) ) Activate();

            m_uButtonState &= ~(UISTATE_PUSHED | UISTATE_CAPTURED);

            Invalidate();

        }

        return;

    }

    if( event.Type == UIEVENT_KILLFOCUS ) 

    xxxxxx

}

Invalidate是触发一次重绘,在重绘前先通过SendNotify去注册的控件中通知消息的发生。

void CPaintManagerUI::SendNotify(TNotifyUI& Msg, bool bAsync /*= false*/)

{

xxx

 for( int i = 0; i < m_aNotifiers.GetSize(); i++ ) {

            static_cast<INotifyUI*>(m_aNotifiers[i])->Notify(Msg);

        }  

xxx

}

可以看出系统向所有注册INotifyUI接口的发送消息。所以如果我们想处理这种鼠标,按键消息的话,需要实现

INotifyUI接口,然后注册。比如

void CSearchPageWnd::Notify(TNotifyUI& msg)

{

   if( msg.sType == _T("click") ) 

   {

      if( msg.pSender->GetName() == _T("ok") ) {

         CStandardPageWnd* pWindow = new CEditPageWnd;

         pWindow->Create(m_hWnd, NULL, UI_WNDSTYLE_FRAME, 0L);

      }

      if( msg.pSender->GetName() == _T("cancel") ) Close();

   }

   CStandardPageWnd::Notify(msg);

}

处理单击消息,消息来源是ok按键,

从上看出,自己实现注册消息处理函数主要从Notify和HandleMessage函数中。

二。对xml布局文件的解析

上面跟踪到调用CDialogBuilder::Create用来加载解析xml布局文件.展示窗口。进入该函数,

CControlUI* CDialogBuilder::Create(xxx)

{

  CMarkupNode root = m_xml.GetRoot();

  for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() ) {

    pstrClass = node.GetName();

         if( _tcscmp(pstrClass, _T("Image")) == 0 ) {

                    pstrName = root.GetAttributeName(i);

                    pstrValue = root.GetAttributeValue(i);

                    if( _tcscmp(pstrName, _T("size")) == 0 ) {

                         pManager->SetInitSize(cx, cy);

  xxxxxxxx

可以看出是解析xml文件,取出节点,然后看节点的名字pstrClass,匹配时image,Font,Default,Window等各种控件。

取出控件名字后,取出pstrName属性名,根据属性名字调用对应的函数,比如上面进入SetInitSize函数后

  ::SetWindowPos(m_hWndPaint, NULL, 0, 0, cx, cy, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);

设置窗口大小。

最后递归的调用 CDialogBuilder::_Parse函数解析子节点,在这个函数中,根据节点名称的字符个数,在堆中new 出对应的控件,

没有新的窗口句柄,如下所示。

   SIZE_T cchLen = _tcslen(pstrClass);

            switch( cchLen ) {

            case 4:

                if( _tcscmp(pstrClass, _T("Edit")) == 0 )                   pControl = new CEditUI;

                else if( _tcscmp(pstrClass, _T("List")) == 0 )              pControl = new CListUI;

                else if( _tcscmp(pstrClass, _T("Text")) == 0 )              pControl = new CTextUI;

                break;

            case 5:

                if( _tcscmp(pstrClass, _T("Combo")) == 0 )    

子控件创建出来后通过pContainer->Add(pControl) 添加到父容器控件中,然后处理子控件的属性信息,如下

if( node.HasAttributes() ) {

            xxxx

            for( int i = 0; i < nAttributes; i++ ) {

                pControl->SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));

            }

解析完xml文件后,对应的窗口就创建出来了,然后注册notify接口,ShowWindow就可以响应消息了。

通过分析,自己实现dui的例子时,三步做。先包含dui的库,然后实现notify和HandleMessage响应各种消息函数。

最后编写xml布局文件,在程序入口处create然后ShowWindow.

wtl的界面实现,类似direct ui,需要继承CFrameWindowImpl,CMessageFilter等类。

在CFrameWindowImpl中实现了消息循环的过程,只需要create和showWindow就可以展现窗口。

通过DECLARE_FRAME_WND_CLASS实现窗口资源和窗口类的绑定,然后通过继承覆盖,父类调用自己的实现类的窗口处理函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ui 界面 directui