最近在一个新的产品上使用了duilib,终于可以方便的做出漂亮的界面了,在此要感谢开发者。不过在使用的过程中也发现了几个问题,但duilib的源码好像已经不更新了,所以就在此记录下来,方便后来人。
遇到的问题主要TreeView这个控件,一个是树节点模板加载的问题,一个是树的叶子节点不显示展开按钮的问题。
1. 树节点模板加载
在我们的实际使用中,一般只是在主xml中写一个TreeView,然后TreeNode会写在一个单独的xml中,比如就叫treenode.xml,然后通过这个treenode.xml来动态生成TreeNode节点,再添加到TreeView下面。但我在实际使用中发现无法生成TreeNode,老是崩溃。后来通过跟踪代码发现问题处在CDialogBuilder::_Parse()这个函数中,具体在275行处,代码如下:
//树控件XML解析
else if( _tcscmp(pstrClass, _T("TreeNode")) == 0 ) {
CTreeNodeUI* pParentNode = static_cast<CTreeNodeUI*>(pParent->GetInterface(_T("TreeNode")));
CTreeNodeUI* pNode = new CTreeNodeUI();
if(pParentNode){
if(!pParentNode->Add(pNode)){
delete pNode;
continue;
}
}
//...
continue;
}
那么问题就出在
CTreeNodeUI* pParentNode = static_cast<CTreeNodeUI*>(pParent->GetInterface(_T("TreeNode")));
这一句,在使用pParent的时候,没有先判断是否为NULL,对于TreeView和TreeNode在一个xml文件中的,自然是没有问题的,因为pParent不会为NULL,但对于我从treenode.xml创建的来说,就有问题了,这个时候pParent会为NULL,所以要先判断下。
改了这里就可以了么?显然不是。改好后,你会发现返回的总是NULL,再看下代码,你会发现没有把创建的pNode赋值给pReturn,从而导致总是返回NULL。所以,在continue之前要把pNode赋值给pReturn。
2. 叶子节点展开按钮
下面再来说说叶子节点的问题。加入选择了显示展开按钮,那么对于所有的树节点都是会显示的。但其实对于没有子节点的叶子节点来说,不应该显示这个按钮才对。最开始,我以为可以通过设置TreeNode的SetVisibleFolderBtn()函数来取消显示,但发现不行。原来是在重绘的时候,会先判断该按钮是否可见,如果不可见,就不重绘了。所以问题就出现了,我们是从可见转换到不可见,应该重绘才对。
既然从可见设置到不可见不行,我就想反操作一下,先让所有的展开按钮不可见,然后非叶子节点都设置展开按钮可见就可以了。经过实践,发现的确可以实现。不过叶子节点的位置不太好看,有点太靠前了。我想要的效果是展开按钮的空间位置依然存在,只是是空的而已。
因为不想改动duilib的代码,所以我只好改动我的代码(方式搓了点)。对于叶子节点,取到展开按钮后,强制把它的几个关联图片全都设置成空。最后终于达到我要的效果,唯一的遗憾是点击叶子几点的展开按钮位置,还是可以发现有不同的,没有实现完全空着的感觉。