C++ Qt开发:TreeWidget 树形选择组件

打印 上一主题 下一主题

主题 866|帖子 866|积分 2600

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍TreeWidget树形选择组件的常用方法及灵活运用。
QTreeWidget 是 Qt 中的树形控件组件,用于显示树形结构的数据。它继承自 QTreeView 和 QTreeWidget,提供了一个方便的方式来展示和编辑包含层次结构数据的项目。
以下是 QTreeWidget 类的一些常用方法,说明和概述:
方法描述addTopLevelItem(QTreeWidgetItem *item)向树中添加一个顶级项目。addTopLevelItems(const QList &items)向树中添加多个顶级项目。clear()清除树中的所有项目。currentItem()返回当前选择的项目。currentIndex()返回当前选择的项目的模型索引。editItem(QTreeWidgetItem *item, int column)进入编辑模式以编辑给定项目的指定列。headerItem()返回树的标题项目,该项目可用于设置标题标签。invisibleRootItem()返回树的不可见根项目。itemAbove(QTreeWidgetItem *item)返回给定项目的上面一个项目。itemBelow(QTreeWidgetItem *item)返回给定项目的下面一个项目。setCurrentItem(QTreeWidgetItem *item)设置当前选择的项目。topLevelItem(int index)返回树中给定索引的顶级项目。topLevelItemCount()返回树的顶级项目的数量。insertTopLevelItem(int index, QTreeWidgetItem *item)在给定索引处插入一个顶级项目。insertTopLevelItems(int index, const QList &items)在给定索引处插入多个顶级项目。takeTopLevelItem(int index)从树中移除给定索引处的顶级项目,并返回该项目的指针。scrollToItem(QTreeWidgetItem *item, QAbstractItemView::ScrollHint hint = EnsureVisible)滚动树以确保给定项目可见。sortItems(int column, Qt::SortOrder order = Qt::AscendingOrder)对树中的项目进行排序。findItems(const QString &text, Qt::MatchFlags flags, int column = 0)查找树中包含指定文本的项目。这只是 QTreeWidget 类的一小部分方法。你可以查阅官方文档以获取完整的方法列表,以及这些方法的详细说明。
首先我们来绘制一下UI界面,由于该节点同时具备编辑功能所以实现起来要稍微复杂一些,我们分别在最左侧放置一个TreeWidget组件,在中间放置不同的PushButton组件,最后是一个plainTextEdit组件用来接收反馈,如下图所示;

1.1 初始化组件

如下代码是在 Qt 中使用 QTreeWidget 初始化一个树形结构,其中包含了朋友、同学和陌生人等不同分类的节点。
以下是概述:

  • 初始化 QTreeWidget: 设置 QTreeWidget 的一些基本属性,包括列数、标题的隐藏等。
  • 创建父节点 "朋友": 使用 QTreeWidgetItem 创建一个朋友节点,并设置图标、选择状态等属性。然后添加两个子节点 "老张" 和 "老王",分别设置图标和选择状态。
  • 创建父节点 "同学": 类似地,创建一个同学节点,并添加两个子节点 "张三" 和 "李四",设置相应的图标和选择状态。
  • 创建 "陌生人" 节点: 使用 QTreeWidgetItem 直接创建一个陌生人节点,并设置文本和图标。
  • 将节点添加到 QTreeWidget 中: 使用 addTopLevelItem 将 "同学" 和 "陌生人" 节点添加到 QTreeWidget 的顶级。
  • 展开所有节点: 使用 expandAll 展开所有节点,使其在初始化时可见。
  • 设置 QTreeWidget 的大小: 使用 resize 设置 QTreeWidget 的大小。
