QTreeWidget树的三态操作

来源:互联网 发布:心动网络 校招笔试 编辑:程序博客网 时间:2024/05/22 20:32

在工作中我们会经常使用到树状结构,例如Windows的资源管理器中的目录结构就用到了类似的控件。在Qt中可以使用QTreeWidget来实现类似的效果。

Qt中提供的QTreeWidget功能相对比较少,在实际中经常需要扩展它的功能,比如本文将要谈到的三态树的问题。


首先我们先创建一个QTreeWidget的对象,并添加一些节点:

[cpp] view plain copy
  1. void WidgetTreeTEST::createDirectoryStruct()  
  2. {  
  3.     QTreeWidgetItem *topLevelDirectory = new QTreeWidgetItem();  
  4.     topLevelDirectory->setText(0, "DIR");  
  5.     topLevelDirectory->setCheckState(0, Qt::Checked);  
  6.     topLevelDirectory->setIcon(0, QIcon(":/Resources/folder.png"));  
  7.   
  8.     //Direcoty C  
  9.     QTreeWidgetItem *directoryC = new QTreeWidgetItem();  
  10.     directoryC->setText(0, "LocalDrive C");  
  11.     directoryC->setCheckState(0, Qt::Checked);  
  12.     directoryC->setIcon(0, QIcon(":/Resources/folder.png"));  
  13.   
  14.     QTreeWidgetItem *file1 = new QTreeWidgetItem();  
  15.     file1->setText(0, "file1");  
  16.     file1->setCheckState(0, Qt::Checked);  
  17.     file1->setIcon(0, QIcon(":/Resources/file.png"));  
  18.   
  19.     QTreeWidgetItem *file2 = new QTreeWidgetItem();  
  20.     file2->setText(0, "file2");  
  21.     file2->setCheckState(0, Qt::Checked);  
  22.     file2->setIcon(0, QIcon(":/Resources/file.png"));  
  23.   
  24.     directoryC->addChild(file1);  
  25.     directoryC->addChild(file2);  
  26.   
  27.     //Directory D  
  28.     QTreeWidgetItem *directoryD = new QTreeWidgetItem();  
  29.     directoryD->setText(0, "LocalDrive D");  
  30.     directoryD->setCheckState(0, Qt::Checked);  
  31.     directoryD->setIcon(0, QIcon(":/Resources/folder.png"));  
  32.   
  33.     QTreeWidgetItem *file3 = new QTreeWidgetItem();  
  34.     file3->setText(0, "file3");  
  35.     file3->setCheckState(0, Qt::Checked);  
  36.     file3->setIcon(0, QIcon(":/Resources/file.png"));  
  37.   
  38.     directoryD->addChild(file3);  
  39.   
  40.     //Direcoty E  
  41.     QTreeWidgetItem *directoryE = new QTreeWidgetItem();  
  42.     directoryE->setText(0, "LocalDrive E");  
  43.     directoryE->setCheckState(0, Qt::Checked);  
  44.     directoryE->setIcon(0, QIcon(":/Resources/folder.png"));  
  45.   
  46.     QTreeWidgetItem *file4 = new QTreeWidgetItem();  
  47.     file4->setText(0, "file4");  
  48.     file4->setCheckState(0, Qt::Checked);  
  49.     file4->setIcon(0, QIcon(":/Resources/file.png"));  
  50.   
  51.     QTreeWidgetItem *file5 = new QTreeWidgetItem();  
  52.     file5->setText(0, "file5");  
  53.     file5->setCheckState(0, Qt::Checked);  
  54.     file5->setIcon(0, QIcon(":/Resources/file.png"));  
  55.   
  56.     QTreeWidgetItem *direcotryE1 = new QTreeWidgetItem();  
  57.     direcotryE1->setText(0, "file6");  
  58.     direcotryE1->setCheckState(0, Qt::Checked);  
  59.     direcotryE1->setIcon(0, QIcon(":/Resources/folder.png"));  
  60.   
  61.     QTreeWidgetItem *file6 = new QTreeWidgetItem();  
  62.     file6->setText(0, "file6");  
  63.     file6->setCheckState(0, Qt::Checked);  
  64.     file6->setIcon(0, QIcon(":/Resources/file.png"));      
  65.     direcotryE1->addChild(file6);  
  66.   
  67.     directoryE->addChild(file4);  
  68.     directoryE->addChild(file5);  
  69.     directoryE->addChild(direcotryE1);  
  70.   
  71.     QList<QTreeWidgetItem*> topLevelItemList;  
  72.     topLevelItemList << directoryC << directoryD << directoryE;  
  73.     topLevelDirectory->addChildren(topLevelItemList);  
  74.     addTopLevelItem(topLevelDirectory);  
  75. }  
