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.