QTreeWidget树的三态操作

https://blog.csdn.net/csxiaoshui/article/details/50328097

 

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

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

 

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

 

 
  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信号,根据这个特点,我们在编写代码的过程中不需要考虑递归的问题,只需要设置一个层级的处理即可。

具体实现如下:

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

 

 
  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.  
    }

在信号的响应槽函数中:

 

 
  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的时候对子节点的状态没有任何影响。

最后结果如下图所示:

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值