这段代码的主要功能是创建一个包含不同分类和子节点的树形结构,每个节点可以有不同的图标、文本和选择状态。在展示的树形结构中,朋友和同学节点有子节点,而陌生人节点没有子节点。这个示例展示了 QTreeWidget 用于创建层次结构的基本用法。
  1. MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
  2. {
  3.     ui->setupUi(this);
  4.     ui->treeWidget->clear();
  5.     // ----------------------------------------------
  6.     // 初始化TreeWidget组件
  7.     // ----------------------------------------------
  8.     // 设置QTreeWidget的列数
  9.     ui->treeWidget->setColumnCount(1);
  10.     // 设置QTreeWidget标题隐藏
  11.     ui->treeWidget->setHeaderHidden(true);
  12.     // ----------------------------------------------
  13.     // 创建QTreeWidget的朋友节点 此时的父节点是TreeWidget
  14.     // ----------------------------------------------
  15.     QTreeWidgetItem *Friend = new QTreeWidgetItem(ui->treeWidget,QStringList(QString("朋友")));
  16.     Friend->setIcon(0,QIcon(":/image/4.ico"));
  17.     Friend->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable
  18.                      | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
  19.     Friend->setCheckState(0,Qt::Checked);
  20.     // 给Friend添加一个子节点frd
  21.     QTreeWidgetItem *frd = new QTreeWidgetItem(Friend);
  22.     frd->setText(0,"老张");
  23.     frd->setIcon(0,QIcon(tr(":/image/1.ico")));
  24.     frd->setCheckState(0,Qt::Checked);
  25.     // 继续给Friend添加一个子节点frs
  26.     QTreeWidgetItem *frs = new QTreeWidgetItem(Friend);
  27.     frs->setText(0,"老王");
  28.     frs->setIcon(0,QIcon(tr(":/image/1.ico")));
  29.     frs->setCheckState(0,Qt::Unchecked);
  30.     // ----------------------------------------------
  31.     // 继续创建名叫同学节点 父节点同样是TreeWidget
  32.     // ----------------------------------------------
  33.     QTreeWidgetItem * ClassMate = new QTreeWidgetItem(ui->treeWidget,QStringList(QString("同学")));
  34.     ClassMate->setIcon(0,QIcon(":/image/5.ico"));
  35.     ClassMate->setCheckState(0,Qt::Checked);
  36.     // Fly是ClassMate的子节点
  37.     QTreeWidgetItem *Fly = new QTreeWidgetItem(QStringList(QString("张三")));
  38.     Fly->setIcon(0,QIcon(tr(":/image/2.ico")));
  39.     // 创建子节点的另一种方法
  40.     ClassMate->addChild(Fly);
  41.     Fly->setCheckState(0,Qt::Checked);
  42.     // 继续创建子节点Fls
  43.     QTreeWidgetItem *Fls = new QTreeWidgetItem(QStringList(QString("李四")));
  44.     Fls->setIcon(0,QIcon(tr(":/image/2.ico")));
  45.     ClassMate->addChild(Fls);
  46.     Fls->setCheckState(0,Qt::Checked);       // 设置为选中
  47.     // ----------------------------------------------
  48.     // 创建陌生人节点
  49.     // ----------------------------------------------
  50.     QTreeWidgetItem  *Strange = new QTreeWidgetItem(true);
  51.     Strange->setText(0,"陌生人");
  52.     Strange->setIcon(0,QIcon(":/image/6.ico"));
  53.     ui->treeWidget->addTopLevelItem(ClassMate);
  54.     ui->treeWidget->addTopLevelItem(Strange);
  55.     // 展开QTreeWidget的所有节点
  56.     ui->treeWidget->expandAll();
  57.     ui->treeWidget->resize(271,401);
  58. }
复制代码
代码运行后可动态对左侧组件进行初始化,并增加应有的父节点与子节点,如下图;

1.2 添加根节点

如下槽函数,其核心功能是在 QTreeWidget 中添加一个新的顶级父节点,并在 QPlainTextEdit 中添加一行文本记录。
以下是概述:

  • 获取节点文本: 使用 QString NodeText = "新的父节点"; 设置新父节点的文本。
  • 创建新的 QTreeWidgetItem: 使用 QTreeWidgetItem 的构造函数创建一个新的顶级父节点,并设置其文本和图标。
  • 添加节点到 QTreeWidget 中: 使用 ui->treeWidget->addTopLevelItem(item); 将新的顶级父节点添加到 QTreeWidget 中。
  • 记录操作到 QPlainTextEdit 中: 使用 ui->plainTextEdit->appendPlainText("添加新的父节点"); 将一行文本记录添加到 QPlainTextEdit 中,用于记录操作。
这段代码的作用是在点击按钮时,在 QTreeWidget 中添加一个新的顶级父节点,并在 QPlainTextEdit 中记录这一操作。这样可以用于在界面上动态添加树节点,并记录相关的操作信息。
  1. void MainWindow::on_pushButton_add_clicked()
  2. {
  3.     QString NodeText = "新的父节点";
  4.     QTreeWidgetItem  *item = new QTreeWidgetItem(true);
  5.     item->setText(0,NodeText);
  6.     item->setIcon(0,QIcon(":/image/7.ico"));
  7.     ui->treeWidget->addTopLevelItem(item);
  8.     ui->plainTextEdit->appendPlainText("添加新的父节点");
  9. }
复制代码
运行后通过点击添加根节点按钮,每次则可以生成一个根,如下图;

