Duilib源码分析(四)绘制管理器—CPaintManagerUI—(前期准备二)

时间:2020-12-12 23:34:19

  接下来,我们继续分析UIlib.h文件中余下的文件,当然部分文件可能顺序错开分析,这样便于从简单到复杂的整个过程的里面,而避免一开始就出现各种不理解的地方。

  1. UIManager.h:UI管理器,暂时放在后面介绍;

  2. UIBase.h:UI窗口相关,包括常用的窗口风格、窗口类风格的宏定义,调试相关,以及基本窗口类;

    首先宏定义了几个常用的窗口风格、窗口扩展风格和窗口类风格,以UI_WNDSTYLE_XXX和UI_CLASSSTYLE__XXX开头的;

    ASSERT采用的是CRT的_ASSERTE、DUI__Trace、DUI__TraceMsg用以调试、跟踪消息,不过注意DUI__Trace字符串长度不能超过300字节;

    CNotifyPump:通告消息泵,用以对消息分发、下发(主要是对继承树的各个添加到_messageEntries的消息映射遍历分发,并执行相应的处理函数),数据成员:m_VirtualWndMap:

    虚拟窗口的集合,类型CStdStringPtrMap可以较为快速查找,此外可能增加了虚拟窗口,此时便先对虚拟窗口分发,若处理则直接返回,否则再遍历主窗口,成员函数:AddVirtualWnd:

    添加虚拟窗口,参数strName、pObject分别为虚拟窗口名称与该虚拟窗口的消息通告泵对象,RemoveVirtualWnd:移除指定名称的虚拟窗口,NotifyPump:通告泵,实现真正的消息

    分发操作(先对虚拟窗口分发,再对主窗口遍历分发),LoopDispatch:循环分发消息(对消息继承树和_messageEntries遍历,并对应消息处理类型,调用执行相应的消息处理接口);

    CWindowWnd:窗口基类,将Win32的创建窗口的主要过程进行了封装,一些控件可能会从它继承实现;先从数据成员:m_hWnd:窗口句柄,m_OldWndProc:早期的窗口消息

    处理函数地址,m_bSubclassed:是否为子类化的窗口类,成员函数:构造函数CWindowWnd:其中m_OldWndProc初始化为默认窗口处理函数::DefWindowProc,GetHWND:

    获取当前窗口句柄,同重载的运算符operator HWND(),RegisterWindowClass:注册窗口类,暂时提供一个默认值的窗口类,重点关注其中的__WndProc的消息处理函数,可以发现

    很熟悉的操作,对是这样的,他把本类对象保存在GWLP_USERDATA窗口关联的用户数据中了,便于下次可直接取出(但保证其他地方不再更新该GWLP_USERDATA的用户数据),

    RegisterSuperclass:注册子类化的窗口类,从一个已存在的窗口中获取到WNDCLASSEX信息,此外其消息处理函数__ControlProc:内部处理方式不再是使用GWLP_USERDATA

    关联,而是使用SetProp设置窗口属性表项,来保存本来对象,便于下一次GetProp取出本类对象,调用本类的非静态成员消息处理函数;Subclass:子类化窗口类,内部调用

    SubclassWindow实现窗口子类化(事实上内部调用的还是SetWindowLongPtr((hwnd), GWLP_WNDPROC, (LPARAM)(WNDPROC)(lpfn),这样用__WndProc接管消息处理,此外

    还调用了SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(this))用来保存本类对象,便于后期消息处理,Unsubclass:卸载窗口子类化:使用原消息

    处理函数来接管消息处理;综上,本类中子类化窗口的方式有:1. 通过GetSuperClassName获取已注册的父类窗口类名,再获取WNDCLASSEX信息,并通过__ControlProc来处理消息;

    2. 使用Subclass,传入已创建好的窗口句柄,这样通过SubclassWindow和SetWindowLongPtr来达到hook消息的目的,多个版本的Create函数与CreateDuiWindow:创建窗口的过程:

    获取超类类名,若已经给予,则调用RegisterSuperclass注册新的窗口类(主要是为了继承部分窗口类的属性),若未给予超类类名,则调用RegisterWindowClass注册一个默认值的窗口类,

    此后调用CreateWindowEx创建该窗口,ShowWindow:显示或隐藏当前窗口,ShowModal:模拟MFC中的对话框DoModal函数的处理流程;可以看到将拥有者窗口变得不可用,并使得

    当前窗口显示,此后内部使用自己的一套消息泵来从线程消息队列中获取消息,当内部消息泵收到本窗口消息WM_CLOSE或是WM_QUIT消息则会退出消息泵,并使得父窗口可用并获取到焦点

    ,另外对于消息WM_QUIT消息,需要将该消息转发给拥有者窗口(不一定是父窗口),使得拥有者窗口可被销毁(因为能跳出内部的GetMessage并得到WM_QUIT消息,则为销毁拥有者窗口);

    Close:关闭窗口,内部使用::PostMessage(WM_CLOSE)实现,发送消息到该线程的消息队列中直接返回;另外SendMessage:内部使用SendMessage发送消息到消息对应处理函数处理

    并等待处理再返回;CenterWindow:居中显示窗口,内部处理了多显示器的情况,若存在拥有者窗口,则获取拥有者窗口所在显示器大小并使得该窗口居中显示,SetIcon:设置当前窗口的

    大小图标,内部调用LoadImage(旧用LoadIcon,被替代)加载资源ID:nRes,不过这里需要批评一下之前定义了STRINGorID类型,其实这里可以直接来用的,ResizeClient:调整窗口客户

    区域大小,内部调用了AdjustWindowRectEx设置客户区域大小并获取调整后所得到的窗口区域大小,并通过SetWindowPos设置窗口大小;HandleMessage:成员消息处理函数,真实地

    接管消息处理不过内部目前只是调用CallWindowProc暂时使用m_OldWndProc来处理消息,此外一个比较有用的消息处理函数OnFinalMessage,专门用来在窗口销毁后的最后一个消息

    WM_NCDESTROY中处理其他的资源销毁的任务,这样外部就可以无需显示的调用当前窗口类的析构函数来销毁内部内核资源或其他资源了,很方便的;最后该类基本完成了一个基本的窗口类

    其他需要特殊处理的窗口类可以继承该类实现自己的操作,如后面介绍的WindowImplBase类。

  3. UIControl.h:UI控件基类,主要实现了控件相关如文本、图形、位置、菜单等属性设置

    FINDCONTROLPROC:声明的控件查找函数,CControlUI* (CALLBACK* FINDCONTROLPROC)(CControlUI*, LPVOID),用在回调查找中;

    CControlUI:UI控件基类,大部分控件实现继承于该类,因该类比较大,所以我们在分析的时候,建议先从成员函数开始;构造函数初始化了一系列的数据成员,暂不理会,后面涉及到相关数据成员

    时再回头看看即可,析构函数~CControlUI:可以看到内部OnDestroy为我们之前分析的事件源,控件析构的时候需要处理的OnDestroy事件,此外调用了CPaintManagerUI管理的释放该UI对象

    消息通告和计时器,这样消息不会再发给当前已被释放的UI对象,GetName/SetName:获取/设置控件的名称m_sName,GetClass:获取控件类名称"ControlUI",子类一般会重写该函数,

    GetInterface:用以根据pstrName匹配获取当前对象的继承层次中的指针对象,GetControlFlags:获取控件标记(取UIFLAG_TABSTOP、UIFLAG_SETCURSOR、UIFLAG_WANTRETURN)

    Activate:当前控件是否为激活的状态(可见并可用),GetManager:获取管理当前UI控件的CPaintManagerUI对象m_pManager,SetManager:设置管理该UI的m_pManager、父控件,此外若

    提供了需要初始化处理操作的事件源OnInit,再此将执行该事件源,GetParent:获取当前控件的父控件,GetText/SetText:获取/设置当前控件的文本并更新继承控件树控件大小,GetBkColor/

    GetBkColor2/GetBkColor3/SetBkColor/SetBkColor2/SetBkColor3/:设置背景色(提供三色,具体作用后面介绍),GetBkImage/SetBkImage:获取/设置背景图片,GetFocusBorderColor/

    SetFocusBorderColor:获取/设置焦点时边框颜色,IsColorHSL/SetColorHSL:获取/设置是否开启HSL色彩模式,GetBorderRound/SetBorderRound:获取/设置边框圆角大小,

    DrawImage:绘制图像,参数hDC将要绘制到的控件或窗体画刷句柄,pStrImage为图形内容字符串(含文件名或资源名等),函数内部根据内容字符串解析并调用CRenderEngine渲染引擎绘制,具体

    操作过程后面分析,GetBorderSize/SetBorderSize:获取/设置圆角边框画笔大小m_nBorderSize(命名也是醉了,含义不清与m_cxyBorderRound容易冲突),GetBorderColor/SetBorderColor:

    获取/设置圆角边框颜色,SetLeftBorderSize/SetTopBorderSize/SetRightBorderSize/SetBottomBorderSize:设置/获取左边框、上边框、右边框、下边框画笔大小,SetBorderStyle:设置边框

    画笔风格,SetPos/GetPos:设置/获取控件位置,m_rcItem,GetWidth/GetHeight/GetX/GetY:获取控件宽度、高度、左位置、上位置(左上位置),SetPadding/GetPadding:设置填充区域

    m_rcPadding,似乎内部未曾使用该变量,SetFixedXY/SetFixedWidth/SetFixedHeight:设置预设值控件的大小、宽度、高度,一般通过SetPos与GetPos获取到实际的大小,此外SetMinXXX系列

    函数设置最小最大宽度、高度,SetRelativePos/SetRelativeParentSize:设置父控件、相对父控件的相对位置,SetToolTip/GetToolTip:设置信息提示,鼠标停留时的提示框信息,SetToolTipWidth:

    设置信息框宽度,SetShortcut/GetShortcut:设置控件快捷键key,SetContextMenuUsed:设置是否使用菜单上下文,SetUserData/GetUserData:设置/获取用户数据,SetTag/GetTag:设置/

    获取标记数据,SetVisible:设置是否显示,SetEnabled:设置是否可用,SetMouseEnabled:设置鼠标是否可用,SetKeyboardEnabled:设置键盘是否可用,SetFocus:设置是否为焦点,

    SetFloat:设置是否可停浮,FindControl:查找控件,并执行Proc回调函数,Invalidate:使无效,重绘,NeedUpdate/NeedParentUpdate:需要更新重绘或父控件继承树重绘,GetAdjustColor:

    获取调整后的色彩,Init、DoInit:执行初始化操作,其中OnInit提供初始化事件源,Event、DoEvent:执行事件操作,其中OnEvent提供事件源,SetAttribute:设置控件属性,ApplyAttributeList

    :设置属性列表,内容包含各种可能的属性字符串,解析并调用SetAttribute设置各属性,EstimateSize:获取预设值控件大小,DoPaint:绘制操作,主要执行背景颜色、背景图、状态图、文本、边框

    等,PaintBkColor/PaintBkImage/PaintStatusImage/PaintText/PaintBorder:分别为绘制背景色、背景图片、状态图、文本、绘制边框,DoPostPaint:绘制相应控件大小至HDC,布局中用到,

    SetVirtualWnd /GetVirtualWnd:设置/获取虚拟窗口;目前大部分成员函数和成员数据说明,一部分函数用以外部调用接口,一部分用于内部绘制操作,此外也有部分参数未曾用到或是用以控制绘制,

    接下来说说数据成员:公有成员5个事件源:OnInit、OnDestroy、OnSize、OnEvent、OnNotify,分别为初始化源、释放源、大小位置改变源、事件源、通告源,受保护成员:m_pManager:绘制

    管理器对象,m_pParent,父控件对象,m_sVirtualWnd:虚拟窗口,m_sName:控件名称,m_bUpdateNeeded:是否需要更新控件,m_bMenuUsed:是否使用菜单上下文,m_rcItem:

    控件位置,m_rcPadding:控件填充大小,m_cXY:控件预设值位置大小,m_cxyFixed:控件固定大小,m_cxyMin、m_cxyMax:预设值最小、最大值,m_bVisible:是否可显示,此外还有一个

    m_bInternVisible:内部使用的是否可显示控件,用在某些继承的控件实现中需要用到的,m_bEnabled:控件是否可用,m_bMouseEnabled:鼠标是否可用,m_bKeyboardEnabled:键盘是否

    可用,m_bFocused:是否获取到焦点,m_bFloat:是否可停浮,m_bSetPos:是否在设置控件位置大小,m_tRelativePos:与父控件关联位置,m_sText:设置文本,m_sToolTip:设置信息提示

    m_chShortcut:快捷键CHAR,m_sUserData:用户保存的数据字符串,m_pTag:用户保存的标记,m_dwBackColor:背景色,m_sBkImage:背景图片,m_sForeImage:前景图片,

    m_dwBorderColor:边框颜色,m_dwFocusBorderColor:获取到焦点时边框颜色,m_bColorHSL:是否启用HSL色彩模型,m_nBorderSize:边框画笔大小,m_nBorderStyle:边框画笔风格,

    m_nTooltipWidth:提示信息框宽度,m_cxyBorderRound:圆角边框大小,m_rcPaint:绘制区域大小,m_rcBorderSize:边框位置大小;

  基本上对整个类进行了概括性的说明,更为详尽的比如:绘制场景、细节、布局等将在后期分析,目前我们只需要有个大概的概念即可。