小鱼塘--自说自话的地方

  • 小玩意
  • 小想法
记录自己技术和想法地方
  1. 首页
  2. 界面
  3. 正文

duilib 消息自己简单总结

27 12 月, 2021 2505点热度 0人点赞 0条评论
内容目录

背景

最近由于各种原因又学习了duilib c/c++界面库

总结

  1. CWindowWnd::__WndPro
  2. pThis->HandleMessage
  3. m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes)[这个是最重要的]
  4. pClick->Event(event); 走到control 处理时间里面
  5. control 调用OnEvent(一般不做处理,也可以在这里处理事件),然后在 DoEvent 满足条件参数Notify投递
  6. 通知监听通知,一般是传递是窗口,这里一般是 WindowImplBase,因为我们注册了INotifyUI,默认处理通知,这个时候我们只要在消息宏设置函数就可以了。这个是WindowImplBase 带来便利,CWindowWnd,自己处理Notify,可以不用那么绕。

window窗口事件-->m_PaintManager(处理界面逻辑)--->丢回窗口处理业务逻辑(通过通知,也可以通过OnEvent处理)

我建议处理函数还是在通知里面,不要在事件里面,除非自己做特别处理。
比喻:点击事件其实通过BUTTON_UP事件判断,如果只是判断UP可能不准,同时跟界面按钮状态可能有冲突。

每个window对应一个CPaintManagerUI.

前2步

调用虚函数 HandleMessage, 我们做界面开发时候会继承CWindowWnd其实前面2步,只是把窗口HWND 与 我们代码对象绑定起来,建立关系,duilib 提供 WindowImplBase 方便我们开发界面而已,我们也可以不继承这个类,自己写事件和一些事件处理。

m_PaintManager.MessageHandle

进入界面库核心逻辑,前面都是只是传统界面逻辑,这里根据windwos 系统消息[WM_PAINT, WM_LBUTTONDOWN] 等等事件。

  1. 属性【画图】
  2. 行为

画图

根据我们的节点,一个一个画出来,这个类似html技术,目前所有主流界面开发都有点类似html 界面开发思路。

行为

根据鼠标和按键触发对应行为,dulib的行为基本都是通过notify 时间投递,这个投递在当前HWND里面。

这个类似win32 界面开发, 传统win32开发增加一个按钮事件 ,那么就投递 BM_CLICK给父窗口,父窗口在消息处理函数中处理这个消息。

例子

Button 点击例子代码分析

    case WM_LBUTTONUP:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            if( m_pEventClick == NULL ) break;
            ReleaseCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_BUTTONUP;
            event.pSender = m_pEventClick;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            // By daviyang35 at 2015-6-5 16:10:13
            // 在Click事件中弹出了模态对话框,退出阶段窗口实例可能已经删除
            // this成员属性赋值将会导致heap错误
            // this成员函数调用将会导致野指针异常
            // 使用栈上的成员来调用响应,提前清空成员
            // 当阻塞的模态窗口返回时,回栈阶段不访问任何类实例方法或属性
            // 将不会触发异常
            CControlUI* pClick = m_pEventClick;
            m_pEventClick = NULL;
            pClick->Event(event);
        }
        break;

在CPaintManagerUI::MessageHandler中处理windows 窗口消息,这里贴出来处理鼠标点击松开事件,基本都是这种写法来处理自绘的界面,记得很久很久之前自己写自绘的按钮就是在WM_PAINT 进行贴图,然后点击处理点击事件,就可以实现图片的按钮,比自己修改win32 button还方便一些,因为整个自绘逻辑都是自己开发的,用系统Button,很多逻辑都是系统,这样子导致很多限制,要打补丁的地方太多了。

            TEventUI event = { 0 };
            event.Type = UIEVENT_BUTTONUP;
            event.pSender = m_pEventClick;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            // By daviyang35 at 2015-6-5 16:10:13
            // 在Click事件中弹出了模态对话框,退出阶段窗口实例可能已经删除
            // this成员属性赋值将会导致heap错误
            // this成员函数调用将会导致野指针异常
            // 使用栈上的成员来调用响应,提前清空成员
            // 当阻塞的模态窗口返回时,回栈阶段不访问任何类实例方法或属性
            // 将不会触发异常
            CControlUI* pClick = m_pEventClick;
            m_pEventClick = NULL;
            pClick->Event(event);

这里获取到点击控件,通过坐标计算找到合适控件【通过计算】,然后触发事件,这里事件就是UIEVENT_BUTTONUP,然后控件开始处理该事件。这个是虚函数,基本不会重载该虚函数,

button 控件处理函数

void CControlUI::Event(TEventUI& event)
{
    if( OnEvent(&event) ) DoEvent(event);
}

所有控件的基类,OnEvent 是委托事件,用户代码基本不会委托这个函数,除了一些复杂的控件。
DoEvent是虚函数,所有控件基本都会重载这个函数,用来专门事件处理的。

这里OnEvent 一般是不会赋值,只有特殊控件需要自己处理时间,才会触发,这里OnEvent(event) 默认返回true,除非我自己添加委托事件返回false不喜欢通知外部才会不调用DoEvent。

butto调用 DoEvent

        if( event.Type == UIEVENT_BUTTONUP )
        {
            if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
                if( ::PtInRect(&m_rcItem, event.ptMouse) && IsEnabled()) Activate();
                m_uButtonState &= ~(UISTATE_PUSHED | UISTATE_CAPTURED);
                Invalidate();
            }
            return;
        }

Activate 激活按钮触发点击事件,Button还有其他事件要处理,来显示不同点击事件

    bool CButtonUI::Activate()
    {
        if( !CControlUI::Activate() ) return false;
        if( m_pManager != NULL ) m_pManager->SendNotify(this, DUI_MSGTYPE_CLICK);
        return true;
    }

触发通知,这个等同win32变成的发送 BN_CLICKED事件,m_pManager里面有一个list 包含notify listener,遍历进行通知。
duilib窗口对象都会绑定一个CPaintManagerUI,窗口创建后就添加事件监听。
我们开发代码都会实现INotifyUI或者直接继承WindowImplBase,我们业务代码基本都在notify实现的。
总结
这里这么多代码,无法就是子控件与窗口建立联系,方便回调。
duiib这个界面库,基本在各大厂商进行验证,可以算是windows pc上面一个标准了,官方开源版本太老,可以用其他大厂的开源duilib直接开发,不过自己继续在官方版本也可以。
如果跨平台基本就是electron,但这种内存比较大,几百M跑不掉,对内容类型的界面用这个比较方便,对于性能要求比较高还是用duilib比较好。
QT也是不错的选择,不过我自己没有用过,wps yy貌似都是qt开发的。
选择哪个开发主要看自己业务,没有完美的东西

标签: c++ duilib 界面库
最后更新:13 10 月, 2022

小鱼儿

爱研究技术,爱玩LOL

点赞
下一篇 >

COPYRIGHT © 2022 小鱼塘. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

湘ICP备18005349号