1.3 添加子节点

如下槽函数,其核心功能是在 QTreeWidget 中添加新的子节点,并在 QPlainTextEdit 中添加一行文本记录。
以下是概述:

  • 获取当前选择的节点: 使用 QTreeWidgetItem * item= ui->treeWidget->currentItem(); 获取当前在 QTreeWidget 中选择的节点。
  • 判断是否有选择的节点: 使用 if(item!=NULL) 条件判断,如果存在选择的节点,则调用 AddTreeNode 函数添加子节点;否则,调用 AddTreeRoot 函数添加新的根节点。
  • 添加子节点或新的根节点:

    • 如果存在选择的节点,调用 AddTreeNode(item,"新子节点","新子节点"); 添加一个新的子节点,其文本和图标分别为 "新子节点"。
    • 如果没有选择的节点,调用 AddTreeRoot("新子节点","新子节点"); 添加一个新的根节点,其文本和图标同样为 "新子节点"。

  • 记录操作到 QPlainTextEdit 中: 使用 ui->plainTextEdit->appendPlainText("添加新的子节点"); 将一行文本记录添加到 QPlainTextEdit 中,用于记录操作。
这段代码的作用是在点击按钮时,根据用户当前选择的节点状态,在 QTreeWidget 中添加新的子节点或新的根节点,并记录这一操作到 QPlainTextEdit 中。
  1. QTreeWidgetItem * MainWindow::AddTreeRoot(QString name,QString desc)
  2. {
  3.     QTreeWidgetItem * item=new QTreeWidgetItem(QStringList()<<name<<desc);
  4.     ui->treeWidget->addTopLevelItem(item);
  5.     return item;
  6. }
  7. QTreeWidgetItem * MainWindow::AddTreeNode(QTreeWidgetItem *parent,QString name,QString desc)
  8. {
  9.     QTreeWidgetItem * item=new QTreeWidgetItem(QStringList()<<name<<desc);
  10.     parent->addChild(item);
  11.     return item;
  12. }
  13. void MainWindow::on_pushButton_addsubnode_clicked()
  14. {
  15.     QTreeWidgetItem * item= ui->treeWidget->currentItem();
  16.         if(item!=NULL)
  17.             AddTreeNode(item,"新子节点","新子节点");
  18.         else
  19.             AddTreeRoot("新子节点","新子节点");
  20.         ui->plainTextEdit->appendPlainText("添加新的子节点");
  21. }
复制代码
修改节点的执行效果如下图,当点击修改选中节点后则将自动替换节点名和图标信息。

1.5 删除选中节点

如下槽函数,其核心功能是删除 QTreeWidget 中当前选中节点,并在 QPlainTextEdit 中添加一行文本记录。
以下是概述:

  • 获取当前选中的节点: 使用 QTreeWidgetItem *currentItem = ui->treeWidget->currentItem(); 获取当前在 QTreeWidget 中选择的节点。
  • 判断是否存在选择的节点: 使用 if(currentItem == NULL) 条件判断,如果没有选择的节点,则直接返回。
  • 判断是否为顶级父节点: 使用 if(currentItem->parent() == NULL) 条件判断,如果当前节点没有父节点(即为顶级父节点),则使用 ui->treeWidget->takeTopLevelItem 删除该节点。
  • 如果有父节点,使用父节点的 takeChild 删除子节点: 使用 delete currentItem->parent()->takeChild(ui->treeWidget->currentIndex().row()); 删除当前节点。这种情况下,要使用父节点的 takeChild 方法,因为直接删除会导致父节点无法正确管理子节点。
  • 记录操作到 QPlainTextEdit 中: 使用 ui->plainTextEdit->appendPlainText("删除一个节点"); 将一行文本记录添加到 QPlainTextEdit 中,用于记录操作。
这段代码的作用是在点击按钮时,删除 QTreeWidget 中当前选中的节点,并记录这一删除操作到 QPlainTextEdit 中。
  1. void MainWindow::on_pushButton_modifynode_clicked()
  2. {
  3.     // 得到当前节点
  4.     QTreeWidgetItem *currentItem = ui->treeWidget->currentItem();
  5.     if(currentItem == NULL)
  6.         return;
  7.     // 修改选中项
  8.     for(int x=0;x<currentItem->columnCount();x++)
  9.     {
  10.         currentItem->setText(x,tr("Modify") + QString::number(x));
  11.         currentItem->setIcon(x,QIcon(":/image/1.ico"));
  12.     }
  13.     ui->plainTextEdit->appendPlainText("修改节点名");
  14. }
