今天来介绍一下 Duilib 中控件的 name 的保存及查询方法吧,使用 Duilib 的过程中,大家最常使用的一个功能可能就是 FindControl(LPCTSTR pstrName)
了吧,我们来看一下到底是怎么进行 Find 的。
先上源码:
CControlUI* CPaintManagerUI::FindControl(LPCTSTR pstrName) const
{
ASSERT(m_pRoot);
return static_cast<CControlUI*>(m_mNameHash.Find(pstrName));
}
struct TITEM
{
CDuiString Key;
LPVOID Data;
struct TITEM* pPrev;
struct TITEM* pNext;
};
class DUILIB_API CDuiStringPtrMap
{
public:
CDuiStringPtrMap(int nSize = 83);
~CDuiStringPtrMap();
void Resize(int nSize = 83);
LPVOID Find(LPCTSTR key, bool optimize = true) const;
bool Insert(LPCTSTR key, LPVOID pData);
LPVOID Set(LPCTSTR key, LPVOID pData);
bool Remove(LPCTSTR key);
void RemoveAll();
int GetSize() const;
LPCTSTR GetAt(int iIndex) const;
LPCTSTR operator[] (int nIndex) const;
protected:
TITEM** m_aT;
int m_nBuckets;
int m_nCount;
};
从以上代码可以看出,最重要的部分在于类 CDuiStringPtrMap
,这个类使用的场合很多,例如前面介绍过的字体的存储,此篇控件名称的存储,凡是可以以字符串为 key 值的都可以使用这个类。
TITEM** m_aT
数组地址,指向一个数组元素类型为TITEM*
的数组,同时,每一个元素又是一个链表头int m_nBuckets
数组预设大小int m_nCount
数组中实际存放的元素个数void Resize(int nSize = 83)
清空所有元素,删除数组,并重新创建数组LPVOID Find(LPCTSTR key, bool optimize = true) const
根据 key 值找对应的对象,参数optimize
代表找到此对象后是否要将此对象放在链表头部bool Insert(LPCTSTR key, LPVOID pData)
插入一条数据,若已存在相同 Key 则跳过LPVOID Set(LPCTSTR key, LPVOID pData)
已存在相同 Key 的场合,覆盖旧值,否则调用 Insert。 所以对于控件的名称尽量不要重复。若重复的话第二个以后的 name 只能通过FindSubControlByName
找到bool Remove(LPCTSTR key)
删除指定 Key 值数据void RemoveAll()
删除所有已保存元素int GetSize() const
返回已保存元素个数,也就是 m_nCountLPCTSTR GetAt(int iIndex) const
获取第 iIndex 个元素,这个我们得稍微看一下,源码如下:int pos = 0; int len = m_nBuckets; while( len-- ) { for( TITEM* pItem = m_aT[len]; pItem; pItem = pItem->pNext ) { if( pos++ == iIndex ) { return pItem->Key.GetData(); } } }
我们可以看到这个查找顺序是按数组从后往前的顺序查的,并按链表从前向后查,查到第 iIndex 个元素则返回,虽然不知道为什么这么写查询顺序,但是对于遍历来说,顺序从前往后还是从后往前倒是没有区别 (若单纯取第 n 个元素做某操作是有区别的,但目前 duilib 中所有的 CDuiStringPtrMap 类型的对象都只存在从头到尾的遍历,所以遍历顺序就没有关系了)。
LPCTSTR operator[] (int nIndex) const
操作符重载函数,作用和GetAt
一样
这个类本身的使用比较简单,但其中比较重要的一点是存储时所采用的结构,数据结构是一个数组,每个数组的元素又是一个列表的表头。在插入一个元素的时候有一个函数 —— UINT HashKey(LPCTSTR Key)
, 一个哈希函数,所以这也就是一个以拉链法解决冲突的一个实例。