创建的场景结构如下图所示:


在QTreeWidget中树结构的每一项都是一个QTreeWidgetItem,通过对它的设置可以修改树的显示效果,对于树的三态切换需要处理QTreeWidget中的一个信号:


当某一个节点被选中或者取消选中的时候需要处理以下情况:

1. 处理该节点的子节点(如果它有子节点),它的子节点的状态(Check或者Uncheck)和它一样 (如果它的子节点中有目录,那么还需要递归处理子节点的子节点)

2. 处理该节点的父节点,父节点会根据当前它子节点的状态来调整自身的状态(如果该父节点还有父节点,那么还需要递归处理父节点的父节点)

在QTreeWidget中的itemChanged事件会一直递归的调用,也就是说如果我们设置了子节点的状态(使用程序设置,或者手动点击),那么被设置的节点会继续调用itemChanged信号,根据这个特点,我们在编写代码的过程中不需要考虑递归的问题,只需要设置一个层级的处理即可。

具体实现如下:

设置子节点和父节点的状态

[cpp] view plain copy
  1. void WidgetTreeTEST::setChildCheckState(QTreeWidgetItem *item, Qt::CheckState cs)  
  2. {  
  3.     if(!item) return;  
  4.     for (int i=0;i<item->childCount();i++)  
  5.     {  
  6.         QTreeWidgetItem* child=item->child(i);  
  7.         if(child->checkState(0)!=cs)  
  8.         {  
  9.             child->setCheckState(0, cs);  
  10.         }  
  11.     }  
  12.     setParentCheckState(item->parent());  
  13. }  
  14.   
  15. void WidgetTreeTEST::setParentCheckState(QTreeWidgetItem *item)  
  16. {  
  17.     if(!item) return;  
  18.     int selectedCount=0;  
  19.     int childCount = item->childCount();  
  20.     for (int i=0;i<childCount;i++)  
  21.     {  
  22.         QTreeWidgetItem* child= item->child(i);  
  23.         if(child->checkState(0)==Qt::Checked)   
  24.         {  
  25.             selectedCount++;  
  26.         }  
  27.     }  
  28.   
  29.     if(selectedCount == 0) {  
  30.         item->setCheckState(0,Qt::Unchecked);  
  31.     } else if (selectedCount == childCount) {  
  32.         item->setCheckState(0,Qt::Checked);  
  33.     } else {  
  34.         item->setCheckState(0,Qt::PartiallyChecked);  
  35.     }  
  36. }  
在信号的响应槽函数中:
[cpp] view plain copy
  1. void WidgetTreeTEST::itemChangedSlot(QTreeWidgetItem* item, int column)  
  2. {  
  3.     if(Qt::PartiallyChecked!=item->checkState(0))  
  4.         setChildCheckState(item,item->checkState(0));  
  5.   
  6.     if(Qt::PartiallyChecked==item->checkState(0))  
  7.         if(!isTopItem(item))  
  8.             item->parent()->setCheckState(0,Qt::PartiallyChecked);      
  9. }  
  10.   
  11.   
  12. bool WidgetTreeTEST::isTopItem(QTreeWidgetItem* item)  
  13. {  
  14.     if(!item) return false;  
  15.     if(!item->parent()) return true;  
  16.     return false;  
  17. }  
槽函数中根据PartiallyChecked进行分类:因为只有组节点(包含子节点的节点)才可能有partiallyChecked的状态,当组节点被设置为partiallyChecked的时候它的父节点也会被设置为这种类型的状态,并且当组节点设置为PartiallyChecked的时候对子节点的状态没有任何影响。

最后结果如下图所示:



FROM:http://blog.csdn.net/csxiaoshui/article/details/50328097



0 0
原创粉丝点击