QTableView复选框

QTableView复选框,支持未选中、部分选中、全选三种状态

参考博文(若有侵权,联系删除)

  1. https://blog.csdn.net/liang19890820/article/details/50718340
  2. https://blog.csdn.net/qq_44257811/article/details/120266599

效果图(未选中)

在这里插入图片描述

效果图(全选)

效果图(部分选中)

在这里插入图片描述

核心代码


/* tablemodel.h
 * QTableView 添加复选框
 * 参考:https://blog.csdn.net/liang19890820/article/details/50718340
*/

#ifndef TABLEMODEL_H
#define TABLEMODEL_H

#include <QObject>
#include <QAbstractTableModel>

class FileRecord
{
public:
    bool bChecked;
    QString strFilePath;
};

class TableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    TableModel(QObject *parent);
    ~TableModel();

public:
    QList<FileRecord> m_recordList;
    void updateData(QList<FileRecord> recordList);
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    QVariant data(const QModelIndex &index, int role) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    Qt::ItemFlags flags(const QModelIndex &index) const;
    void onStateChanged();//更新表头复选框状态
public slots:
    void onStateChanged(int state);//根据表头选中状态更新数据选中状态
signals:
     void stateChanged(int);//复选框被点击发送信号
};

#endif // TABLEMODEL_H

//tablemodel.cpp

#include "tablemodel.h"

#define CHECK_BOX_COLUMN 0
#define File_PATH_COLUMN 1

TableModel::TableModel(QObject *parent)
    : QAbstractTableModel(parent)
{

}

TableModel::~TableModel()
{

}

// 更新表格数据
void TableModel::updateData(QList<FileRecord> recordList)
{
    m_recordList = recordList;
    beginResetModel();
    endResetModel();
}

// 行数
int TableModel::rowCount(const QModelIndex &parent) const
{
    return m_recordList.count();
}

// 列数
int TableModel::columnCount(const QModelIndex &parent) const
{
    return 2;
}

// 设置表格项数据
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid())
        return false;

    int nColumn = index.column();
    FileRecord record = m_recordList.at(index.row());
    switch (role)
    {
    case Qt::DisplayRole:
    {
        if (nColumn == File_PATH_COLUMN)
        {
            record.strFilePath = value.toString();

            m_recordList.replace(index.row(), record);
            emit dataChanged(index, index);
            return true;
        }
    }
    case Qt::CheckStateRole:
    {
        if (nColumn == CHECK_BOX_COLUMN)
        {
            record.bChecked = (value.toInt() == Qt::Checked);

            m_recordList.replace(index.row(), record);
            emit dataChanged(index, index);
            emit onStateChanged();
            return true;
        }
    }
    default:
        return false;
    }
    return false;
}

// 表格项数据
QVariant TableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    int nRow = index.row();
    int nColumn = index.column();
    FileRecord record = m_recordList.at(nRow);

    switch (role)
    {
    case Qt::TextColorRole:
        return QColor(Qt::white);
    case Qt::TextAlignmentRole:
        return QVariant(Qt::AlignCenter | Qt::AlignVCenter);// 表格数据内容位置
    case Qt::DisplayRole:
    {
        if (nColumn == File_PATH_COLUMN)
            return record.strFilePath;
        return "";
    }
    case Qt::CheckStateRole:
    {
        if (nColumn == CHECK_BOX_COLUMN)
            return record.bChecked ? Qt::Checked : Qt::Unchecked;
    }
    default:
        return QVariant();
    }

    return QVariant();
}

// 表头数据
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    switch (role)
    {
    case Qt::TextAlignmentRole:
        return QVariant(Qt::AlignCenter | Qt::AlignVCenter);// 表头内容位置
    case Qt::DisplayRole:
    {
        if (orientation == Qt::Horizontal)
        {
            if (section == CHECK_BOX_COLUMN)
                return QStringLiteral("全选");

            if (section == File_PATH_COLUMN)
                return QStringLiteral("文件路径");
        }
    }
    default:
        return QVariant();
    }

    return QVariant();
}

// 表格可选中、可复选
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return QAbstractItemModel::flags(index);

    Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    if (index.column() == CHECK_BOX_COLUMN)
        flags |= Qt::ItemIsUserCheckable;

    return flags;
}

void TableModel::onStateChanged()
{
    int checked = 0, unchecked = 0;
    foreach (FileRecord fr, m_recordList) {
        if(fr.bChecked)
            checked++;
        else
            unchecked++;
    }
    if(checked == m_recordList.count())
        emit stateChanged(Qt::Checked);
    else if(unchecked == m_recordList.count())
        emit stateChanged(Qt::Unchecked);
    else
        emit stateChanged(Qt::PartiallyChecked);
}

void TableModel::onStateChanged(int state)
{
    state==Qt::Checked?Qt::Checked:Qt::Unchecked;//判断全选是选中还是未选中
    QModelIndex index;
    for (int i = 0; i < m_recordList.count(); ++i)
    {
        index = this->index(i, 0);
        setData(index,state, Qt::CheckStateRole);//使用自己重写的setData更新状态
    }
}


// tableheaderview.h

#ifndef TABLEHEADERVIEW_H
#define TABLEHEADERVIEW_H

#include <QObject>
#include <QHeaderView>

