QTableView复选框,支持未选中、部分选中、全选三种状态
参考博文(若有侵权,联系删除)
- https://blog.csdn.net/liang19890820/article/details/50718340
- 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 1TableModel::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++;elseunchecked++;}if(checked == m_recordList.count())emit stateChanged(Qt::Checked);else if(unchecked == m_recordList.count())emit stateChanged(Qt::Unchecked);elseemit 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 1TableHeaderView::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;elseoption.state |= m_bChecked ? QStyle::State_On : QStyle::State_Off;if (testAttribute(Qt::WA_Hover) && underMouse()) {if (m_bMoving)option.state |= QStyle::State_MouseOver;elseoption.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复选框源码