duilib 自带树形控件的认识
CTreeViewUI
1、该控件继承自CListUI,所以是使用了对应的列表来模拟树形控件。该控件的容器填装的是CTreeNodeUI,而CTreeNodeUI也继承CListContainerElementUI,所以树形控件剥掉外壳其实就是CListUI,然后子列表是CListContainerElementUI。
2、a.每个属性控件包含的节点:扩展按钮点前面的空格、扩展按钮、checkbox按钮、空格 再加上 后面的用户自添元素。所有元素加起来的宽度是250,也就是说如果该树形控件比较大的话就会出现太窄而无法容下所有元素的现象。所以这里可以根据自身的需要进行相应的调整。如代码UITreeView.cpp的第32行:this->SetFixedWidth(250);
b.树形控件的每个节点的扩展按钮前面的空白如何计算呢?如代码的UITreeView.cpp的第48行:pDottedLine->SetFixedWidth(_ParentNode->GetDottedLine()->GetFixedWidth()+16); 通过获取父节点的宽度再加上16。如果父节点是空则使用默认的2.虽然这里有默认的了,但是在添加childnode的时候会更新空白宽度调用CalLocation
3、节点相关属性的设置则可以看对应的void CTreeNodeUI::SetAttribute( LPCTSTR pstrName, LPCTSTR pstrValue )函数的设置。再根据我第二点的描述则可以简单应用。
4、关于树形控件子树的打开跟关闭。这里使用的是刚开始的时候默认全部是打开的。是因为每个控件默认是全部打开的。虽然是打开的,但是每个扩展按钮默认都是check=false,所以在放图片的时候注意这个foldattr属性normalimage跟selectedimage。
如果在程序开始运行的时候不想让每个控件都打开,只想让部分控件打开则需要修改树形控件的程序。修改的位置是在bool CTreeNodeUI::Add( CControlUI* _pTreeNodeUI ),该函数是在UIDlgBuilder进行解析xml函数的时候直接调用的函数。这里我尝试将selected="true" 进行设置发现只是图标修改了而子树还显示着。
所以这里我在Add函数调用的CTreeNodeUI::AddChildNode的第370行添加了
// 这里使用 !this->IsVisible()是如果本父节点是非可见了那么它对应的子树也应该是不可见的。
if (pFolderButton->IsSelected() || !this->IsVisible())
SetItemExpand(this);
并写了SetItemExpand函数,该函数我是抄袭对应的CTreeViewUI的SetItemExpand
void CTreeNodeUI::SetItemExpand( CTreeNodeUI* _TreeNode ) { if(_TreeNode) { if(_TreeNode->GetCountChild() > 0) { int nCount = _TreeNode->GetCountChild(); for(int nIndex = 0;nIndex < nCount;nIndex++) { CTreeNodeUI* pItem = _TreeNode->GetChildNode(nIndex); pItem->SetVisible(false); if(pItem->GetCountChild() && !pItem->GetFolderButton()->IsSelected()) SetItemExpand(pItem); } } } }
这样,当设置了selected="true"的时候,则相应的子树均为不可见状态。
5、对应的按钮响应函数:其实在TreeViewUI的Add函数中已经都有对应的显示了。
bool CTreeViewUI::Add( CTreeNodeUI* pControl )
long CTreeViewUI::AddAt( CTreeNodeUI* pControl, int iIndex )
均已经做了相应的操作。
但是我们经常做这样子的操作:双击树形控件checkbox右边的空白区域然后打开的子树则会相应的关闭,或者关闭的子树则会相应的打开。(即修改对应的foldattr的selected参数的值)。
在这里我们这样子却做不了。即使像
本身add里面那样子操作
pControl->OnNotify += MakeDelegate(this,&CTreeViewUI::OnDBClickItem);
pControl->GetFolderButton()->OnNotify += MakeDelegate(this,&CTreeViewUI::OnFolderChanged);
pControl->GetCheckBox()->OnNotify += MakeDelegate(this,&CTreeViewUI::OnCheckBoxChanged);
也是没办法获取到。究其原因得看本身的空白处到底是什么: COptionUI();
而看其对应的父控件的CbuttonUI则可以知其一二,里面的onevent对应的
if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK ) { if( ::PtInRect(&m_rcItem, event.ptMouse) && IsEnabled() ) { m_uButtonState |= UISTATE_PUSHED | UISTATE_CAPTURED; Invalidate(); } return; }
只是做了相应的图像更新操作,而没有发送对应的onnotify double click操作。那如果在button里面添加该操作呢?但是事实证明在onevent根本捕捉不到对应的dbclick,因为按钮是不支持双击的。
那到底啥原因呢?
后来我发现在注册windowclass的时候
WNDCLASS wc = { 0 };
wc.style = GetClassStyle();
该GetClassStyle是虚函数,可以通过继承该函数添加相应的style来实现双击的效果。
UINT GetClassStyle() const
{
return CS_DBLCLKS;
};
如果需要使用自己量身定制的树形控件,可以看对应的duilib官方给的demo中的GameDemo。(即自绘树形控件)