qtableview添加qcheckbox

#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();
}

posted @ 2025-12-18 09:47  tdyx  阅读(2)  评论(0)    收藏  举报