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 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复选框源码