目录
四、Delegate + Model + View 自定义模型实现
1、QtTabelWidget.cpp - 组织界面,定义数据模型、委托、代理
2、QtModelViewTabelDelegate.cpp - 委托:用于 绘制自定义 名片控件
3、StudentTableModel.cpp - 创建模型类,提供数据的调用接口
4、TabelSortFilterProxyModel.cpp - 代理:用于对数据过滤、排序
零、附上最新版本
1、附上成果图:( 四 代码对应的效果图)
1、使用 QTableView 显示 10万条数据
2、每一条用自定义界面(名片的形式) 来显示
3、提供搜索过滤功能

2、代码位置:
https://download.youkuaiyun.com/download/LearnLHC/15933659
一、常用实现方式 - 有多少就创建多少,就显示多少
1、MainWindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QTableWidget>
#include <QVBoxLayout>
#include <QTableWidgetItem>
#include <QList>
#include <QString>
struct Student
{
char name[16];
char id[24];
char sex[8];
int age;
char phone[16];
char hobby[24];
char company[16];
};
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
/**
* @brief 生成数据
* @param size,生成数据的规模
*/
void generateData(int size);
private:
/**
* @brief 生成一行数据
* @param item,数据项
* @return 返回数据项链表
*/
QList<QTableWidgetItem*> generateRow(const Student& item);
private:
QTableWidget* m_table;
};
#endif // MAINWINDOW_H
2、MainWindow.cpp文件:
#include "MainWindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
m_table = new QTableWidget(this);
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(m_table);
setLayout(layout);
QStringList header;
header << "Name" << "ID" << "Sex" << "Age" << "Phone" << "Hobby" << "Company";
m_table->setHorizontalHeaderLabels(header);
m_table->setColumnCount(7);
}
MainWindow::~MainWindow()
{
}
// 头部插入实现
void MainWindow::generateData(int size)
{
Student* zhangsan = (Student*)malloc(sizeof(Student));
memset(zhangsan, 0, sizeof(Student));
strncpy(zhangsan->name, "zhangsan", strlen("zhangsan"));
strncpy(zhangsan->id, "53302219861001xxxx", strlen("53302219861001xxxx"));
strncpy(zhangsan->sex, "M", strlen("M"));
zhangsan->age = 33;
strncpy(zhangsan->phone, "18910108888", strlen("18910108888"));
strncpy(zhangsan->hobby, "BasketBall, Play", strlen("BasketBall, Play"));
strncpy(zhangsan->company, "Alibaba", strlen("Alibaba"));
for(int i = 0; i < size; i++)
{
m_table->insertRow(0);
QList<QTableWidgetItem*> items1 = generateRow(*zhangsan);
for(int k = 0; k < items1.size(); k++)
{
m_table->setItem(0, k, items1.at(k));
}
}
delete zhangsan;
qDebug() << sizeof(Student);
}
// 尾部插入实现
void MainWindow::generateData(int size)
{
Student* zhangsan = (Student*)malloc(sizeof(Student));
memset(zhangsan, 0, sizeof(Student));
strncpy(zhangsan->name, "zhangsan", strlen("zhangsan"));
strncpy(zhangsan->id, "53302219861001xxxx", strlen("53302219861001xxxx"));
strncpy(zhangsan->sex, "M", strlen("M"));
zhangsan->age = 33;
strncpy(zhangsan->phone, "18910108888", strlen("18910108888"));
strncpy(zhangsan->hobby, "BasketBall, Play", strlen("BasketBall, Play"));
strncpy(zhangsan->company, "Alibaba", strlen("Alibaba"));
for(int i = 0; i < size; i++)
{
m_table->insertRow(i);
QList<QTableWidgetItem*> items1 = generateRow(*zhangsan);
for(int k = 0; k < items1.size(); k++)
{
m_table->setItem(i, k, items1.at(k));
}
}
delete zhangsan;
qDebug() << sizeof(Student);
}
QList<QTableWidgetItem*> MainWindow::generateRow(const Student &item)
{
QList<QTableWidgetItem*> ret;
QTableWidgetItem* name = new QTableWidgetItem();
name->setData(Qt::DisplayRole, QString("%1").arg(item.name));
ret.append(name);
QTableWidgetItem* id = new QTableWidgetItem();
id->setData(Qt::DisplayRole, QString("%1").arg(item.id));
ret.append(id);
QTableWidgetItem* sex = new QTableWidgetItem();
sex->setData(Qt::DisplayRole, QString("%1").arg(item.sex));
ret.append(sex);
QTableWidgetItem* age = new QTableWidgetItem();
age->setData(Qt::DisplayRole, QString("%1").arg(item.age));
ret.append(age);
QTableWidgetItem* phone = new QTableWidgetItem();
phone->setData(Qt::DisplayRole, QString("%1").arg(item.phone));
ret.append(phone);
QTableWidgetItem* hobby = new QTableWidgetItem();
hobby->setData(Qt::DisplayRole, QString("%1").arg(item.hobby));
ret.append(hobby);
QTableWidgetItem* company = new QTableWidgetItem();
company->setData(Qt::DisplayRole, QString("%1").arg(item.company));
ret.append(company);
return ret;
}
3、main.cpp文件:
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.generateData(500000);
w.show();
return a.exec();
}
4、性能分析
Student结构体如下:
struct Student
{
char name[16];
char id[24];
char sex[8];
int age;
char phone[16];
char hobby[24];
char company[16];
};
Student结构体大小为108字节,根据生成的不同数量规模的数据,其程序占用的内存如下:

根据上述数据,在大规模数据量下,使用QTableWidget展示数据时,每条数据实际占用的内存是数据本身大小的15倍,数据量越大插入越耗时,头部插入耗时远远大于尾部追加插入。
二、Model / View 标准模型实现
1、StudentTableModel.h文件
#ifndef STUDENTTABLEMODEL_H
#define STUDENTTABLEMODEL_H
#include <QStandardItemModel>
#include <QStandardItem>
struct Student
{
char name[16];
char id[24];
char sex[8];
int age;
char phone[16];
char hobby[24];
char company[16];
};
class StudentTableModel : public QStandardItemModel
{
Q_OBJECT
public:
StudentTableModel();
/**
* @brief 生成数据
* @param size,数据规模
*/
void generateData(int size);
/**
* @brief 生成一行数据
* @param item,数据对象
* @return 返回数据项链表
*/
QList<QStandardItem*> generateRow(const Student& item);
/**
* @brief 追加一行
* @param item,数据对象
*/
void appendRow(const Student& item);
private:
QStandardItem* m_root;//模型虚拟根节点
};
#endif // STUDENTTABLEMODEL_H
2、StudentTableModel.cpp文件:
#include "StudentTableModel.h"
StudentTableModel::StudentTableModel()
{
m_root = invisibleRootItem();
}
void StudentTableModel::generateData(int size)
{
Student* zhangsan = (Student*)malloc(sizeof(Student));
memset(zhangsan, 0, sizeof(Student));
strncpy(zhangsan->name, "zhangsan", strlen("zhangsan"));
strncpy(zhangsan->id, "53302219861001xxxx", strlen("53302219861001xxxx"));
strncpy(zhangsan->sex, "M", strlen("M"));
zhangsan->age = 33;
strncpy(zhangsan->phone, "18910108888", strlen("18910108888"));
strncpy(zhangsan->hobby, "BasketBall, Play", strlen("BasketBall, Play"));
strncpy(zhangsan->company, "Alibaba", strlen("Alibaba"));
for(int i = 0; i < size; i++)
{
QList<QStandardItem*> items1 = generateRow(*zhangsan);
// 尾部追加
m_root->appendRow(items1);
// 头部插入
m_root->insertRow(0, items1);
}
delete zhangsan;
}
QList<QStandardItem*> StudentTableModel::generateRow(const Student &item)
{
QList<QStandardItem*> ret;
QStandardItem* name = new QStandardItem();
name->setData(QString("%1").arg(item.name), Qt::DisplayRole);
ret.append(name);
QStandardItem* id = new QStandardItem();
id->setData(QString("%1").arg(item.id), Qt::DisplayRole);
ret.append(id);
QStandardItem* sex = new QStandardItem();
sex->setData(QString("%1").arg(item.sex), Qt::DisplayRole);
ret.append(sex);
QStandardItem* age = new QStandardItem();
age->setData(QString("%1").arg(item.age), Qt::DisplayRole);
ret.append(age);
QStandardItem* phone = new QStandardItem();
phone->setData(QString("%1").arg(item.phone), Qt::DisplayRole);
ret.append(phone);
QStandardItem* hobby = new QStandardItem();
hobby->setData(QString("%1").arg(item.hobby), Qt::DisplayRole);
ret.append(hobby);
QStandardItem* company = new QStandardItem();
company->setData(QString("%1").arg(item.company), Qt::DisplayRole);
ret.append(company);
return ret;
}
3、MainWindow.h文件:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QTableView>
#include <QVBoxLayout>
#include <QHeaderView>
#include "StudentTableModel.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void generateData(int size);
private:
QTableView* m_tableView;
StudentTableModel* m_model;
};
#endif // MAINWINDOW_H
4、MainWindow.cpp文件:
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent): QWidget(parent)
{
m_tableView = new QTableView(this);
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(m_tableView);
setLayout(layout);
m_model = new StudentTableModel();
m_tableView->setModel(m_model);
QStringList header;
header << "Name" << "ID" << "Sex" << "Age" << "Phone" << "Hobby" << "Company";
m_model->setHorizontalHeaderLabels(header);
}
MainWindow::~MainWindow()
{
}
void MainWindow::generateData(int size)
{
m_model->generateData(size);
}
5、main.cpp文件:
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.generateData(500000);
return a.exec();
}
6、性能分析
根据生成的不同数量规模的数据,其程序占用的内存如下:

使用QStandardItemModel与QTableView展示数据,每条数据实际占用内存的大小是数据本身大小的15倍,数据量越大插入越耗时,头部插入耗时远远大于尾部追加插入,其性能表现与QTableWidget相当。
三、Model / View 自定义模型实现
1、StudentTableModel.h文件:
#ifndef STUDENTTABLEMODEL_H
#define STUDENTTABLEMODEL_H
#include <QAbstractTableModel>
#include <QList>
#include <QStringList>
#include <QString>
#include <QVariant>
struct Student
{
char name[16];
char id[24];
char sex[8];
int age;
char phone[16];
char hobby[24];
char company[16];
};
class StudentTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
StudentTableModel(QObject* parent = NULL);
virtual int rowCount(const QModelIndex &parent) const;
virtual int columnCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
virtual bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
void appendRow(const Student& item);
void setHorizontalHeaderLabels(const QStringList& header);
private:
QStringList m_headers;
QList<Student*> m_itemList;
};
#endif // STUDENTTABLEMODEL_H
2、StudentTableModel.cpp文件:
#include "StudentTableModel.h"
StudentTableModel::StudentTableModel(QObject *parent): QAbstractTableModel(parent)
{
}
int StudentTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_itemList.size();
}
int StudentTableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_headers.size();
}
QVariant StudentTableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= m_itemList.size() || index.row() < 0)
return QVariant();
if (role == Qt::DisplayRole)
{
int row = index.row();
Student* data = m_itemList.at(row);
int column = index.column();
switch(column)
{
case 0:
return QString("%1").arg(data->name);
case 1:
return QString("%1").arg(data->id);
case 2:
return QString("%1").arg(data->sex);
case 3:
return data->age;
case 4:
return QString("%1").arg(data->phone);
case 5:
return QString("%1").arg(data->hobby);
case 6:
return QString("%1").arg(data->company);
}
}
return QVariant();
}
QVariant StudentTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
{
return m_headers.at(section);
}
return QVariant();
}
bool StudentTableModel::insertRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row)
{
// m_itemList.insert(position, );
}
endInsertRows();
return true;
}
bool StudentTableModel::removeRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row)
m_itemList.removeAt(position);
endRemoveRows();
return true;
}
void StudentTableModel::appendRow(const Student &item)
{
Student* data = (Student*)malloc(sizeof(Student));
memset(data, 0, sizeof(Student));
strncpy(data->name, item.name, strlen(item.name));
strncpy(data->id, item.id, strlen(item.id));
strncpy(data->sex, item.sex, strlen(item.sex));
data->age = item.age;
strncpy(data->phone, item.phone, strlen(item.phone));
strncpy(data->hobby, item.hobby, strlen(item.hobby));
strncpy(data->company, item.company, strlen(item.company));
int row = m_itemList.size();
insertRows(0, 1);
m_itemList.append(data);
// m_itemList.insert(0, data);
}
void StudentTableModel::setHorizontalHeaderLabels(const QStringList &header)
{
m_headers = header;
}
bool StudentTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
int row = index.row();
// mpdify data
emit(dataChanged(index, index));
return true;
}
return false;
}
Qt::ItemFlags StudentTableModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}
3、MainWindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QTableView>
#include <QVBoxLayout>
#include "StudentTableModel.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void generateData(int size);
private:
StudentTableModel* m_model;
QTableView* m_tableView;
};
#endif // MAINWINDOW_H
4、MainWindow.cpp文件:
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent): QWidget(parent)
{
m_tableView = new QTableView(this);
m_model = new StudentTableModel();
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(m_tableView);
setLayout(layout);
QStringList header;
header << "Name" << "ID" << "Sex" << "Age" << "Phone" << "Hobby" << "Company";
m_model->setHorizontalHeaderLabels(header);
m_tableView->setUpdatesEnabled(true);
m_tableView->setModel(m_model);
}
MainWindow::~MainWindow()
{
}
void MainWindow::generateData(int size)
{
Student* zhangsan = (Student*)malloc(sizeof(Student));
memset(zhangsan, 0, sizeof(Student));
strncpy(zhangsan->name, "zhangsan", strlen("zhangsan"));
strncpy(zhangsan->id, "53302219861001xxxx", strlen("53302219861001xxxx"));
strncpy(zhangsan->sex, "M", strlen("M"));
zhangsan->age = 33;
strncpy(zhangsan->phone, "18910108888", strlen("18910108888"));
strncpy(zhangsan->hobby, "BasketBall, Play", strlen("BasketBall, Play"));
strncpy(zhangsan->company, "Alibaba", strlen("Alibaba"));
for(int i = 0; i < size; i++)
{
m_model->appendRow(*zhangsan);
}
delete zhangsan;
}
5、main.cpp文件:
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.generateData(1000000);
return a.exec();
}
6、性能分析
根据生成的不同数量规模的数据,其程序占用的内存如下:

使用QAbstractTableModel派生类与QTableView展示数据,每条数据实际占用内存的大小是数据本身大小的1.5倍,数据量越大插入越耗时,由于底层数据结构采用链表实现,头部插入耗时与尾部追加插入耗时相当,但内存空间占用大幅下降。
将底层数据结构换成QVector,根据生成的不同数量规模的数据,其程序占用的内存如下

使用QVector作为模型的底层数据结构存储数据,其内存占用与QList相当,尾部追加插入耗时与QList相当,但头部插入比QList耗时较多
四、Delegate + Model + View 自定义模型实现
1、QtTabelWidget.cpp - 组织界面,定义数据模型、委托、代理
#include <QTableView>
#include <QHeaderView>
#include <QVBoxLayout>
#include <QTime>
#include <qDebug>
#include <QLabel>
#include <QLineEdit>
#include "QtTabelWidget.h"
QtTabelWidget::QtTabelWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(800, 800);
QVBoxLayout * mainLayout = new QVBoxLayout();
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 10, 0, 30);
// 创建表格显示控件;
m_TableView = new QTableView(this);
m_TableView->setObjectName("MemberManageTableView");
m_TableView->setShowGrid(true);
m_TableView->setSelectionBehavior(QAbstractItemView::SelectItems);
m_TableView->setMouseTracking(true);
//m_TableView->setEditTriggers(QAbstractItemView::AllEditTriggers);
// 创建委托类,用于 绘制自定义 名片控件;
m_TableDelegate = new QtModelViewTabelDelegate(m_TableView);
m_TableView->setItemDelegate(m_TableDelegate);
// 创建模型类;
m_TableModel = new StudentTableModel(this);
QStringList header;
header << "Name";
m_TableModel->setHorizontalHeaderLabels(header);
// ① 不使用数据过滤器;
//m_TableView->setModel(m_TableModel);
// ② 使用数据过滤器;
m_TSFProxyModel = new TabelSortFilterProxyModel();
m_TSFProxyModel->setSourceModel(m_TableModel); //将model放入代理中;
m_TableView->setModel(m_TSFProxyModel); //在视图中安装代理;
m_TSFProxyModel->setFilterRegExp("zhangsan20"); //安装过滤器;
m_TableView->setUpdatesEnabled(true);
m_TableView->verticalHeader()->setDefaultSectionSize(600);
m_TableView->resizeRowsToContents();
m_TableView->horizontalHeader()->setDefaultSectionSize(290);
m_TableView->horizontalHeader()->setVisible(true);// 水平不可见
m_TableView->verticalHeader()->setVisible(false);// 垂直不可见
m_TableView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
// 添加 搜索框;
QHBoxLayout* hLayout = new QHBoxLayout;
QLabel * laber = new QLabel();
laber->setText("Search");
QLineEdit *lineEdit = new QLineEdit;
connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(onLineEditChangeSlot(const QString &)));
hLayout->addWidget(laber);
hLayout->addWidget(lineEdit);
mainLayout->addLayout(hLayout);
mainLayout->addWidget(m_TableView);
setLayout(mainLayout);
}
QtTabelWidget::~QtTabelWidget()
{
}
//组织 十万条数据;
void QtTabelWidget::generateData(int size)
{
QTime time;
time.start();
QList<StudentPtr> itemList;
for (int i = 0; i < size; i++)
{
StudentPtr data = QSharedPointer<Student>(new Student);
data->name = "zhangsan" + QString::number(i);
data->id = "53302219861001xxxx";
data->sex = "M";
data->age = 33;
data->phone = "18910108888";
data->hobby = "BasketBall, Play";
data->company = QString(":/pic/Resources/side%1.png").arg(i%3+1);
itemList.push_back(data);
//m_TableModel->appendRow(data);
}
m_TableModel->appendRows(itemList);
//qDebug() << QStringLiteral("代码程序运行时间:") << time.elapsed();
qDebug() << time.elapsed() / 1000.0 << "s";
}
// 搜索内容变更时,重设过滤器;
void QtTabelWidget::onLineEditChangeSlot(const QString & text)
{
//安装过滤器;
m_TSFProxyModel->setFilterRegExp(text);
// 调用 invalidateFilter() 函数,使之前的过滤失效,激活当前过滤.
//m_TSFProxyModel->invalidateFilter();
}
2、QtModelViewTabelDelegate.cpp - 委托:用于 绘制自定义 名片控件
#include <QAbstractItemView>
#include <QTableView>
#include <QLabel>
#include <QGridLayout>
#include <QLineEdit>
#include "QtModelViewTabelDelegate.h"
#include "StudentTableModel.h"
QtModelViewTabelDelegate::QtModelViewTabelDelegate(QAbstractItemView *itemView)
{
m_itemView = itemView;
}
QtModelViewTabelDelegate::~QtModelViewTabelDelegate()
{
}
void QtModelViewTabelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(painter);
Q_UNUSED(option);
QStyleOptionViewItem opt = option;
QString NN = opt.widget->objectName();
// 也可以直接用 m_itemView 代替 tV 来操作;
QWidget * widget = const_cast<QWidget *>(opt.widget);
QTableView * tV = dynamic_cast<QTableView *>(widget);
if (tV)
{
if (tV->indexWidget(index) == nullptr)
{
QWidget *itemWidget = createItemWidget(index);
if (itemWidget != nullptr)
{
tV->setIndexWidget(index, itemWidget);
}
}
else
{
updateItemWidget(index);
setRowHeight(index);
}
}
}
QWidget * QtModelViewTabelDelegate::createItemWidget(const QModelIndex &index) const
{
StudentPtr adapter = index.data().value<StudentPtr>();
if (!adapter)
return nullptr;
QWidget *wid = new QWidget();
wid->setObjectName("QWidgetF");
QGridLayout *glay = new QGridLayout();
glay->setObjectName("QGridLayoutF");
QLabel *nameItem = new QLabel();
nameItem->setText(adapter->name);
QLabel *idItem = new QLabel();
idItem->setText(adapter->id);
QLabel *sexItem = new QLabel();
sexItem->setText(adapter->sex);
QLineEdit *phoneItem = new QLineEdit();
phoneItem->setText(adapter->phone);
phoneItem->setObjectName("phoneItem");
phoneItem->installEventFilter(const_cast<QtModelViewTabelDelegate*>(this));
connect(phoneItem, SIGNAL(textChanged(const QString &)), this, SLOT(onLineEditChangeSlot(const QString &)));
QLineEdit *hobbyItem = new QLineEdit();
hobbyItem->setText(adapter->hobby);
connect(hobbyItem, SIGNAL(textChanged(const QString &)), this, SLOT(onLineEditChangeSlot(const QString &)));
QLabel *companyItem = new QLabel();
companyItem->setText(adapter->company);
companyItem->setPixmap(QPixmap(adapter->company).scaled(90,90));
glay->addWidget(nameItem, 0, 0, 1, 1);
glay->addWidget(idItem, 1, 0, 1, 1);
glay->addWidget(sexItem, 2, 0, 1, 1);
glay->addWidget(phoneItem, 0, 1);
glay->addWidget(hobbyItem, 2, 1);
glay->addWidget(companyItem, 0, 2, 3, 4);
glay->setContentsMargins(5, 5, 5, 5);
wid->setLayout(glay);
return wid;
}
void QtModelViewTabelDelegate::setRowHeight(const QModelIndex &index) const
{
StudentPtr adapter = index.data().value<StudentPtr>();
if (!adapter)
return;
QTableView *tableView = dynamic_cast<QTableView*>(m_itemView);
if (tableView == nullptr)
return;
int nHeight = 100;
tableView->setRowHeight(index.row(), nHeight);
tableView->setColumnWidth(0, 400);
}
void QtModelViewTabelDelegate::updateItemWidget(const QModelIndex &index) const
{
}
bool QtModelViewTabelDelegate::eventFilter(QObject *watched, QEvent *event)
{
if (watched->objectName() == "phoneItem")
{
if (event->type() == QEvent::MouseButtonPress)
{
QTableView *tableView = dynamic_cast<QTableView*>(m_itemView);
if (tableView == nullptr)
return false;
QModelIndex indexM = tableView->indexAt(tableView->mapFromGlobal(QCursor::pos()));
tableView->setCurrentIndex(indexM);
}
}
return false;
}
void QtModelViewTabelDelegate::onLineEditChangeSlot(const QString & text)
{
StudentPtr adapter = m_itemView->currentIndex().data().value<StudentPtr>();
if (!adapter)
return;
QString ob = adapter->name;
int i = 0;
}
3、StudentTableModel.cpp - 创建模型类,提供数据的调用接口
#include "StudentTableModel.h"
StudentTableModel::StudentTableModel(QObject *parent) : QAbstractTableModel(parent)
{
}
int StudentTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_itemList.size();
}
int StudentTableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_headers.size();
}
QVariant StudentTableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= m_itemList.size() || index.row() < 0)
return QVariant();
if (role == Qt::DisplayRole)
{
int row = index.row();
StudentPtr data = m_itemList.at(row);
return QVariant::fromValue(data);
/*int column = index.column();
switch (column)
{
case 0:
return QString("%1").arg(data->name);
case 1:
return QString("%1").arg(data->id);
case 2:
return QString("%1").arg(data->sex);
case 3:
return data->age;
case 4:
return QString("%1").arg(data->phone);
case 5:
return QString("%1").arg(data->hobby);
case 6:
return QString("%1").arg(data->company);
}*/
}
return QVariant();
}
QVariant StudentTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
{
return m_headers.at(section);
}
return QVariant();
}
bool StudentTableModel::insertRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position + rows - 1);
endInsertRows();
return true;
}
bool StudentTableModel::removeRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row)
m_itemList.removeAt(position);
endRemoveRows();
return true;
}
void StudentTableModel::appendRow(const StudentPtr item)
{
beginInsertRows(QModelIndex(), m_itemList.size(), m_itemList.size() + 1);
m_itemList.append(item);
endInsertRows();
}
void StudentTableModel::appendRows(QList<StudentPtr> item)
{
beginInsertRows(QModelIndex(), 0, item.size());
m_itemList = item;
endInsertRows();
}
void StudentTableModel::setHorizontalHeaderLabels(const QStringList &header)
{
m_headers = header;
}
bool StudentTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
int row = index.row();
// mpdify data
emit(dataChanged(index, index));
return true;
}
return false;
}
Qt::ItemFlags StudentTableModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}
4、TabelSortFilterProxyModel.cpp - 代理:用于对数据过滤、排序
#include "TabelSortFilterProxyModel.h"
#include "StudentTableModel.h"
TabelSortFilterProxyModel::TabelSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
TabelSortFilterProxyModel::~TabelSortFilterProxyModel()
{
}
bool TabelSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
//获取model中实际的数据;
StudentPtr adapter = sourceModel()->index(source_row, 0, source_parent).data().value<StudentPtr>();
if (!adapter)
return false;
if (adapter->name.contains(this->filterRegExp()))
{
return true;
}
return false;
}
bool TabelSortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
//通过当前视图中的index位置获取model中实际的数据;
QVariant leftData = sourceModel()->data(source_left);
QVariant rightData = sourceModel()->data(source_right);
switch (source_left.column())
{
case 0: //序号,需要判断数字;
case 3: //信号ID,需要判断数字;
return leftData.toInt() < rightData.toInt();
break;
default: //其它,只判断字符串;
return leftData.toString() < rightData.toString();
break;
}
return true;
}
本文详细介绍了如何在QT中以名片形式流畅地显示10万条数据,对比了不同实现方式的性能,包括QTableWidget、QStandardItemModel、QAbstractTableModel和自定义Delegate结合Model/View的方法。通过性能分析,展示了内存占用和插入效率,特别是自定义模型和委托的优化效果。

被折叠的 条评论
为什么被折叠?