复制代码
删除节点有两种情况,如果只有父节点那么可以直接删除,如果有子节点则那就要一并删除,如下图;

1.6 枚举全部节点

如下槽函数,其核心功能是遍历 QTreeWidget 中的所有节点,并输出每个节点的文本。
以下是概述:

  • 获取全部的根节点数量: 使用 int size = ui->treeWidget->topLevelItemCount(); 获取顶级父节点的数量。
  • 遍历所有根节点: 使用 for 循环遍历每一个根节点,通过 ui->treeWidget->topLevelItem(x) 获取当前的根节点。
  • 输出所有根节点: 使用 child->text(0).toStdString().data() 输出当前根节点的文本信息,并将其输出到标准输出流。
  • 遍历根节点下的子节点: 使用内层 for 循环遍历当前根节点下的所有子节点,通过 child->child(y) 获取子节点。
  • 输出子节点: 使用 grandson->text(0).toStdString().data() 输出当前子节点的文本信息,并将其输出到标准输出流。
  • 记录操作到 QPlainTextEdit 中: 使用 ui->plainTextEdit->appendPlainText("枚举所有节点"); 将一行文本记录添加到 QPlainTextEdit 中,用于记录操作。
这段代码的作用是在点击按钮时,遍历 QTreeWidget 中的所有节点,输出每个节点的文本信息,并将信息记录到 QPlainTextEdit 中。
  1. void MainWindow::on_pushButton_delnode_clicked()
  2. {
  3.     QTreeWidgetItem *currentItem = ui->treeWidget->currentItem();
  4.     if(currentItem == NULL)
  5.         return;
  6.     // 如果没有父节点则直接删除
  7.     if(currentItem->parent() == NULL)
  8.     {
  9.         delete ui->treeWidget->takeTopLevelItem(ui->treeWidget->currentIndex().row());
  10.         std::cout << ui->treeWidget->currentIndex().row() << std::endl;
  11.     }
  12.     else
  13.     {
  14.         // 如果有父节点就要用父节点的takeChild删除节点
  15.         delete currentItem->parent()->takeChild(ui->treeWidget->currentIndex().row());
  16.     }
  17.     ui->plainTextEdit->appendPlainText("删除一个节点");
  18. }
复制代码
枚举所有节点会将父节点与子节点一并输出,如下图;

1.7 枚举选中节点

如下槽函数,其核心功能是遍历 QTreeWidget 中的所有节点,并输出每个选中节点的文本信息。
以下是概述:

  • 获取全部的根节点数量: 使用 int size = ui->treeWidget->topLevelItemCount(); 获取顶级父节点的数量。
  • 遍历所有根节点: 使用 for 循环遍历每一个根节点,通过 ui->treeWidget->topLevelItem(x) 获取当前的根节点。
  • 遍历根节点下的子节点: 使用内层 for 循环遍历当前根节点下的所有子节点,通过 child->child(y) 获取子节点。
  • 判断是否选中: 使用 if(Qt::Checked == grandson->checkState(0)) 判断当前子节点是否被选中。
  • 输出选中节点信息: 如果子节点被选中,输出当前根节点与子节点的文本信息,并将信息输出到标准输出流。
  • 记录操作到 QPlainTextEdit 中: 使用 ui->plainTextEdit->appendPlainText("枚举所有选中节点"); 将一行文本记录添加到 QPlainTextEdit 中,用于记录操作。
这段代码的作用是在点击按钮时,遍历 QTreeWidget 中的所有节点,输出每个被选中节点的文本信息,并将信息记录到 QPlainTextEdit 中。
  1. void MainWindow::on_pushButton_enumnode_clicked()
  2. {
  3.     // 获取到全部的根节点数量
  4.     int size = ui->treeWidget->topLevelItemCount();
  5.     QTreeWidgetItem *child;
  6.     for(int x=0;x<size;x++)
  7.     {
  8.         // 输出所有父节点
  9.         child = ui->treeWidget->topLevelItem(x);
  10.         std::cout << "all root = "<< child->text(0).toStdString().data() << std::endl;
  11.         // 得到所有子节点计数
  12.         int childCount = child->childCount();
  13.         // std::cout << "all child count = " << childCount << std::endl;
  14.         // 输出根节点下面的子节点
  15.         for(int y=0;y<childCount;++y)
  16.         {
  17.             QTreeWidgetItem *grandson = child->child(y);
  18.             std::cout << "--> sub child = "<< grandson->text(0).toStdString().data() << std::endl;
  19.             ui->plainTextEdit->appendPlainText(grandson->text(0).toStdString().data());
  20.         }
  21.     }
  22.     ui->plainTextEdit->appendPlainText("枚举所有节点");
  23. }