class TableHeaderView:public QHeaderView
{
    Q_OBJECT
public:
    TableHeaderView(Qt::Orientation orientation, QWidget *parent);
    ~TableHeaderView();

public:
    void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
    bool event(QEvent *e) Q_DECL_OVERRIDE;
    void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
public slots:
    void onStateChanged(int state);
signals:
    void stateChanged(int);

public:
    bool m_bPressed;
    bool m_bChecked;
    bool m_bTristate;
    bool m_bNoChange;
    bool m_bMoving;
};

#endif // TABLEHEADERVIEW_H

//tableheaderview.cpp

#include "tableheaderview.h"
#include <QCheckBox>

#define CHECK_BOX_COLUMN 0
#define File_PATH_COLUMN 1

TableHeaderView::TableHeaderView(Qt::Orientation orientation, QWidget *parent)
    : QHeaderView(orientation, parent),
      m_bPressed(false),
      m_bChecked(false),
      m_bTristate(false),
      m_bNoChange(false),
      m_bMoving(false)
{
    setSectionsClickable(true);
}

TableHeaderView::~TableHeaderView()
{

}

// 槽函数,用于更新复选框状态
void TableHeaderView::onStateChanged(int state)
{
    if (state == Qt::PartiallyChecked)
    {
        m_bTristate = true;
        m_bNoChange = true;
    }
    else
    {
        m_bNoChange = false;
    }
    m_bChecked = (state != Qt::Unchecked);
    update();
}


// 绘制复选框
void TableHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
    painter->save();
        QHeaderView::paintSection(painter, rect, logicalIndex);
        painter->restore();
        if (logicalIndex == CHECK_BOX_COLUMN)
        {
            QStyleOptionButton option;
            option.initFrom(this);

            if (m_bChecked)
                option.state |= QStyle::State_Sunken;

            if (m_bTristate && m_bNoChange)
                option.state |= QStyle::State_NoChange;
            else
                option.state |= m_bChecked ? QStyle::State_On : QStyle::State_Off;
            if (testAttribute(Qt::WA_Hover) && underMouse()) {
                if (m_bMoving)
                    option.state |= QStyle::State_MouseOver;
                else
                    option.state &= ~QStyle::State_MouseOver;
            }

            QCheckBox checkBox;
            option.rect = QRect(4,5,15,15);//绘制复选框的位置与大小
            style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, &checkBox);
        }
}

// 鼠标按下表头
void TableHeaderView::mousePressEvent(QMouseEvent *event)
{
    int nColumn = logicalIndexAt(event->pos());
    if ((event->buttons() & Qt::LeftButton) && (nColumn == CHECK_BOX_COLUMN))
    {
        m_bPressed = true;
    }
    else
    {
        QHeaderView::mousePressEvent(event);
    }
}

// 鼠标从表头释放,发送信号,更新model数据
void TableHeaderView::mouseReleaseEvent(QMouseEvent *event)
{
    if (m_bPressed)
    {
        if (m_bTristate && m_bNoChange)
        {
            m_bChecked = true;
            m_bNoChange = false;
        }
        else
        {
            m_bChecked = !m_bChecked;
        }

        update();

        Qt::CheckState state = m_bChecked ? Qt::Checked : Qt::Unchecked;
        emit stateChanged(state);
    }
    else
    {
        QHeaderView::mouseReleaseEvent(event);
    }

    m_bPressed = false;
}


// 鼠标滑过、离开,更新复选框状态
bool TableHeaderView::event(QEvent *event)
{
    updateSection(0);
    if (event->type() == QEvent::Enter || event->type() == QEvent::Leave)
    {
        QMouseEvent *pEvent = static_cast<QMouseEvent *>(event);
        int nColumn = logicalIndexAt(pEvent->x());
        if (nColumn == CHECK_BOX_COLUMN)
        {
            m_bMoving = (event->type() == QEvent::Enter);
            update();
            return true;
        }
    }
    return QHeaderView::event(event);
}
// 调用方法

#include <tablemodel.h>
#include <tableheaderview.h>

{
    TableHeaderView *pHeader = new TableHeaderView(Qt::Orientation::Horizontal, this);
    TableModel *pModel = new TableModel(this);

    // 设置表头
    ui->tableView->setHorizontalHeader(pHeader);
    // 关联表头复选框与第一列复选框
    connect(pHeader, SIGNAL(stateChanged(int)), pModel, SLOT(onStateChanged(int)));
    connect(pModel, SIGNAL(stateChanged(int)), pHeader, SLOT(onStateChanged(int)));

    // 设置单行选中、最后一列拉伸、表头不高亮、无边框等
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tableView->horizontalHeader()->setStretchLastSection(true);
    ui->tableView->horizontalHeader()->setHighlightSections(false);
    ui->tableView->verticalHeader()->setVisible(false);
    ui->tableView->setShowGrid(false);
    ui->tableView->setFrameShape(QFrame::NoFrame);
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->tableView->setModel(pModel);

    // 加载数据、更新界面
    QList<FileRecord> recordList;
    for (int i = 0; i < 5; ++i)
    {
        FileRecord record;
        record.bChecked = false;
        record.strFilePath = QString("E:/Qt/image_%1.png").arg(i + 1);
        recordList.append(record);
    }
    pModel->updateData(recordList);
}

源码下载:QTableView复选框源码

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值