#include <QApplication>
#include <QHeaderView>
#include <QTableView>
#include <QStandardItemModel>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QCheckBox>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>
#include <QHBoxLayout>
#include <QWidget>
// 自定义 HeaderView 类,支持复选框
class CheckBoxHeaderView : public QHeaderView
{
Q_OBJECT
public:
explicit CheckBoxHeaderView(Qt::Orientation orientation, QWidget* parent = nullptr)
: QHeaderView(orientation, parent)
, m_isChecked(false)
, m_isPartialChecked(false)
{
// 设置 HeaderView 可响应鼠标点击
setSectionsClickable(true);
}
// 设置复选框状态
void setCheckState(Qt::CheckState state)
{
bool stateChanged = false;
if (state == Qt::Checked) {
if (!m_isChecked) {
m_isChecked = true;
m_isPartialChecked = false;
stateChanged = true;
}
} else if (state == Qt::Unchecked) {
if (m_isChecked || m_isPartialChecked) {
m_isChecked = false;
m_isPartialChecked = false;
stateChanged = true;
}
} else if (state == Qt::PartiallyChecked) {
if (!m_isPartialChecked || m_isChecked) {
m_isChecked = false;
m_isPartialChecked = true;
stateChanged = true;
}
}
if (stateChanged) {
updateSection(0); // 只更新第一列
}
}
// 获取当前复选框状态
Qt::CheckState getCheckState() const
{
if (m_isChecked) {
return Qt::Checked;
} else if (m_isPartialChecked) {
return Qt::PartiallyChecked;
} else {
return Qt::Unchecked;
}
}
signals:
void checkStateChanged(Qt::CheckState state);
protected:
// 绘制复选框
void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const override
{
QHeaderView::paintSection(painter, rect, logicalIndex);
if (logicalIndex == 0) { // 只在第一列显示复选框
QStyleOptionButton option;
// 计算复选框位置,使其在表头单元格中居中
int checkboxSize = 20;
int x = rect.x() + 5;
int y = rect.y() + (rect.height() - checkboxSize) / 2;
option.rect = QRect(x, y, checkboxSize, checkboxSize);
if (m_isChecked) {
option.state = QStyle::State_Enabled | QStyle::State_On;
} else if (m_isPartialChecked) {
option.state = QStyle::State_Enabled | QStyle::State_NoChange;
} else {
option.state = QStyle::State_Enabled | QStyle::State_Off;
}
// 绘制复选框
style()->drawControl(QStyle::CE_CheckBox, &option, painter);
}
}
// 处理鼠标点击事件
void mousePressEvent(QMouseEvent* event) override
{
int logicalIndex = logicalIndexAt(event->pos());
if (logicalIndex == 0) { // 只在第一列的 Header 区域点击有效
// 获取该列的矩形区域
int sectionX = sectionViewportPosition(logicalIndex);
int sectionWidth = sectionSize(logicalIndex);
int headerHeight = height();
// 计算复选框的位置
int checkboxSize = 20;
int x = sectionX + 5;
int y = (headerHeight - checkboxSize) / 2;
QRect checkBoxRect = QRect(x, y, checkboxSize, checkboxSize);
if (checkBoxRect.contains(event->pos())) {
// 切换复选框状态
if (m_isChecked || m_isPartialChecked) {
m_isChecked = false;
m_isPartialChecked = false;
} else {
m_isChecked = true;
m_isPartialChecked = false;
}
// 发送状态变化信号
emit checkStateChanged(getCheckState());
// 更新视图
updateSection(0);
return;
}
}
QHeaderView::mousePressEvent(event);
}
private:
bool m_isChecked;
bool m_isPartialChecked;
};
// 主窗口类
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr)
: QWidget(parent)
{
setupUI();
setupModel();
setupConnections();
}
private:
void setupUI()
{
QHBoxLayout* layout = new QHBoxLayout(this);
// 创建 TableView
tableView = new QTableView(this);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
// 创建模型
model = new QStandardItemModel(this);
tableView->setModel(model);
// 设置自定义的 HeaderView
headerView = new CheckBoxHeaderView(Qt::Horizontal, tableView);
tableView->setHorizontalHeader(headerView);
layout->addWidget(tableView);
setLayout(layout);
// 设置窗口属性
setWindowTitle("QTableView Header Checkbox Demo");
resize(600, 400);
}
void setupModel()
{
// 设置表头
model->setHorizontalHeaderLabels(QStringList() << "复选框" << "姓名" << "年龄" << "城市");
// 添加示例数据
for (int row = 0; row < 5; ++row) {
// 第一列添加带复选框的 Item
QStandardItem* checkItem = new QStandardItem();
checkItem->setCheckable(true);
checkItem->setCheckState(Qt::Unchecked);
checkItem->setTextAlignment(Qt::AlignCenter);
QList<QStandardItem*> rowItems;
rowItems << checkItem;
rowItems << new QStandardItem(QString("用户%1").arg(row + 1));
rowItems << new QStandardItem(QString::number(20 + row * 2));
rowItems << new QStandardItem(QString("城市%1").arg(row + 1));
model->appendRow(rowItems);
}
}
void setupConnections()
{
// 连接 Header 复选框状态变化信号
connect(headerView, &CheckBoxHeaderView::checkStateChanged,
this, &MainWindow::onHeaderCheckStateChanged);
// 监听模型数据变化
connect(model, &QStandardItemModel::dataChanged,
this, &MainWindow::onDataChanged);
}
private slots:
// Header 复选框状态变化
void onHeaderCheckStateChanged(Qt::CheckState state)
{
// 批量设置所有行的复选框状态
for (int row = 0; row < model->rowCount(); ++row) {
QStandardItem* item = model->item(row, 0);
if (item) {
item->setCheckState(state);
}
}
}
// 数据变化
void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
{
Q_UNUSED(bottomRight)
// 只处理第一列(复选框列)的变化
if (topLeft.column() == 0) {
qDebug() << "123";
// 检查是否是复选框状态变化
qDebug() << roles;
//if (roles.contains(Qt::CheckStateRole)) {
updateHeaderCheckState();
// }
}
}
// 更新 Header 复选框状态
void updateHeaderCheckState()
{
qDebug() << "456";
int checkedCount = 0;
int totalRows = model->rowCount();
// 统计选中状态
for (int row = 0; row < totalRows; ++row) {
QStandardItem* item = model->item(row, 0);
if (item && item->checkState() == Qt::Checked) {
checkedCount++;
}
}
// 更新 Header 复选框状态
if (checkedCount == 0) {
headerView->setCheckState(Qt::Unchecked);
} else if (checkedCount == totalRows) {
headerView->setCheckState(Qt::Checked);
} else {
headerView->setCheckState(Qt::PartiallyChecked);
}
// 强制更新视图
headerView->update();
}
private:
QTableView* tableView;
QStandardItemModel* model;
CheckBoxHeaderView* headerView; // 保存指针以便访问
};
#include "main.moc" // 包含 MOC 生成的代码
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}