QTreeView 最常见最常用的控件,很神奇的事关于它的基础用法很少。一个无限递归都没找到,就几行代码, 而大多是傻瓜的3层树形,4层树形。
使用 Qt 仿 ant 的界面 : https://ant.design/components/tree-cn/
思路: 当勾选/取消勾选一个 item 时,如果有子项都要跟着改变, 如果有父项也要做出改变(子全选则父勾选,子全不选父取消勾选,夹在中间的就是Qt::PartiallyChecked) ; 仔细看我下面的烂代码
#include "AllTreeView.h"
#include <QDebug>
AllTreeView::AllTreeView(QWidget *parent) : QTreeView(parent)
{
//禁止编辑
this->setEditTriggers(QTreeView::NoEditTriggers);
//自定义右键菜单
this->setContextMenuPolicy(Qt::CustomContextMenu);
//最喜欢用的model, 不喜欢自己写model浪费时间
_model = new QStandardItemModel(this);
//隐藏头部
this->setHeaderHidden(true);
//水平头部描述(已经被隐藏了)
QStringList headList;
headList<<"item";
_model->setHorizontalHeaderLabels(headList);
_model->setColumnCount(headList.size());
for(int i=0; i<20; ++i){
auto item = new QStandardItem(QString("%1").arg(i));
item->setCheckable(true);
int cRowCount = 2;/*rand() %300;*/
for(int j=0; j<cRowCount; ++j){
auto cItem = new QStandardItem(QString("[%1:%2]").arg(i).arg(j));
cItem->setCheckable(true);
item->appendRow(cItem);
for(int n=0; n<4; ++n){
auto nItem = new QStandardItem(QString("[%1:%2]:[%3]").arg(i).arg(j).arg(n));
nItem->setCheckable(true);
cItem->appendRow(nItem);
for(int m=0; m<4; ++m){
auto mItem = new QStandardItem(QString("[%1:%2]:[%3][%4]").arg(i).arg(j).arg(n).arg(m));
mItem->setCheckable(true);
nItem->appendRow(mItem);
}
}
}
item->setText(QString("%1 (%2)").arg(item->text()).arg(item->rowCount()));
_model->appendRow(item);
}
connect ( _model ,SIGNAL(itemChanged(QStandardItem*)) , this ,SLOT(slotItemChanged(QStandardItem*)));
this->setModel(_model);
//全部展开
// this->expandAll();
}
AllTreeView::~AllTreeView()
{
if(_model) delete _model;
}
void AllTreeView::slotItemChanged(QStandardItem *item)
{
if (!item)
return ;
_model->blockSignals(true);
setChildItems(item,item->checkState() == Qt::Checked ? true : false);
setParentItems(item,item->checkState() == Qt::Checked ? true : false);
_model->blockSignals(false);
this->viewport()->update();
}
bool AllTreeView::setParentItems(QStandardItem * item,bool check)
{
if(!item || !item->parent()) return false;
QStandardItem *parentItem = item->parent();
int rowCount = parentItem->rowCount();
Qt::CheckState checkState = check ? Qt::Checked : Qt::Unchecked;
int checkedCount = 0;
int uncheckedCount = 0;
for(int i=0; i<rowCount; ++i){
QStandardItem *childItem = parentItem->child(i);
if(childItem->checkState() == Qt::Checked && check ){
++checkedCount;
}else if(childItem->checkState() == Qt::Unchecked && !check){
++uncheckedCount;
}else{
checkState = Qt::PartiallyChecked;
break;
}
}
if(checkedCount != rowCount && uncheckedCount !=rowCount){
checkState = Qt::PartiallyChecked;
}
parentItem->setCheckState(checkState);
setParentItems(parentItem,check);
return true;
}
bool AllTreeView::setChildItems(QStandardItem * item,bool check)
{
if(!item) return false;
item->setCheckState(check ? Qt::Checked : Qt::Unchecked);
int rowCount = item->rowCount();
for(int i=0; i<rowCount; ++i){
QStandardItem *childItem = item->child(i);
setChildItems(childItem,check);
}
return true;
}
//启用/禁用 item及子项
bool AllTreeView::setChildItemsEnabled(QStandardItem * item,bool enabled)
{
if(!item) return false;
item->setEnabled(enabled);
int rowCount = item->rowCount();
for(int i=0; i<rowCount; ++i){
QStandardItem *childItem = item->child(i);
setChildItemsEnabled(childItem,enabled);
}
return true;
}