TableModel.h
#pragma once
#include <QObject>
#include <QAbstractItemModel>
struct FlashIndexData{
FlashIndexData() :is_be_checked(false){
}
bool is_be_checked;
quint32 unix_time;
quint16 addr;
};
class TableModel : public QAbstractItemModel
{
Q_OBJECT
public:
TableModel(QObject *parent = nullptr);
~TableModel();
//需要实现的5个函数
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex & parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const;//返回每个数据项的index
virtual QModelIndex parent(const QModelIndex &index) const;//本需求树只有一层,parent返回NULL
//剩余根据需求
virtual bool setData(const QModelIndex & index, const QVariant & value,
int role = Qt::EditRole);//设置数据
virtual Qt::ItemFlags flags(const QModelIndex & index) const;//返回Item项的可选,可用户点击等标识
virtual QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;//返回相应role的表头数据
void setFlashData(QList<FlashIndexData> &flash_data);
void clear();
void getSelectedFlashData(QList<int>& listRow);
public slots:
void slot_stateChanged(Qt::CheckState state);
void deleteData();
private:
QList<FlashIndexData> m_flash_index; //flash 索引
void onStateChanged();
enum{
CHECK_BOX_COLUMN = 0,
UNIX_TIME_COLUMN,
FLASH_ADDR_COLUMN
};
signals:
void stateChanged(Qt::CheckState state);
};
TableModel.cpp
#include "TableModel.h"
#include <QDateTime>
#include <QColor>
#include <QSize>
#include <QFont>
#include <QBrush>
TableModel::TableModel(QObject *parent)
: QAbstractItemModel(parent)
{
m_flash_index.clear();
}
TableModel::~TableModel()
{
}
int TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_flash_index.count();
}
int TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 3;
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
int row = index.row();
int column = index.column();
FlashIndexData index_data = m_flash_index.at(row);
switch (role) {
case Qt::DisplayRole:
if (column == UNIX_TIME_COLUMN)
return index_data.unix_time;/*QDateTime::fromTime_t(index_data.unix_time).toString("yyyy-MM-dd hh:mm:ss");*/
else if (column == FLASH_ADDR_COLUMN)
return index_data.addr;
return "";
break;
case Qt::CheckStateRole:
if (column == CHECK_BOX_COLUMN)
return index_data.is_be_checked ? Qt::Checked : Qt::Unchecked;
break;
case Qt::TextAlignmentRole:
if (column == CHECK_BOX_COLUMN)
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
else
return Qt::AlignCenter;
break;
case Qt::TextColorRole:
return QColor(Qt::black);
break;
case Qt::SizeHintRole:
return QSize(100, 30);
break;
case Qt::FontRole:
return QFont("SimSun", 11);
break;
default:
break;
}
return QVariant();
}
//可编辑,只提供可选不可选的编辑,不提供对数据源的编辑
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
int column = index.column();
FlashIndexData index_data = m_flash_index.at(index.row());
switch (role) {
case Qt::UserRole: //根据表头的复选框选择
case Qt::CheckStateRole: //根据鼠标点击
if (column == CHECK_BOX_COLUMN)
{
index_data.is_be_checked = (((Qt::CheckState)value.toInt()) == Qt::Checked);
m_flash_index.replace(index.row(), index_data);
emit dataChanged(index, index);
if (role == Qt::CheckStateRole) //点击鼠标,更新表头复选框状态
onStateChanged();
return true;
}
break;
default:
return false;
break;
}
return false;
}
QModelIndex TableModel::index(int row, int column, const QModelIndex &parent) const
{
if (row < 0 || column < 0 || column >= columnCount(parent))
return QModelIndex();
return createIndex(row, column);
}
QModelIndex TableModel::parent(const QModelIndex &index) const
{
Q_UNUSED(index);
return QModelIndex();
}
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
switch (role) {
case Qt::DisplayRole:
if (section == CHECK_BOX_COLUMN)
{
return QString::fromLocal8Bit("全选");
}
else if (section == UNIX_TIME_COLUMN)
{
return QString::fromLocal8Bit("时间");
}
else if (section == FLASH_ADDR_COLUMN)
{
return QString::fromLocal8Bit("地址");
}
return "";
break;
case Qt::FontRole:
return QFont("SimSun", 12);
break;
case Qt::TextAlignmentRole:
return Qt::AlignCenter;
break;
case Qt::TextColorRole:
return QColor(Qt::black);
break;
case Qt::SizeHintRole:
return QSize(100, 40);
break;
case Qt::BackgroundRole:
return QBrush(Qt::black);
break;
default:
break;
}
return QVariant();
}
//可选
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
{
return QAbstractItemModel::flags(index);
}
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable
| Qt::ItemNeverHasChildren;
if (index.column() == CHECK_BOX_COLUMN)
flags |= Qt::ItemIsUserCheckable;
return flags;
}
void TableModel::setFlashData(QList<FlashIndexData> &flash_data)
{
m_flash_index = flash_data;
beginResetModel();
endResetModel();
emit stateChanged(Qt::Unchecked);
}
void TableModel::clear()
{
m_flash_index.clear();
beginResetModel();
endResetModel();
emit stateChanged(Qt::Unchecked);
}
void TableModel::getSelectedFlashData(QList<int>& listRow)
{
listRow.clear();
for (int i = 0; i < rowCount(); ++i)
{
if (m_flash_index.at(i).is_be_checked)
{
listRow.append(i);
//selected_list.insert(m_flash_index.at(i).unix_time, m_flash_index.at(i).addr);
}
}
}
void TableModel::deleteData()
{
for (int i = 0; i < rowCount(); ++i)
{
if (m_flash_index.at(i).is_be_checked)
{
m_flash_index.removeAt(i);
}
}
beginResetModel();
endResetModel();
emit stateChanged(Qt::Unchecked);
}
void TableModel::onStateChanged()
{
int select_total = 0;
for (int i = 0; i < rowCount(); ++i)
{
if (m_flash_index.at(i).is_be_checked)
++select_total;
}
if (select_total == 0)
{
emit stateChanged(Qt::Unchecked);
}
else if (select_total < rowCount())
{
emit stateChanged(Qt::PartiallyChecked);
}
else
{
emit stateChanged(Qt::Checked);
}
}
void TableModel::slot_stateChanged(Qt::CheckState state)
{
for (int i = 0; i < rowCount();i++)
{
setData(index(i, CHECK_BOX_COLUMN), state, Qt::UserRole);
}
}
HeaderView.h
#pragma once
#include <QObject>
#include <QHeaderView>
class HeaderView : public QHeaderView
{
Q_OBJECT
public:
HeaderView(QWidget *parent);
~HeaderView();
protected:
virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
signals:
void stateChanged(Qt::CheckState state);
private slots:
void slot_stateChanged(Qt::CheckState state);
private:
Qt::CheckState m_state;
bool m_is_pressed;
};
HeaderView.cpp
#include "HeaderView.h"
#include <QPainter>
#include <QMouseEvent>
//默认水平表头
HeaderView::HeaderView(QWidget *parent)
: QHeaderView(Qt::Horizontal, parent)
{
m_state = Qt::Unchecked;
m_is_pressed = false;
setSectionsClickable(true);
}
HeaderView::~HeaderView()
{
}
void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);//绘制其他Section
painter->restore();
//绘制背景色
painter->save();
painter->setBrush(QBrush(Qt::gray));
painter->setPen(Qt::NoPen);
painter->drawRect(rect);
//绘制Section的Text
painter->setFont(QFont("SimSun", 12));
painter->setPen(QColor("#000000"));
painter->drawText(rect, Qt::AlignCenter, model()->headerData(logicalIndex, Qt::Horizontal).toString());
painter->restore();
//为第一列绘制Checkbox
if (logicalIndex == 0)
{
QStyleOptionButton option;
option.initFrom(this);
if (m_state == Qt::Unchecked)
{
option.state |= QStyle::State_Off;
}
else if (m_state == Qt::PartiallyChecked)
{
option.state |= QStyle::State_NoChange;
}
else if (m_state == Qt::Checked)
{
option.state |= QStyle::State_On;
}
option.iconSize = QSize(20, 20);
option.rect = QRect(QPoint(rect.left() + 5, rect.top() + (rect.height() - 20) / 2), QPoint(rect.left() + 25, rect.bottom() - (rect.height() - 20) / 2));
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
}
}
void HeaderView::mousePressEvent(QMouseEvent *e)
{
int nColumn = logicalIndexAt(e->pos());
if ((e->buttons() & Qt::LeftButton) && (nColumn == 0))
{
m_is_pressed = true;
e->accept();
}
e->ignore();
}
void HeaderView::mouseReleaseEvent(QMouseEvent *e)
{
if (m_is_pressed)
{
if (m_state == Qt::Unchecked)
{
m_state = Qt::Checked;
}
else
{
m_state = Qt::Unchecked;
}
updateSection(0);
emit stateChanged(m_state); //状态改变
}
m_is_pressed = false;
e->accept();
}
//根据Item的复选框状态,表头复选框状态更新
void HeaderView::slot_stateChanged(Qt::CheckState state)
{
m_state = state;
updateSection(0);
}
MVCDemo.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_MVCDemo.h"
#include "TableModel.h"
#include "HeaderView.h"
class MVCDemo : public QMainWindow
{
Q_OBJECT
public:
MVCDemo(QWidget *parent = Q_NULLPTR);
public slots:
void slot_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void on_pushButton_clicked();
void on_pushButtonAdd_clicked();
void on_pushButtonDelete_clicked();
private:
Ui::MVCDemoClass ui;
TableModel* m_pMode = nullptr;
HeaderView* m_pHeaderView = nullptr;
QList<FlashIndexData> m_listData;
};
MVCDemo.cpp
#include "MVCDemo.h"
#include <QDateTime>
MVCDemo::MVCDemo(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
m_pMode = new TableModel(this);
m_pHeaderView = new HeaderView(this);
ui.tableView->setModel(m_pMode);
ui.tableView->setHorizontalHeader(m_pHeaderView);
for (int i = 0; i < 20;i++)
{
FlashIndexData stuData;
stuData.is_be_checked = false;
stuData.unix_time = 1111 + i;
stuData.addr = 22 + i;
m_listData.append(stuData);
}
m_pMode->setFlashData(m_listData);
ui.tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui.tableView->setColumnWidth(0, 150);
ui.tableView->setColumnWidth(1, 400);
ui.tableView->horizontalHeader()->setStretchLastSection(true);
ui.tableView->verticalHeader()->hide();
connect(m_pHeaderView, SIGNAL(stateChanged(Qt::CheckState)), m_pMode, SLOT(slot_stateChanged(Qt::CheckState)));
connect(m_pMode, SIGNAL(stateChanged(Qt::CheckState)), m_pHeaderView, SLOT(slot_stateChanged(Qt::CheckState)));
connect(ui.tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(slot_selectionChanged(QItemSelection, QItemSelection)));
}
void MVCDemo::slot_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
for (int i = 0; i < selected.indexes().count(); ++i)
{
m_pMode->setData(selected.indexes().at(i), Qt::Checked, Qt::UserRole + 1);
}
for (int i = 0; i < deselected.indexes().count(); ++i)
{
m_pMode->setData(deselected.indexes().at(i), Qt::Unchecked, Qt::UserRole + 1);
}
}
void MVCDemo::on_pushButton_clicked()
{
QList<int> listRow;
m_pMode->getSelectedFlashData(listRow);
for (auto r:listRow)
{
ui.tableView->setRowHidden(r, true);
}
}
void MVCDemo::on_pushButtonAdd_clicked()
{
FlashIndexData stuData;
stuData.is_be_checked = true;
stuData.unix_time = 4000;
stuData.addr = 8000;
m_listData.append(stuData);
m_pMode->setFlashData(m_listData);
}
void MVCDemo::on_pushButtonDelete_clicked()
{
//QList<int> listRow;
//m_pMode->getSelectedFlashData(listRow);
m_pMode->deleteData();
}
main.cpp
#include "MVCDemo.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MVCDemo w;
w.show();
return a.exec();
}