QTreeWidget树的三态操作
2015-12-16 17:37
501 查看
在工作中我们会经常使用到树状结构,例如Windows的资源管理器中的目录结构就用到了类似的控件。在Qt中可以使用QTreeWidget来实现类似的效果。
Qt中提供的QTreeWidget功能相对比较少,在实际中经常需要扩展它的功能,比如本文将要谈到的三态树的问题。
首先我们先创建一个QTreeWidget的对象,并添加一些节点:
void WidgetTreeTEST::createDirectoryStruct()
{
QTreeWidgetItem *topLevelDirectory = new QTreeWidgetItem();
topLevelDirectory->setText(0, "DIR");
topLevelDirectory->setCheckState(0, Qt::Checked);
topLevelDirectory->setIcon(0, QIcon(":/Resources/folder.png"));
//Direcoty C
QTreeWidgetItem *directoryC = new QTreeWidgetItem();
directoryC->setText(0, "LocalDrive C");
directoryC->setCheckState(0, Qt::Checked);
directoryC->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file1 = new QTreeWidgetItem();
file1->setText(0, "file1");
file1->setCheckState(0, Qt::Checked);
file1->setIcon(0, QIcon(":/Resources/file.png"));
QTreeWidgetItem *file2 = new QTreeWidgetItem();
file2->setText(0, "file2");
file2->setCheckState(0, Qt::Checked);
file2->setIcon(0, QIcon(":/Resources/file.png"));
directoryC->addChild(file1);
directoryC->addChild(file2);
//Directory D
QTreeWidgetItem *directoryD = new QTreeWidgetItem();
directoryD->setText(0, "LocalDrive D");
directoryD->setCheckState(0, Qt::Checked);
directoryD->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file3 = new QTreeWidgetItem();
file3->setText(0, "file3");
file3->setCheckState(0, Qt::Checked);
file3->setIcon(0, QIcon(":/Resources/file.png"));
directoryD->addChild(file3);
//Direcoty E
QTreeWidgetItem *directoryE = new QTreeWidgetItem();
directoryE->setText(0, "LocalDrive E");
directoryE->setCheckState(0, Qt::Checked);
directoryE->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file4 = new QTreeWidgetItem();
file4->setText(0, "file4");
file4->setCheckState(0, Qt::Checked);
file4->setIcon(0, QIcon(":/Resources/file.png"));
QTreeWidgetItem *file5 = new QTreeWidgetItem();
file5->setText(0, "file5");
file5->setCheckState(0, Qt::Checked);
file5->setIcon(0, QIcon(":/Resources/file.png"));
QTreeWidgetItem *direcotryE1 = new QTreeWidgetItem();
direcotryE1->setText(0, "file6");
direcotryE1->setCheckState(0, Qt::Checked);
direcotryE1->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file6 = new QTreeWidgetItem();
file6->setText(0, "file6");
file6->setCheckState(0, Qt::Checked);
file6->setIcon(0, QIcon(":/Resources/file.png"));
direcotryE1->addChild(file6);
directoryE->addChild(file4);
directoryE->addChild(file5);
directoryE->addChild(direcotryE1);
QList<QTreeWidgetItem*> topLevelItemList;
topLevelItemList << directoryC << directoryD << directoryE;
topLevelDirectory->addChildren(topLevelItemList);
addTopLevelItem(topLevelDirectory);
}创建的场景结构如下图所示:
![](https://img-blog.csdn.net/20151216161157876)
在QTreeWidget中树结构的每一项都是一个QTreeWidgetItem,通过对它的设置可以修改树的显示效果,对于树的三态切换需要处理QTreeWidget中的一个信号:
![](https://img-blog.csdn.net/20151216161508836)
当某一个节点被选中或者取消选中的时候需要处理以下情况:
1. 处理该节点的子节点(如果它有子节点),它的子节点的状态(Check或者Uncheck)和它一样 (如果它的子节点中有目录,那么还需要递归处理子节点的子节点)
2. 处理该节点的父节点,父节点会根据当前它子节点的状态来调整自身的状态(如果该父节点还有父节点,那么还需要递归处理父节点的父节点)
在QTreeWidget中的itemChanged事件会一直递归的调用,也就是说如果我们设置了子节点的状态(使用程序设置,或者手动点击),那么被设置的节点会继续调用itemChanged信号,根据这个特点,我们在编写代码的过程中不需要考虑递归的问题,只需要设置一个层级的处理即可。
具体实现如下:
设置子节点和父节点的状态
void WidgetTreeTEST::setChildCheckState(QTreeWidgetItem *item, Qt::CheckState cs)
{
if(!item) return;
for (int i=0;i<item->childCount();i++)
{
QTreeWidgetItem* child=item->child(i);
if(child->checkState(0)!=cs)
{
child->setCheckState(0, cs);
}
}
setParentCheckState(item->parent());
}
void WidgetTreeTEST::setParentCheckState(QTreeWidgetItem *item)
{
if(!item) return;
int selectedCount=0;
int childCount = item->childCount();
for (int i=0;i<childCount;i++)
{
QTreeWidgetItem* child= item->child(i);
if(child->checkState(0)==Qt::Checked)
{
selectedCount++;
}
}
if(selectedCount == 0) {
item->setCheckState(0,Qt::Unchecked);
} else if (selectedCount == childCount) {
item->setCheckState(0,Qt::Checked);
} else {
item->setCheckState(0,Qt::PartiallyChecked);
}
}在信号的响应槽函数中:
void WidgetTreeTEST::itemChangedSlot(QTreeWidgetItem* item, int column)
{
if(Qt::PartiallyChecked!=item->checkState(0))
setChildCheckState(item,item->checkState(0));
if(Qt::PartiallyChecked==item->checkState(0))
if(!isTopItem(item))
item->parent()->setCheckState(0,Qt::PartiallyChecked);
}
bool WidgetTreeTEST::isTopItem(QTreeWidgetItem* item)
{
if(!item) return false;
if(!item->parent()) return true;
return false;
}槽函数中根据PartiallyChecked进行分类:因为只有组节点(包含子节点的节点)才可能有partiallyChecked的状态,当组节点被设置为partiallyChecked的时候它的父节点也会被设置为这种类型的状态,并且当组节点设置为PartiallyChecked的时候对子节点的状态没有任何影响。
最后结果如下图所示:
Qt中提供的QTreeWidget功能相对比较少,在实际中经常需要扩展它的功能,比如本文将要谈到的三态树的问题。
首先我们先创建一个QTreeWidget的对象,并添加一些节点:
void WidgetTreeTEST::createDirectoryStruct()
{
QTreeWidgetItem *topLevelDirectory = new QTreeWidgetItem();
topLevelDirectory->setText(0, "DIR");
topLevelDirectory->setCheckState(0, Qt::Checked);
topLevelDirectory->setIcon(0, QIcon(":/Resources/folder.png"));
//Direcoty C
QTreeWidgetItem *directoryC = new QTreeWidgetItem();
directoryC->setText(0, "LocalDrive C");
directoryC->setCheckState(0, Qt::Checked);
directoryC->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file1 = new QTreeWidgetItem();
file1->setText(0, "file1");
file1->setCheckState(0, Qt::Checked);
file1->setIcon(0, QIcon(":/Resources/file.png"));
QTreeWidgetItem *file2 = new QTreeWidgetItem();
file2->setText(0, "file2");
file2->setCheckState(0, Qt::Checked);
file2->setIcon(0, QIcon(":/Resources/file.png"));
directoryC->addChild(file1);
directoryC->addChild(file2);
//Directory D
QTreeWidgetItem *directoryD = new QTreeWidgetItem();
directoryD->setText(0, "LocalDrive D");
directoryD->setCheckState(0, Qt::Checked);
directoryD->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file3 = new QTreeWidgetItem();
file3->setText(0, "file3");
file3->setCheckState(0, Qt::Checked);
file3->setIcon(0, QIcon(":/Resources/file.png"));
directoryD->addChild(file3);
//Direcoty E
QTreeWidgetItem *directoryE = new QTreeWidgetItem();
directoryE->setText(0, "LocalDrive E");
directoryE->setCheckState(0, Qt::Checked);
directoryE->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file4 = new QTreeWidgetItem();
file4->setText(0, "file4");
file4->setCheckState(0, Qt::Checked);
file4->setIcon(0, QIcon(":/Resources/file.png"));
QTreeWidgetItem *file5 = new QTreeWidgetItem();
file5->setText(0, "file5");
file5->setCheckState(0, Qt::Checked);
file5->setIcon(0, QIcon(":/Resources/file.png"));
QTreeWidgetItem *direcotryE1 = new QTreeWidgetItem();
direcotryE1->setText(0, "file6");
direcotryE1->setCheckState(0, Qt::Checked);
direcotryE1->setIcon(0, QIcon(":/Resources/folder.png"));
QTreeWidgetItem *file6 = new QTreeWidgetItem();
file6->setText(0, "file6");
file6->setCheckState(0, Qt::Checked);
file6->setIcon(0, QIcon(":/Resources/file.png"));
direcotryE1->addChild(file6);
directoryE->addChild(file4);
directoryE->addChild(file5);
directoryE->addChild(direcotryE1);
QList<QTreeWidgetItem*> topLevelItemList;
topLevelItemList << directoryC << directoryD << directoryE;
topLevelDirectory->addChildren(topLevelItemList);
addTopLevelItem(topLevelDirectory);
}创建的场景结构如下图所示:
在QTreeWidget中树结构的每一项都是一个QTreeWidgetItem,通过对它的设置可以修改树的显示效果,对于树的三态切换需要处理QTreeWidget中的一个信号:
当某一个节点被选中或者取消选中的时候需要处理以下情况:
1. 处理该节点的子节点(如果它有子节点),它的子节点的状态(Check或者Uncheck)和它一样 (如果它的子节点中有目录,那么还需要递归处理子节点的子节点)
2. 处理该节点的父节点,父节点会根据当前它子节点的状态来调整自身的状态(如果该父节点还有父节点,那么还需要递归处理父节点的父节点)
在QTreeWidget中的itemChanged事件会一直递归的调用,也就是说如果我们设置了子节点的状态(使用程序设置,或者手动点击),那么被设置的节点会继续调用itemChanged信号,根据这个特点,我们在编写代码的过程中不需要考虑递归的问题,只需要设置一个层级的处理即可。
具体实现如下:
设置子节点和父节点的状态
void WidgetTreeTEST::setChildCheckState(QTreeWidgetItem *item, Qt::CheckState cs)
{
if(!item) return;
for (int i=0;i<item->childCount();i++)
{
QTreeWidgetItem* child=item->child(i);
if(child->checkState(0)!=cs)
{
child->setCheckState(0, cs);
}
}
setParentCheckState(item->parent());
}
void WidgetTreeTEST::setParentCheckState(QTreeWidgetItem *item)
{
if(!item) return;
int selectedCount=0;
int childCount = item->childCount();
for (int i=0;i<childCount;i++)
{
QTreeWidgetItem* child= item->child(i);
if(child->checkState(0)==Qt::Checked)
{
selectedCount++;
}
}
if(selectedCount == 0) {
item->setCheckState(0,Qt::Unchecked);
} else if (selectedCount == childCount) {
item->setCheckState(0,Qt::Checked);
} else {
item->setCheckState(0,Qt::PartiallyChecked);
}
}在信号的响应槽函数中:
void WidgetTreeTEST::itemChangedSlot(QTreeWidgetItem* item, int column)
{
if(Qt::PartiallyChecked!=item->checkState(0))
setChildCheckState(item,item->checkState(0));
if(Qt::PartiallyChecked==item->checkState(0))
if(!isTopItem(item))
item->parent()->setCheckState(0,Qt::PartiallyChecked);
}
bool WidgetTreeTEST::isTopItem(QTreeWidgetItem* item)
{
if(!item) return false;
if(!item->parent()) return true;
return false;
}槽函数中根据PartiallyChecked进行分类:因为只有组节点(包含子节点的节点)才可能有partiallyChecked的状态,当组节点被设置为partiallyChecked的时候它的父节点也会被设置为这种类型的状态,并且当组节点设置为PartiallyChecked的时候对子节点的状态没有任何影响。
最后结果如下图所示:
相关文章推荐
- QT学习 第一章:基本对话框
- 使用Shiboken为C++和Qt库创建Python绑定
- Qt定时器和随机数详解
- Qt实现图片移动实例(图文教程)
- Qt for Android开发实例教程
- QModelIndex/Role/Model介紹<二>
- 基于PyQt5的快速开发框架QFramer
- OSX下安装PyQt
- ok6410开发板移植DirectFB手记
- 【笔记】给Qt内嵌一个Chrome吧
- 【算法】最短路径之A*搜索
- qt入门必备
- 在 Qt4 中使用 C++11
- Hello Word ~ v0.2.2 背单词软件发布 -- By WHYPRO
- ubuntu下opencv和qt的安装配置
- linux下opengl的安装(with qt)
- qt 学习小节
- QT的命名风格
- QT 中的sleep
- QT 串口的监控