目录
一、设计需求
设计一个带有复选框的树形控件。要求当选中顶层的树形节点时,子节点全部选中;当取消选择顶层树形节点时,子节点的选中状态全部被取消,而当选中子节点时,父亲节点显示部分选中状态。
二、实现代码
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTreeWidgetItem>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
/*
* 初始化函数
* */
void init();
/*
* 更新父亲节点
* */
void updateParentItem(QTreeWidgetItem* item);
private:
Ui::Widget *ui;
public slots:
void treeItemChanged(QTreeWidgetItem* item, int column);
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化
init();
//建立树形控件的节点改变信号与对应槽函数之间的连接
//当用户更改了树形控件中的一个项目的属性(例如文本、图标或勾选状态)时,itemChanged信号将发出
connect(ui->treeWidget,SIGNAL(itemChanged(QTreeWidgetItem*, int)),
this, SLOT(treeItemChanged(QTreeWidgetItem*, int)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::init()
{
//初始化树形控件
ui->treeWidget->clear();
//第一个分组
QTreeWidgetItem *group1 = new QTreeWidgetItem(ui->treeWidget);
//设置文本
group1->setText(0, "group1");
//允许用户设置项目的检查状态(是否选中)|启用项目,允许对其进行操作|允许项目被选中
group1->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt:: ItemIsSelectable);
//设置选中状态
group1->setCheckState(0, Qt::Unchecked);
//建立子节点
QTreeWidgetItem *subItem11 = new QTreeWidgetItem(group1);
subItem11->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt:: ItemIsSelectable);
subItem11->setText(0, "subItem11");
subItem11->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem12 = new QTreeWidgetItem(group1);
subItem12->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt:: ItemIsSelectable);
subItem12->setText(0, "subItem12");
subItem12->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem13 = new QTreeWidgetItem(group1);
subItem13->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem13->setText(0, "subItem13");
subItem13->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem14 = new QTreeWidgetItem(group1);
subItem14->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt:: ItemIsSelectable);
subItem14->setText(0, "subItem14");
subItem14->setCheckState(0, Qt::Unchecked);
//第二个分组
QTreeWidgetItem *group2 = new QTreeWidgetItem(ui->treeWidget);
group2->setText(0, "group2");
group2->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt:: ItemIsSelectable);
group2->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem21 = new QTreeWidgetItem(group2);
subItem21->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt:: ItemIsSelectable);
subItem21->setText(0, "subItem21");
subItem21->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem22 = new QTreeWidgetItem(group2);
subItem22->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt:: ItemIsSelectable);
subItem22->setText(0, "subItem22");
subItem22->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem23 = new QTreeWidgetItem(group2);
subItem23->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt:: ItemIsSelectable);
subItem23->setText(0, "subItem23");
subItem23->setCheckState(0, Qt::Unchecked);
}
void Widget::treeItemChanged(QTreeWidgetItem* item, int column)
{
QString itemText = item->text(0);
//选中时
if (Qt::Checked == item->checkState(0))
{
QTreeWidgetItem* parent = item->parent();
int count = item->childCount();
if (count > 0)
{
for (int i = 0; i < count; i++)
{
//子节点也选中
item->child(i)->setCheckState(0, Qt::Checked);
}
}
else
{
//是子节点
updateParentItem(item);
}
}
else if (Qt::Unchecked == item->checkState(0))
{
int count = item->childCount();
if (count > 0)
{
//设置子节点
for (int i = 0; i < count; i++)
{
item->child(i)->setCheckState(0, Qt::Unchecked);
}
}
else
{
updateParentItem(item);
}
}
}
void Widget::updateParentItem(QTreeWidgetItem* item)
{
//获取父亲节点
QTreeWidgetItem *parent = item->parent();
if (parent == NULL)
{
return;
}
//选中的子节点个数
int selectedCount = 0;
//获取子节点个数
int childCount = parent->childCount();
for (int i = 0; i < childCount; i++)
{
//获取子节点
QTreeWidgetItem *childItem = parent->child(i);
if (childItem->checkState(0) == Qt::Checked)
{
selectedCount++;
}
}
//通过子节点的选中个数,设置父亲节点的个数
if (selectedCount <= 0)
{
//选中状态
parent->setCheckState(0, Qt::Unchecked);
}
else if (selectedCount > 0 && selectedCount < childCount)
{
//部分选中状态
parent->setCheckState(0, Qt::PartiallyChecked);
}
else if (selectedCount == childCount)
{
//未选中状态
parent->setCheckState(0, Qt::Checked);
}
}
三、代码解析
本文代码较为清晰,参考注释即可。
四、总结
本文通过简单的代码逻辑实现了一个带有复选框的树形控件。代码整体比较简单、逻辑清晰,需要特殊考虑的就是Qt::ItemIsUserCheckable、Qt::ItemIsEnabled、Qt:: ItemIsSelectable这些flag的含义与作用。
五、扩展
在学习QTableWidget控件的时候,想必大家也多注意到了另外一个相似的控件QTableView。这两个控件有众多相似与不同之处,可以根据实际的需要,选择合适控件。
区别点 | QTableView | QTableWidget |
---|---|---|
继承关系 | QTableWidget继承自QTableView | |
使用数据模型setModel | 可以使用setModel设置模型 | setModel是私有函数,不能使用该函数设置数据模型 |
显示复选框setCheckState | 没有函数实现复选框 | QTableWidgetItem类中的setCheckState(Qt::Checked)可以设置复选框 |
与QSqlTableModel绑定 | QTableView能够与QSqlTableModel绑定 | QTableWidget不能与QSqlTableModel绑定 |