duilib消息类型汇总


duilib作为一个轻量快速的开源界面库,有很多值得学习的地方,虽然也有不少人吐槽它的各种问题,但是它是一种技术,技术没有正确与错误,好与坏之分,可以取其精华,学为己用就足够了。

1、duilib的整体结构图

在这里插入图片描述
通过设计图有了一个初步认识后,接下来开始进一步深入学习了解,主要从以下几个方面进行了解学习:
库的组成;框架基本流程;元素创建机制;消息处理机制。

1.1、库的基本组成

1.1.1、工具库

由于duilib没有对外部的任何库进行依赖,所以在其内部实现了很多用于支撑项目的基础类(如下图所示)。这些类分布在Util文件夹中:
在这里插入图片描述

  • UI相关:CPoint / CSize / CDuiRect。
  • 简单容器:CStdPtrArray / CStdValArray / CStdString / CStdStringPtrMap。

上面这些类看名字就基本能够理解其具体的含义了,当然除了基本的基础库,还有一些和窗口使用相关的工具的封装,如窗口工具:WindowImplBase,这个工具我们在这里不详述,后面使用中会经常用到。

1.1.2、控件库

在这里插入图片描述
控件库在duilib的实现中被分为了两块:Core和Control

  • Core中包含的是所有控件公用的部分,里面主要是一些基类和绘制的封装。
  • Control中包含的就是各个不同的控件的行为了。

这当中尤其要注意控件基类CControlUI和容器基类CContainerUI,这是duilib核心类(如下图所示)中是很重要的两部分:
在这里插入图片描述

1.1.2.1、控件基类:CControlUI

CControlUI在整个控件体系中非常重要,它是所有控件的基类,也是组成控件树的基本元素,控件树中所有的节点都是一个CControlUI

它基本包括了所有控件公共的属性,如:位置,大小,颜色,是否有焦点,是否被启用等等。当然这个类中还提供了非常多的基础函数,用于重载来实现子控件,如获取控件名称和ClassName,是否显示等等。

另外为了方便从XML中直接解析出控件的各个属性,这个类中还在提供了一个SetAttribute的方法,传入字符串的属性名称和值对特定的属性进行设置,内部其实就是挨个比较字符串去完成的,所以平时使用的时候就还是不要使用的比较好了,因为每个属性实际上都有特定的方法来获取和设置。

另外每个控件中还有几个事件管理的对象——CEventSource,这些对象会在特定的时机被触发,如OnInit,调用其中保存的各个回调函数。

1.1.2.2、容器基类:CContainerUI

有了基本的控件基类之后,我们就需要容器来将他管理起来,这个容器就是CContainerUI,其内部用一个数组来保存所有的CControlUI的对象,后续的所有工作,就都是基于这个对象来进行的了。

这样在CContainerUI里面,主要实现了一下几个功能:

  • 子控件的查找:CContainerUI::FindControl
  • 子控件的生命周期管理:是否销毁(在Remove的时候自动销毁) / 是否延迟销毁(交给CPaintMangerUI去一起销毁)。
  • 滚动条:所有的容器都支持滚动条,在其内部会对键盘和鼠标滚轮事件进行处理(CContainerUI::DoEvent),对其内部所有的元素调整位置,最后在绘制的时候实现滚动的效果。
  • 绘制:由于容器中有很多元素,所以为了加快容器的绘制,绘制的时候会获取其真正需要绘制的区域,如果子控件不在此区域中,那么就不予绘制了。

而对于这些控件的绘制实现以及相关使用,在后续具体进一步学习中再深入详解。

1.1.3、框架基本流程

框架的基本流程实际上类似Win32创建窗口流程,如果对于Win32比较熟悉,这部分可以很快掌握。

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    
    
    CPaintManagerUI::SetInstance(hInstance);        // 第一步: 实例句柄与渲染类关联
    CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));
    HRESULT Hr = ::CoInitialize(NULL);              // 第二步:初始化COM库, 为加载COM库提供支持
    if( FAILED(Hr) ) 
        return 0;
    CMainFrameWnd* pFrame = new CMainFrameWnd();    // 第三步:创建窗口类
    if( pFrame == NULL ) 
        return 0;
    pFrame->Create(NULL, _T("主程序"), UI_WNDSTYLE_FRAME, 0L, 0, 0, 800, 600); // 第四步:注册窗口类与创建窗口
    //  实际上这里调用Create操作和Win32创建窗体一样,内部实际上做了以下操作:
    //  -> RegisterSuperclass (注册一个超类 即已有一个窗口类的基上再注册一个窗口类)
    //  -> RegisterWindowClass (注册窗口类)
    //  -> ::CreateWindowEx (创建窗口,此时触发 WM_CREATE 消息)
    //  -> HandleMessage  ( WM_CREATE消息处理OnCreate)
    pFrame->CenterWindow();          // 第五步:窗口居中显示
    ::ShowWindow(*pFrame, SW_SHOW);
    CPaintManagerUI::MessageLoop(); // 第六步:处理消息循环
    ::CoUninitialize();             // 第七部:退出程序并释放COM库
    return 0;
}

1.1.4、消息处理机制

  • 第一步:注册消息处理函数

    在CWindowWnd注册窗口(RegisterWindowClass())里,注册消息回调函数(__WndProc);

  • 第二步:消息分发

      消息回调函数(处理所有系统发送的消息),然后回调函数通过子类的CMainFrameWnd::HandleMessage对消息进行分发。
    
     非窗口消息通过CMainFrameWnd::HandleMessage调用CPaintManagerUI::MessageHandler进行分发。
    
  • 第三步:消息循环

    在CPaintManagerUI类的MessageLoop处理消息循环; 
    
    接收到消息以后,进入消息回调函数(__WndProc);
    

