QTreeWidget 中可以直接将item项设置成可勾选的CheckBox形态,进而可以实现多层级的复选框结构。每个item都有三种状态:勾选,未勾选,部分勾选。

然而,由于各层级item的勾选状态相互之间是联动的,每一项item的状态改变会同步导致其子项和父项的状态发生变化。这个更新状态的功能是需要我们自己实现的。

参考了一些文章但发现还是有bug,所以在他们的基础上进一步完善了一下,目前没发现bug。

直接上函数实现的源代码:

//创建树形控件
void Dialog::init()
    ui->treeWidget->clear();    //初始化树形控件
    ui->treeWidget->setHeaderHidden(true);  //隐藏表头
    //定义第一个树形组 爷爷项
    QTreeWidgetItem* group1 = new QTreeWidgetItem(ui->treeWidget);
    group1->setText(0, QStringLiteral("Tree"));    //树形控件显示的文本信息
    group1->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);   //设置树形控件子项的属性
    group1->setCheckState(0, Qt::Unchecked); //初始状态没有被选中
    //父亲项
    QTreeWidgetItem* subItem11 = new QTreeWidgetItem(group1);
    subItem11->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    subItem11->setText(0, "subItem11");  //设置子项显示的文本
    subItem11->setCheckState(0, Qt::Unchecked); //设置子选项的显示格式和状态
    QTreeWidgetItem* subItem12 = new QTreeWidgetItem(group1);
    subItem12->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    subItem12->setText(0, "subItem12");
    subItem12->setCheckState(0, Qt::Unchecked);
    QTreeWidgetItem* subItem13 = new QTreeWidgetItem(group1);
    subItem13->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    subItem13->setText(0, "subItem13");
    subItem13->setCheckState(0, Qt::Unchecked);
    //儿子项
    QTreeWidgetItem* group2 = new QTreeWidgetItem(subItem13);
    group2->setText(0, "group2");
    group2->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    group2->setCheckState(0, Qt::Unchecked);
    QTreeWidgetItem* group3 = new QTreeWidgetItem(subItem13);
    group3->setText(0, "group3");
    group3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    group3->setCheckState(0, Qt::Unchecked);
    //孙子项
    QTreeWidgetItem* subItem21 = new QTreeWidgetItem(group2);   //指定子项属于哪一个父项
    subItem21->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    subItem21->setText(0, "subItem21");
    subItem21->setCheckState(0, Qt::Unchecked);
    QTreeWidgetItem* subItem22 = new QTreeWidgetItem(group2);
    subItem22->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    subItem22->setText(0, "subItem22");
    subItem22->setCheckState(0, Qt::Unchecked);
    QTreeWidgetItem* subItem23 = new QTreeWidgetItem(group2);
    subItem23->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
    subItem23->setText(0, "subItem23");
    subItem23->setCheckState(0, Qt::Unchecked);
    ui->treeWidget->expandAll();  //展开树
//更新父亲项的状态
void Dialog::updateParentItem(QTreeWidgetItem* item)
    QTreeWidgetItem *parent = item->parent();
    if (parent == nullptr)
        return;
    int nSelectedCount = 0;
    int childCount = parent->childCount();
    for (int i = 0; i < childCount; i++) //判断有多少个子项被选中
        QTreeWidgetItem* childItem = parent->child(i);
        if (childItem->checkState(0) == Qt::Checked)
            nSelectedCount++;
    if (nSelectedCount <= 0){  //如果没有子项被选中,还要向下检查是否有某一级子孙项被勾选
        if (isThereCheckedDescendant(item)){
            parent->setCheckState(0, Qt::PartiallyChecked); //如果有则设置父项为部分勾选状态
        }else{
            parent->setCheckState(0, Qt::Unchecked); //如果没有则设置父项为未勾选状态
    }else if (nSelectedCount > 0 && nSelectedCount < childCount){    //如果有部分子项被选中,父项设置为部分选中状态,即用灰色显示
        parent->setCheckState(0, Qt::PartiallyChecked);
    }else if (nSelectedCount == childCount){    //如果子项全部被选中,父项则设置为选中状态
        parent->setCheckState(0, Qt::Checked);
    updateParentItem(parent);
//检查是否有某一级子孙项被勾选
bool Dialog::isThereCheckedDescendant(QTreeWidgetItem* item)
    int childCount = item->childCount(); //返回子项的个数
    if(childCount > 0){
        for(int i = 0; i < childCount; i++){
            if(item->child(i)->checkState(0) == Qt::Checked || item->child(i)->checkState(0) == Qt::PartiallyChecked){
                return true;
            }else{
                isThereCheckedDescendant(item->child(i));
        return false;
    }else{
        return false;
//更新儿子项的状态
void Dialog::updateChildItem(QTreeWidgetItem *item, int &n)
    int childCount = item->childCount(); //返回子项的个数
    if(childCount > 0){
        for(int i = 0; i < childCount; i++)
            if(n == 0){
                item->child(i)->setCheckState(0, Qt::Checked);
            }else if(n == 1){
                item->child(i)->setCheckState(0, Qt::Unchecked);
            if(item->child(i)->childCount() > 0){
                updateChildItem(item->child(i), n);
    }else{
        return;
//槽函数
void Dialog::onTreeItemChanged(QTreeWidgetItem* item)
    if (Qt::Checked == item->checkState(0)){
        int n = 0;
        updateChildItem(item, n);
    }else if (Qt::Unchecked == item->checkState(0)){
        int n = 1;
        updateChildItem(item, n);
    updateParentItem(item);

在构造函数中调用,connect时使用了itemClicked信号:

init();
connect(ui->treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(onTreeItemChanged(QTreeWidgetItem*)));
今天又次体会到jquery的强大了,做了个多级复选框的效果,代码总共就20+行就over了。 我又想用js来做一个看看,才写了几个方法就写不动了,兼容性要考虑很多,而且代码量直线上升。 主要分享下jquery的这个效果的实现。代码块分两块: 一是全选的效果,就是点击全选的复选框时它的子孙都相应被选中或者未选中。这人很好做,代码如下: 代码如下: evtEle.parent().next(“.checks”).find(“input:checkbox”).attr(“checked”, evtEle[0].checked);//evtEle是点击的复选框 二是当前复选框的父框根据当前框的兄弟 首先,查看了Qt文档,发现竟然没有提供这个功能,所以自己写了一个简单的例子。 QTreeWidget在添加节点时,其节点前面的复选框默认时不显示的,而要显示复选框,我们则需要通过QTreeWidgetItem的方法来设置。 void QTreeWidgetItem::setCheckState(int column 1.重载QTreeWidget这个类,在构造函数设置多选节点: //按 ctrl 或 shift 多选 this->setSelectionMode(QAbstractItemView::ExtendedSelection); //设置可拖拽性质 this->setDefaultDropAction(Qt::MoveAction); this-&g... 在树形结构中有时候需要在每项前添加复选框QTreeWidgetItem的复选框可以通过setCheckState(int column,Qt::CheckState state)方法调出。 勾选状态的改变,通过itemChanged(QTreeWidgetItem *item,int column)信号触发。 connect(ui->treeWidget,&QTreeWidget::itemChanged,this.