QTableView
在通常情况下,一个应用需要和一批数据(比如数组、列表)进行交互,然后以表格的形式输出这些信息,
这时就要用到QTableView类了。在QtableView中可以使用自定义的数据模型来进行数据单元添加、单元格删除和设置表格标题等操作,
一般常见的就是QStandardItemModel模型,通过setModel来绑定数据源。
使用时需要包含#include 和#include
常用方法:
标题操作:
setHorizontalHeaderLabels(…)//水平标题设置
setVerticalHeaderLabels(…)//竖直标题设置
headerData()//获取当前列的文字内容
插入数据:
setItem()//指定设置的行和列,设置QStandardItem
setData //insertRow创建modeIndex,指定QModelIndex,设置数据
appendRow()//可以先将一行item的对象添加一个list中然后一次性插入
删除数据:
clear() //可以一次将表格内容和表格标题都删掉
removeRows() //参数1:起始行 参数2:行数 只是想将表格内容清空
removeColumn() //删除某一列数据
属性设置:
horizontalHeader()->setSectionResizeMode(…);
//QHeaderView::Fixed:不可手动调整宽度;
//QHeaderView::ResizeToContents:表格宽度随内容自动扩展;
//QHeaderView::Stretch:表格宽度自动根据UI进行计算,不可手动调整宽度
setShowGrid(false);//隐藏网格线
setGridStyle(Qt::DotLine);//线的样式
可以自定义数据模型来显示数据:
qtableview的自定义model对比QTableWidget,可以优化很多内存,特别是在数据量庞大的时候。
QStandardItemModel可以满足一般的Table的结构,也可以满足树状的结构,
但是自带缺点是使用起来不够灵活,对数据的操作受限于自带的接口,所以需要自定义model。
QStringListModel:存储简单的字符串列表
QStandardItemModel:可以用于树结构的存储,提供了层次数据
QFileSystemModel:本地系统的文件和目录信息
QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel:存取数据库数据
一般情况下满足需求了,不过有时候需要一些定制功能,或者是大量数据下对性能和开销比较注重,觉得自带的model无用功能太多效率比较低,这时候自定义model就比较适合了。
使用自定义model 同时出于这两方面需要,既为了性能也为了特殊功能。 (***)
展示大量级数据方法:1)多线程处理 2)动态局部加载
重写一个model继承QAbstractTableModel,QAbstractTableModel继承自 QAbstractItemModel,用于为 QTableView 提供数据接口,必须实现以下五个接口:
int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
QTableWidget
是QTableView的子类,使用的是标准的数据模型,其单元格数据是通过QTableWidgetItem对象来实现。
常用方法:
标题操作:
setHorizontalHeaderLabels(…)//水平标题设置
setVerticalHeaderLabels(…)//竖直标题设置
插入数据:
setItem //通过insertRow插入行 setItem指定行列设置QTableWidgetItem
删除数据:
clear() //可以一次将表格内容和表格标题都删掉
removeRow //遍历所有行,进行删除
属性设置:
setEditTriggers //设置编辑状态
setColumnWidth //设置列宽
setSectionResizeMode //设置伸缩状态
setSelectionMode //设置连续选择状态
代码
widgettable.h:
#ifndef WIDGETTABLE_H
#define WIDGETTABLE_H
#include <QWidget>
#include "tableviewheader.h"
#include <QStandardItemModel>
#include <QMutex>
#include "tablemodel.h"
namespace Ui {
class WidgetTable;
}
typedef struct TEST_TABLE_DATA_T
{
int nNo;
QString sName;
int nSex;
int nAge;
QString sID;
}TEST_TABLE_DATA;
typedef QHash<QString, TEST_TABLE_DATA> QHashTestTable;
typedef QHash<QString, TEST_TABLE_DATA>::iterator QHashTestTableIterator;
class WidgetTable : public QWidget
{
Q_OBJECT
enum COLUMN_NUM_E
{
COLUMN_CHECKBOX = 0,
COLUMN_NO,
COLUMN_NAME,
COLUMN_SEX,
COLUMN_AGE,
COLUMN_ID
};
public:
explicit WidgetTable(QWidget *parent = nullptr);
~WidgetTable();
void initTableView();
void initTableWidget();
void initCusModelTableView();
//测试用
void initTestHash();
void setColumnWidth(); // 更新列宽
void resizeEvent(QResizeEvent *); //拉伸
public slots:
void on_tableViewClick(QModelIndex nIndex);
void on_tableViewDbClick(QModelIndex nIndex);
void on_tableViewMenu(const QPoint &pos);
void on_tableViewSort(int nColumn);
void on_tableViewSelectAllCheckBoxClick(Qt::CheckState state);
protected:
void changeEvent(QEvent* event);
private slots:
void on_Btn_Update_clicked();
void on_Btn_Get_clicked();
void on_Btn_Clear_clicked();
void on_Btn_Update2_clicked();
void on_Btn_SetCurrentIndex_clicked();
void on_Btn_SetColor_clicked();
private:
void retranslateUi();
private:
Ui::WidgetTable *ui;
private:
//tableview
QStandardItemModel *m_pTableModel;
TableViewHeader *m_pTableHeader;
QMutex m_lock;
int m_nCheckedCount;//选中个数
QMenu *m_actMenu;
QAction *m_actDevRefresh;
QHashTestTable m_testTableHash;
TableModel *m_pModelEx;
};
#endif // WIDGETTABLE_H
widgettable.cpp
#include "widgettable.h"
#include "ui_widgettable.h"
#include <QLinkedList>
#include <QStringList>
#include "commondef.h"
#include <QMenu>
WidgetTable::WidgetTable(QWidget *parent) :
QWidget(parent),
ui(new Ui::WidgetTable)
{
ui->setupUi(this);
initTableView();
initTestHash();
initCusModelTableView();
initTableWidget();
}
WidgetTable::~WidgetTable()
{
SAFE_FREE(m_actDevRefresh);
SAFE_FREE(m_actMenu);
delete ui;
}
/*************************
* QTableView-初始化
* ***********************/
void WidgetTable::initTableView()
{
//自定义表头操作
m_pTableHeader = new TableViewHeader(Qt::Horizontal, this);//表头
m_pTableHeader->setStretchLastSection(true);//表头最后一列填充
ui->tableView->setHorizontalHeader(m_pTableHeader);//设置表头
//创建model(目前使用的是标准数据模型,可以自定义数据模型),绑定model
m_pTableModel = new QStandardItemModel(this);
ui->tableView->setModel(m_pTableModel);//设置model
//右键菜单创建
m_actMenu = new QMenu(ui->tableView);
m_actMenu->setStyleSheet("border:1px solid #4d738b;");
m_actDevRefresh = new QAction("Refresh", ui->tableView);
connect(m_actDevRefresh, &QAction::triggered, [this]()
{
MY_DEBUG << "Refresh";
});
m_actMenu->addAction(m_actDevRefresh);
//创建表头信息
QStringList headerList;
headerList << "" << tr("No.") << tr("Name") << tr("Sex") << tr("Age") << tr("ID");
m_pTableModel->setHorizontalHeaderLabels(headerList);
//单击
connect(ui->tableView, &QTableView::clicked,
this, &WidgetTable::on_tableViewClick);
//双击
connect(ui->tableView, &QTableView::doubleClicked,
this, &WidgetTable::on_tableViewDbClick);
//右键菜单设置
ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tableView, &QTableView::customContextMenuRequested,
this, &WidgetTable::on_tableViewMenu);
//标题头排序
connect(ui->tableView->horizontalHeader(), &QHeaderView::sectionClicked,
this, &WidgetTable::on_tableViewSort);
//全选
connect(m_pTableHeader, &TableViewHeader::stateChanged,
this, &WidgetTable::on_tableViewSelectAllCheckBoxClick);
//设置列宽
setColumnWidth();
}
/*************************
* QTableView-设置列宽
* ***********************/
void WidgetTable::setColumnWidth()
{
ui->tableView->setColumnWidth(COLUMN_NO, 100);
ui->tableView->setColumnWidth(COLUMN_NAME, 200);
ui->tableView->setColumnWidth(COLUMN_SEX, 100);
ui->tableView->setColumnWidth(COLUMN_AGE, 100);
//ui->tableView->setColumnWidth(COLUMN_ID, qRound(0.3*width));
}
void WidgetTable::resizeEvent(QResizeEvent *)
{
setColumnWidth();
}
/*************************
* QTableView-单击事件
* ***********************/
void WidgetTable::on_tableViewClick(QModelIndex nIndex)
{
QMutexLocker guard(&m_lock);
int nRow = nIndex.row();
int nCol = nIndex.column();
Qt::CheckState oldState = m_pTableModel->item(nRow, COLUMN_CHECKBOX)->checkState();
Qt::CheckState newState;
if(oldState == Qt::Unchecked)
{
newState = Qt::Checked;
m_nCheckedCount++;
}
else
{
newState = Qt::Unchecked;
m_nCheckedCount--;
}
m_pTableModel->item(nRow, COLUMN_CHECKBOX)->setCheckState(newState);
if(newState == Qt::Unchecked || m_nCheckedCount == m_pTableModel->rowCount())
{
m_pTableHeader->onStateChanged(newState);//改变标题栏的全选状态
}
}
/*************************
* QTableView-双击事件
* ***********************/
void WidgetTable::on_tableViewDbClick(QModelIndex nIndex)
{
QMutexLocker guard(&m_lock);
int row = nIndex.row();
MY_DEBUG << "Db Click row:" << row;
}
/*************************
* QTableView-右键菜单显示
* ***********************/
void WidgetTable::on_tableViewMenu(const QPoint &pos)
{
//m_actMenu->exec(mapToGlobal(pos));//绝对位置
m_actMenu->exec(cursor().pos());//相对位置
}
/*************************
* QTableView-排序
* ***********************/
void WidgetTable::on_tableViewSort(int nColumn)
{
QMutexLocker guard(&m_lock);
//点击表头实现排序
ui->tableView->horizontalHeader()->setSortIndicatorShown(true);
ui->tableView->sortByColumn(nColumn);
}
/*************************
* QTableView-响应表头全选操作
* ***********************/
void WidgetTable::on_tableViewSelectAllCheckBoxClick(Qt::CheckState state)
{
QMutexLocker guard(&m_lock);
int nRowCount = m_pTableModel->rowCount();//当前行数
for(int i = 0; i < nRowCount; i++)
{
m_pTableModel->item(i, COLUMN_CHECKBOX)->setCheckState(state);
}
}
/*************************
* QTableView-更新数据
* ***********************/
void WidgetTable::on_Btn_Update_clicked()
{
QMutexLocker guard(&m_lock);
//清空数据
if(m_pTableModel->rowCount() > 0)
{
m_pTableModel->removeRows(0, m_pTableModel->rowCount());
}
QHashTestTableIterator i = m_testTableHash.begin();
int row = 0;
for(; i != m_testTableHash.end(); ++i)
{
TEST_TABLE_DATA data = i.value();
//可以通过insertRow和setData增加数据
m_pTableModel->insertRow(row, QModelIndex());
m_pTableModel->setData(m_pTableModel->index(row, COLUMN_CHECKBOX), "");
m_pTableModel->setData(m_pTableModel->index(row, COLUMN_NO), row+1);
m_pTableModel->setData(m_pTableModel->index(row, COLUMN_NAME), data.sName);
m_pTableModel->setData(m_pTableModel->index(row, COLUMN_SEX), data.nSex);
m_pTableModel->setData(m_pTableModel->index(row, COLUMN_AGE), data.nAge);
m_pTableModel->setData(m_pTableModel->index(row, COLUMN_ID), data.sID);
//也可以通过setItem增加数据
//m_pTableModel->setItem(row, COLUMN_CHECKBOX, new QStandardItem(""));
// 设置全部列居中显示
for(int j = COLUMN_NO; j <= COLUMN_ID; j++)
{
m_pTableModel->item(row, j)->setTextAlignment(Qt::AlignCenter);
}
row++;
}
}
/*************************
* QTableWidget-初始化
* ***********************/
void WidgetTable::initTableWidget()
{
//设置禁止修改
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
//双击或获取焦点后单击,进入编辑状态
//ui->tableWidget->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
//设置列数和列宽
ui->tableWidget->setColumnCount(5);
ui->tableWidget->setColumnWidth(0, 100);
ui->tableWidget->setColumnWidth(1, 100);
ui->tableWidget->setColumnWidth(2, 200);
ui->tableWidget->setColumnWidth(3, 100);
//设置列伸缩
ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);
//设置最后一栏自适应长度
//ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
// 表格宽度随内容自动扩展
//ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
//设置连续选择状态
ui->tableWidget->setSelectionMode(QAbstractItemView::ContiguousSelection);
//设置为可以选中多个目标,按ctrl键
//ui->tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
//开启交替行背景色,在设置style为交替颜色时必须开启
//ui->tableWidget->setAlternatingRowColors(true);
//不显示边框
ui->tableWidget->setGridStyle(Qt::NoPen);
connect(ui->tableWidget,SIGNAL(itemChanged(QTableWidgetItem*)),
ui->tableWidget,SLOT(resizeRowsToContents()) );//自动换行
}
/*************************
* QTableWidget-插入数据
* ***********************/
void WidgetTable::on_Btn_Get_clicked()
{
//设置表头
QStringList headList;
headList<<"NO."<<"Name"<<"Sex"<<"Age"<<"ID";
ui->tableWidget->setColumnCount(headList.size());
ui->tableWidget->setHorizontalHeaderLabels(headList); //设置水平表头为list
//各列数据
QStringList nameList;
nameList << "AAA" << "BBB" << "CCC";
QStringList sexList;
sexList << "man" << "woman" << "woman";
QStringList ageList;
ageList << "32" << "30" << "3";
QStringList idList;
idList << "A11111" << "B11111" << "C111111";
int num = ageList.size();
for(int i = 0; i < num; i ++)
{
int Col = 0;
//通过insertRow 和 setItem 插入数据
int RowCont = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(RowCont);
ui->tableWidget->setItem(RowCont, Col++, new QTableWidgetItem(QString::number(RowCont+1)));
ui->tableWidget->setItem(RowCont, Col++, new QTableWidgetItem(nameList.at(i)));
ui->tableWidget->setItem(RowCont, Col++, new QTableWidgetItem(sexList.at(i)));
ui->tableWidget->setItem(RowCont, Col++, new QTableWidgetItem(ageList.at(i)));
ui->tableWidget->setItem(RowCont, Col++, new QTableWidgetItem(idList.at(i)));
//ui->tableWidget->setCellWidget()//可以放入组件例如QComboBox
//设置各列数据居中显示
for(int j = 0; j < Col; j++)
{
ui->tableWidget->item(RowCont, j)->setTextAlignment(Qt::AlignCenter);
}
}
ui->tableWidget->scrollToBottom();
}
/*************************
* QTableWidget-清除数据
* ***********************/
void WidgetTable::on_Btn_Clear_clicked()
{
QMutex mutex;
QMutexLocker locker(&mutex);
int RowCont = ui->tableWidget->rowCount();
for(int i = RowCont; i >= 0; i--)
{
ui->tableWidget->removeRow(i);
}
}
/*************************
* QTableView-自定义model
* ***********************/
void WidgetTable::initCusModelTableView()
{
m_pModelEx = new TableModel();
ui->tableView_2->setModel(m_pModelEx);
/*
int nID = 0;
//保存和恢复model选中项,因为在resetModel后会失效
connect(m_pModelEx, &TableModel::modelAboutToBeReset, this, [=]{
QModelIndex selectedIndex = ui->tableView_2->currentIndex();
selectedIndex.data(Qt::UserRole).toInt();
},Qt::DirectConnection);
connect(m_pModelEx, &TableModel::modelReset, this, [=]{
//不用担心无效的index,接口内部会处理
//ui->tableView_2->setCurrentIndex(selectedIndex);
},Qt::DirectConnection);
*/
}
///
/*************************
* 数据初始化
* ***********************/
void WidgetTable::initTestHash()
{
TEST_TABLE_DATA data[5];
data[0] = {1, "AAA", 1, 31, "A1111111"};
data[1] = {2, "BBB", 0, 33, "B1111111"};
data[2] = {3, "CCC", 1, 29, "C1111111"};
data[3] = {4, "DDD", 0, 26, "D1111111"};
data[4] = {5, "EEE", 1, 32, "E1111111"};
for(int i = 0; i < 5; i++)
{
m_testTableHash.insert(data[i].sID, data[i]);
}
}
void WidgetTable::on_Btn_Update2_clicked()
{
QVariantMap data_map;
//标题
data_map["headerlabel"] = QStringList() << "ID" << tr("jiange") << tr("device") << tr("device type") << tr("factory name") << tr("voltage type") << tr("wf identifier") << tr("wf tuichu");
//数据
for(int i = 0; i < 10000; i++)
{
QVariantMap map;
map["ID"] = i + 1;
map["jiange"] = i + 2;
map["device"] = i + 3;
map["device type"] = i + 4;
map["factory name"] = i + 5;
map["voltage type"] = i + 6;
map["wf identifier"] = i + 7;
map["wf tuichu"] = i + 8;
data_map[QString::number(i) + "id"] = map;
}
m_pModelEx->SetData(data_map);
}
void WidgetTable::on_Btn_SetCurrentIndex_clicked()
{
MY_DEBUG << "on_Btn_SetCurrentIndex_clicked";
QVector< QPair<int, int> > indexs;
for(int i = 0; i < 2000; i++)
{
indexs.append(qMakePair<int ,int>(i, 2));
}
m_pModelEx->setHignlightIndex(indexs);
}
void WidgetTable::on_Btn_SetColor_clicked()
{
MY_DEBUG << "on_Btn_SetColor_clicked";
m_pModelEx->setItemText(1, 1, "test");
m_pModelEx->SetItemData(1, 1, "aoligei");
}
void WidgetTable::changeEvent(QEvent *event)
{
switch(event->type())
{
case QEvent::LanguageChange:
retranslateUi();
break;
default:
QWidget::changeEvent(event);
}
}
void WidgetTable::retranslateUi()
{
ui->label->setText(tr("Use Table View:"));
ui->label_2->setText(tr("Use Table Widget:"));
ui->label_3->setText(tr("Use Table View(Custom Model)"));
ui->Btn_Get->setText(tr("Get"));
ui->Btn_Clear->setText(tr("Clear"));
ui->Btn_Update->setText(tr("Update"));
ui->Btn_Update2->setText(tr("Update"));
}
tableviewheader.h
#ifndef TABLEVIEWHEADER_H
#define TABLEVIEWHEADER_H
#include <QHeaderView>
#include <QEvent>
#include <QPainter>
#include <QCheckBox>
#include <QMouseEvent>
#include <qnamespace.h>
#include <QDebug>
#define CHECK_BOX_COLUMN 0
class TableViewHeader :public QHeaderView
{
Q_OBJECT
public:
TableViewHeader(Qt::Orientation orientation,QWidget *parent = nullptr);
public:
void onStateChanged(int state);
bool isChecked();
signals:
void stateChanged(Qt::CheckState);
protected:
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
bool event(QEvent *event);
private:
bool m_bPressed;
bool m_bChecked;
bool m_bTristate;
bool m_bNoChange;
bool m_bMoving;
};
#endif // TABLEVIEWHEADER_H
tableviewheader.cpp
#include "tableviewheader.h"
TableViewHeader::TableViewHeader(Qt::Orientation orientation, QWidget *parent)
: QHeaderView(orientation, parent),
m_bPressed(false),
m_bChecked(false),
m_bTristate(false),
m_bNoChange(false),
m_bMoving(false)
{
setHighlightSections(false);
setMouseTracking(true);
// 响应鼠标
setSectionsClickable(true);
}
// 槽函数,用于更新复选框状态
void TableViewHeader::onStateChanged(int state)
{
if (state == Qt::PartiallyChecked)
{
m_bTristate = true;
m_bNoChange = true;
}
else
{
m_bNoChange = false;
}
m_bChecked = (state != Qt::Unchecked);
update();
}
bool TableViewHeader::isChecked()
{
return m_bChecked;
}
// 绘制复选框
void TableViewHeader::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.iconSize = QSize(14, 14);
option.rect = QRect(3,7,14,14);
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, &checkBox);
}
}
// 鼠标按下表头
void TableViewHeader::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 TableViewHeader::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 TableViewHeader::event(QEvent *event)
{
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);
}
tablemodel.h
#ifndef TableModel_H
#define TableModel_H
#include<QAbstractTableModel>
#include <QObject>
#include<QVector>
#include<QMap>
#include<QStringList>
//自定义QTableView model
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit TableModel(QObject *parent=nullptr);
void SetData(const QVariantMap &map);
void setHignlightIndex(QVector< QPair<int, int> > vec_index);
//itemFlag相关的设置是针对项的,与View中的拖放、编辑、选择等属性的设置是独立的,一个项能否进行拖放、编辑、选择等
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
//行列数
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
QString itemText(int row, int column) const;
QString itemText(const QModelIndex &index) const;
void setItemText(const QModelIndex &index, const QString &str);
void setItemText(int row, int column, const QString &str);
QVariant ItemData(const QModelIndex &index) const;
QVariant ItemData(int row, int column) const;
void SetItemData(const QModelIndex &index, const QVariant &data);
void SetItemData(int row, int column, const QVariant &data);
void clear();
signals:
void itemChanged(const QModelIndex &index, const QVariant &value);
private:
QStringList m_pHeaders;
QStringList m_hor_hedlbls; // 橫向标题
QStringList m_vec_hedlbls; // 纵向标题
QVariantMap m_table_map, m_data_map;
QVector<QPair<int, int> > m_highlight_indexs; // 背景高亮的indexs
};
#endif // TableModel_H
tablemodel.cpp
#include "tablemodel.h"
TableModel::TableModel(QObject *parent):QAbstractTableModel (parent)
{
}
void TableModel::SetData(const QVariantMap &map)
{
//重置model数据之前调用beginResetModel,此时会触发modelAboutToBeReset信号
beginResetModel();
m_hor_hedlbls = map["headerlabel"].toStringList();
m_table_map = map;
m_vec_hedlbls = map.keys();
//数据设置结束后调用endResetModel,此时会触发modelReset信号
endResetModel();
//如果表的行列数是固定的,只是数据变更了,我们可以用 dataChanged 信号来请求刷新
//emit dataChanged(index(0,0),index(RowMax-1,ColMax-1),QVector<int>());
}
void TableModel::setHignlightIndex(QVector<QPair<int, int> > vec_index)
{
beginResetModel();
m_highlight_indexs = vec_index;
endResetModel();
}
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
flags |= Qt::ItemIsEditable;
return flags;
}
int TableModel::rowCount(const QModelIndex &parent) const
{
if(parent.isValid())
return 0;
else
return m_table_map.size();
}
int TableModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
else
return m_hor_hedlbls.size();
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
QVariantMap *map = (QVariantMap*)(m_table_map[m_vec_hedlbls[index.row()]].data());
return (*map)[m_hor_hedlbls[index.column()]];
}
else if(role == Qt::TextAlignmentRole)
return Qt::AlignCenter;
return QVariant();
}
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
QVariantMap *_map = (QVariantMap*)(m_table_map[m_vec_hedlbls[index.row()]].data());
if((*_map)[m_hor_hedlbls[index.column()]] != value)
{
(*_map)[m_hor_hedlbls[index.column()]] = value;
emit dataChanged(index, index);
emit itemChanged(index, value);
return true;
}
}
return false;
}
QString TableModel::itemText(int row, int column) const
{
QVariantMap *_map = (QVariantMap*)(m_table_map[m_vec_hedlbls[row]].data());
return (*_map)[m_hor_hedlbls[column]].toString();
}
QString TableModel::itemText(const QModelIndex &index) const
{
QVariantMap *_map = (QVariantMap*)(m_table_map[m_vec_hedlbls[index.row()]].data());
return (*_map)[m_hor_hedlbls[index.column()]].toString();
}
void TableModel::setItemText(const QModelIndex &index, const QString &str)
{
QVariantMap *_map = (QVariantMap*)(m_table_map[m_vec_hedlbls[index.row()]].data());
(*_map)[m_hor_hedlbls[index.column()]] = str;
}
void TableModel::setItemText(int row, int column, const QString &str)
{
QVariantMap *_map = (QVariantMap*)(m_table_map[m_vec_hedlbls[row]].data());
(*_map)[m_hor_hedlbls[column]] = str;
}
QVariant TableModel::ItemData(const QModelIndex &index) const
{
QVariantMap *_map = (QVariantMap*)(m_data_map[m_vec_hedlbls[index.row()]].data());
return (*_map)[m_hor_hedlbls[index.column()]];
}
QVariant TableModel::ItemData(int row, int column) const
{
QVariantMap *_map = (QVariantMap*)(m_data_map[m_vec_hedlbls[row]].data());
return (*_map)[m_hor_hedlbls[column]];
}
void TableModel::SetItemData(const QModelIndex &index, const QVariant &data)
{
QString vec_lbl = m_vec_hedlbls[index.row()];
if(!m_data_map.contains(vec_lbl)) m_data_map[vec_lbl] = QVariantMap();
QVariantMap *_map = (QVariantMap*)(m_data_map[vec_lbl].data());
(*_map)[m_hor_hedlbls[index.column()]] = data;
}
void TableModel::SetItemData(int row, int column, const QVariant &data)
{
QString vec_lbl = m_vec_hedlbls[row];
if(!m_data_map.contains(vec_lbl)) m_data_map[vec_lbl] = QVariantMap();
QVariantMap *_map = (QVariantMap*)(m_data_map[vec_lbl].data());
(*_map)[m_hor_hedlbls[column]] = data;
}
void TableModel::clear()
{
beginResetModel();
m_table_map.clear();
m_data_map.clear();
m_hor_hedlbls.clear();
m_vec_hedlbls.clear();
m_highlight_indexs.clear();
endResetModel();
}
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal)
{
if (role == Qt::DisplayRole) return m_hor_hedlbls.at(section);
else return QVariant();
}
return QAbstractTableModel::headerData(section, orientation, role); // 垂直表头的序号
}
实现效果:
工程下载路径:
https://download.csdn.net/download/linyibin_123/86512679