(注:以下内容以鼠标单机Button事件为例)。

  • 第四步:处理控件消息

      鼠标按下时(WM_LBUTTONDOWN),查找鼠标点击的控件。
    
      处理控件的鼠标按下消息:通过调用基类CControlUI:: DoEvent,引起子类如CButtonUI::DoEvent事件。
    
     子类的DoEvent对不同类型的事件进行处理。通过CPaintManagerUI:: SendNotify回调控件注册的事件。
    

2、本篇记录duilib的消息类型(类似于MFC的消息)

在这里插入图片描述
使用简介:

消息的处理在duilib继承自public CWindowWnd, public INotifyUI 的类中**void Notify(TNotifyUI& msg)**中,如下:

void Notify(TNotifyUI& msg)
    {
    
    
        if( msg.sType == _T("windowinit") )   //此处为消息类型宏定义或者消息类型字符串
       {
    
    
          //要做的事情
         
       }
    }
void CContainerDlg::Notify(TNotifyUI& msg)
{
    
    
	//
	if (msg.sType == DUI_MSGTYPE_CLICK)
	{
    
    
		if (msg.pSender == m_pCloseBtn)
		{
    
    
			CefModule::CefManager::GetInstance()->PostQuitMessage(0);
			m_pCefControl->CloseAllBrowser();
			m_pSDOLogin->CloseLoginDialog();
			this->Close();
		}
		else if (msg.pSender == m_pSettingBtn)
		{
    
    
			wstring strExe = GAME_DIR L"wooolcfg.exe";
			PROCESS_INFORMATION pi = {
    
     0 };
			STARTUPINFO si = {
    
     0 };
			si.cb = sizeof(si);
			BOOL ret = CreateProcess(nullptr, (LPWSTR)strExe.c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
			if (ret)
			{
    
    
				CloseHandle(pi.hProcess);
				CloseHandle(pi.hThread);
			}
		}
		else if (msg.pSender == m_pHideLoginDialogBtn)
		{
    
    

			//MessageBox(NULL, L"1", L"1", MB_OK);
			m_pSDOLogin->SetLoginDialogState(2);
			//MessageBox(NULL, L"2", L"2", MB_OK);
		}
		else if (msg.pSender == m_pShowLoginDialogBtn)
		{
    
    
			//MessageBox(NULL, L"3", L"3", MB_OK);
			m_pSDOLogin->SetLoginDialogState(1);
			//MessageBox(NULL, L"4", L"4", MB_OK);
		}
	}
	else if (msg.sType == DUI_MSGTYPE_WINDOWINIT)
	{
    
    
		if (m_pSDOLogin != nullptr && m_pLoginFrameArea != nullptr)
		{
    
    
			m_pSDOLogin->ShowLoginDialog(LoginCallback, 0, 0);
			MoveLoginFrame();
		}
	}

	if (m_pAreaTypeSwitch != nullptr)
	{
    
    
		m_pAreaTypeSwitch->Notify(msg);
	}
}

3、DuiLib中自定义消息以及事件消息有什么区别和HandleMessage处理自定义消息以及Notify处理事件消息

3.1、在DuiLib中,自定义消息和事件消息是两种不同类型的消息,它们在处理方式和用途上有一些区别

  1. 自定义消息:
    自定义消息是应用程序开发者自己定义的消息类型,用于在不同的控件之间进行通信和传递数据。这些消息通常不是系统定义的消息,而是开发者根据自己的需求添加的。自定义消息的用途包括但不限于在控件之间传递数据、触发特定的操作等。当控件接收到自定义消息时,它会调用对应的处理函数来处理这些消息。

  2. 事件消息:
    事件消息是在DuiLib中预定义的消息类型,用于响应用户的交互操作,如鼠标点击、键盘输入等。当用户在控件上进行操作时,DuiLib会生成相应的事件消息,并传递给控件的父控件,直到找到一个处理该事件的控件为止。通常,控件会通过处理事件消息来执行相应的操作,例如打开一个菜单、处理用户输入等。

  3. HandleMessage和Notify:
    在DuiLib中,HandleMessage和Notify是两个用于处理消息的函数。

    • HandleMessage
      HandleMessage是用于处理自定义消息和一些特定的系统消息的函数。每个控件类都有一个HandleMessage函数,你可以在这个函数中实现对自定义消息的处理逻辑。当控件接收到一个消息时,DuiLib会调用控件的HandleMessage函数,然后你可以根据消息类型进行相应的处理。

    • Notify
      Notify是用于处理事件消息的函数。当控件接收到一个事件消息时,DuiLib会调用控件的Notify函数,然后你可以在这个函数中根据事件类型执行相应的操作。例如,当用户点击了一个按钮控件时,DuiLib会生成一个点击事件消息,然后调用按钮控件的Notify函数,你可以在这个函数中执行按钮的点击响应逻辑。

在处理自定义消息和事件消息时,你可以通过wParamlParam参数来传递额外的数据。在DuiLib中,还有一些其他的消息处理函数,比如OnEventOnNotify等,用于处理特定类型的事件和通知消息。这些函数都是为了方便你在控件中处理消息而提供的。

总结:自定义消息用于应用程序内部的通信和数据传递,而事件消息用于响应用户的交互操作。在处理自定义消息时,使用控件的HandleMessage函数,在处理事件消息时,使用控件的Notify函数,同时可以结合其他特定的消息处理函数来实现控件的功能。

猜你喜欢

转载自blog.csdn.net/qq_44918090/article/details/131782644