前言
学会了怎么写XML文件,但是我还是不知道怎么实现各个控件之间的消息传递。于是我对源代码好好研究了一下,发现duilib作为一个界面库有自己独立的封装的窗口类,也就是WindowsImplBase。
在这个类中,实现对windows窗口传过来的消息的处理,以及初始化时创建控件,绘制窗口等功能。继承这个窗口类,就可以将我们自己的XML文件解析,显示自己设计的窗口。
//.h头文件
virtual CControlUI* CreateControl(LPCTSTR pstrClass); //创建XML文件中的控件,如果自绘控件的话,需要重载这个函数,否则无法加载XML文件中的自绘控件
virtual CDuiString GetSkinFolder(); //设置XML文件的路径
virtual CDuiString GetSkinFile() = 0;//获取XML文件的名字
窗口类解析完XML文件后,窗口就可以显示了,我们还要重载INotifyUI类中的消息处理函数来处理自己窗口获得的消息。
void Notify(TNotifyUI& msg);//消息处理函数;
在这个函数里面,msg是一个结构体,新手同学可以去看看定义。msg.pSender这个指针就是获得消息的控件指针,调用GetType()这个函数获取消息的类型,是单击还是右键等等,然后调用GetName这个函数去对应控件,做相应的处理。
typedef struct tagTNotifyUI
{
CDuiString sType;
CDuiString sVirtualWnd;
CControlUI* pSender;
DWORD dwTimestamp;
POINT ptMouse;
WPARAM wParam;
LPARAM lParam;
} TNotifyUI;
在这里就有一个相当有用的点,假如单击这个控件,要对另一个控件进行操作该怎么办呢?
在这里我也疑惑了很久,可能是因为菜鸟。后面看别人的代码自己总结出来一种方法,不知道有没有更好的。
每一个控件都有一个管理控件的对象(m_PaintManager),通过这个对象管理对应的控件,我们还可以查找窗口里的任意控件。里面提供了很多种查找方法,常用的如下。
CControlUI* FindSubControlByPoint(CControlUI* pParent, POINT pt) const;
CControlUI* FindSubControlByName(CControlUI* pParent, LPCTSTR pstrName) const;
CControlUI* FindSubControlByClass(CControlUI* pParent, LPCTSTR pstrClass, int iIndex = 0);
用这三个函数基本上可以满足我们的所有需求。有通过坐标查找的,有用名字的,还有用控件属性的。函数里的第一个参数是要查找的控件的父控件,也可以是更上层的父控件。在用第三个函数的时候需要注意,它的遍历子控件的方式是深度优先遍历,如果需要用到iIndex(指第几个同类控件),要考虑到前面包含的所有同类控件,并且标号是从0开始的。
这样我们就可以通过msg.pSender->GetParent() 来获得父类(可以反复调用),GetManager() 来使用查找方法,然后用查找子控件的方式获得要处理的控件的指针,OK了。
还有一点就是返回的指针都是CControlUI类型的,有很多设置参数的函数都无法使用。因为duilib所有控件都是以CControlUI为父类的,所以可以使用强制转换转成它原来的控件类型,就很方便对它操作了。