复制代码
枚举所有选中的节点,此处需要打上对勾才会生效,如下图;

1.8 获取节点父节点

如下槽函数,其核心功能是获取当前选中节点的父节点(如果存在),输出父节点的序号和名字,并将信息记录到 QPlainTextEdit 中。
以下是概述:
<ol>获取当前选中节点的父节点: 使用 QTreeWidgetItem *currentItem = ui->treeWidget->currentItem()->parent(); 获取当前选中节点的父节点。
获取父节点在顶级节点中的序号: 使用 int root_count = ui->treeWidget->indexOfTopLevelItem(currentItem); 获取父节点在顶级节点中的序号。
判断是否存在父节点: 使用 if(root_count != -1) 条件判断,如果存在父节点,执行下面的操作;否则,直接返回。
获取指定序号对应的父节点: 使用 child = ui->treeWidget->topLevelItem(root_count); 获取指定序号对应的父节点。
输出父节点的序号和名字: 使用 std::cout parent();    int root_count = ui->treeWidget->indexOfTopLevelItem(currentItem);    std::cout text(0).toStdString().data());    }    ui->plainTextEdit->appendPlainText("获取父节点ID");}[/code]当用户选中一个子节点时,可通过该槽函数获取其父节点的ID编号,如下图;

1.9 绑定右键菜单

在开发中我们经常会把它当作一个升级版的ListView组件使用,因为ListView每次只能显示一列数据集,而使用TableWidget组件显示多列显得不够美观,此时使用TreeWidget组件显示单层结构是最理想的方式,同时该组件同样支持增加右键菜单,在真正的开发中尤为常用。
首先我们在MainWindow主窗体中只保留一个treeWidget组件,接着直接来到MainWindow构造函数上,在该函数中我们通过动态创建一个menuBar()并将其隐藏起来,接着将菜单属性与treeWidget中的事件相互绑定,最后初始化填充一些测试数据,其代码如下;
  1. void MainWindow::on_pushButton_enumselectnode_clicked()
  2. {
  3.     // 获取到全部的根节点数量
  4.     int size = ui->treeWidget->topLevelItemCount();
  5.     QTreeWidgetItem *child;
  6.     for(int x=0;x<size;x++)
  7.     {
  8.         // 输出所有父节点
  9.         child = ui->treeWidget->topLevelItem(x);
  10.         // 得到所有子节点计数
  11.         int childCount = child->childCount();
  12.         // 输出根节点下面的子节点
  13.         for(int y=0;y<childCount;++y)
  14.         {
  15.             QTreeWidgetItem *grandson = child->child(y);
  16.             // 判断是否选中,如果选中输出父节点与子节点
  17.             if(Qt::Checked == grandson->checkState(0))
  18.             {
  19.                 std::cout << "root -> " << child->text(0).toStdString().data()
  20.                           << "--> sub child = "<< grandson->text(0).toStdString().data() << std::endl;
  21.                 ui->plainTextEdit->appendPlainText(child->text(0).toStdString().data());
  22.                 ui->plainTextEdit->appendPlainText(grandson->text(0).toStdString().data());
  23.             }
  24.         }
  25.     }
  26.     ui->plainTextEdit->appendPlainText("枚举所有选中节点");
  27. }
复制代码
此时,当treeWidget中的右键被点击后则将触发on_treeWidget_customContextMenuRequested槽函数,此函数中动态的新建一个菜单,并在鼠标点击位置将其显示输出,代码如下;
  1. void MainWindow::on_pushButton_getnode_clicked()
  2. {
  3.     // 取所有的父节点
  4.     QTreeWidgetItem *currentItem = ui->treeWidget->currentItem()->parent();
  5.     int root_count = ui->treeWidget->indexOfTopLevelItem(currentItem);
  6.     std::cout << "root Count = " <<  root_count << std::endl;
  7.     if(root_count != -1)
  8.     {
  9.         // 指定序号对应的父节点名字
  10.         QTreeWidgetItem *child;
  11.         child = ui->treeWidget->topLevelItem(root_count);
  12.         std::cout << "root name= "<< child->text(0).toStdString().data() << std::endl;
  13.         ui->plainTextEdit->appendPlainText(child->text(0).toStdString().data());
  14.     }
  15.     ui->plainTextEdit->appendPlainText("获取父节点ID");
  16. }
复制代码
运行后读者可看到如下图所示的输出效果;

完整案例下载

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表