Qt5中表格处理大数据量
在Qt中如果是普通项目,GUI处理展现的数据量不大,一般用QTableWidget,QTreeWidget这样的控件就满足了,但是如果数据量行数达到了几万行,那么Widget的展示性能就偏差了。
Qt中提供了一种Model/View的编程方式来处理数据,也就是展示层和数据层分离,这样就解耦了。一旦Model的状态改变,它会自动渲染到View控件。这样的机制使得GUI可以展现大量的数据也不会卡顿。
为了处理数据的灵活性,我们用QStandardItemModel来做QTableView的Model层实现。因为以Table的形式展现,所以以下代码实现了,点击表头按列排序,点击行显式行的上下文菜单的功能。因为QTableView的默认
排序是按字符序列排序,所以得对QStandardItem进行子类化,并重载operator< 函数才能达到某些列用数值大小来排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | // ModelViewTable.h #pragma once #include <QtWidgets/QWidget> #include "ui_ModelViewTable.h" class QStandardItemModel; class QMenu; class ModelViewTable : public QWidget { Q_OBJECT public : ModelViewTable(QWidget *parent = Q_NULLPTR); void generateDataSet(); void addRowRecord( int row); void setColumnItem( int row, int column, QString ip); public slots: void slotShowContextMenu( const QPoint& point); private : Ui::ModelViewTableClass ui; QStandardItemModel * m_model; QMenu* m_contextMenu; }; // ModelViewTable.cpp #include "ModelViewTable.h" #include <QStandardItemModel> #include <QStandardItem> #include <QString> #include <QMenu> #include <QAction> #include "CustomStandardItem.h" ModelViewTable::ModelViewTable(QWidget *parent) : QWidget(parent) { ui.setupUi( this ); //////////////////////////设置表头///////////////////// m_model = new QStandardItemModel( this ); m_model->setColumnCount(3); m_model->setHeaderData(0, Qt::Horizontal, QStringLiteral( "终端IP" )); m_model->setHeaderData(1, Qt::Horizontal, QStringLiteral( "CPU使用率" )); m_model->setHeaderData(2, Qt::Horizontal, QStringLiteral( "内存使用率" )); ui.tableView->resizeColumnsToContents(); // 自适应列宽 ui.tableView->setSortingEnabled( true ); // 可以按列来排序 ui.tableView->setModel(m_model); ui.tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignHCenter); ui.tableView->horizontalHeader()->setFont(QFont( "Times" ,10,QFont::Bold)); ui.tableView->setSelectionBehavior(QAbstractItemView::SelectRows); //整行选中 ui.tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); // 表格单元格为只读 ui.tableView->setContextMenuPolicy(Qt::CustomContextMenu); // 可以自定义右键菜单 m_contextMenu = new QMenu( this ); QAction *processAct = new QAction(QStringLiteral( "进程列表信息" ),m_contextMenu); QAction *windowAppsAct = new QAction(QStringLiteral( "窗口应用列表信息" ),m_contextMenu); m_contextMenu->addAction(processAct); m_contextMenu->addAction(windowAppsAct); connect(ui.tableView, SIGNAL(customContextMenuRequested( const QPoint&)), this , SLOT(slotShowContextMenu( const QPoint&))); } void ModelViewTable::generateDataSet() { for ( int i = 0; i < 3000; ++i) { addRowRecord(i); } } void ModelViewTable::addRowRecord( int row) { // 每行3列 QString ip = QString( "%1.%2.%3.%4" ).arg(192).arg(168).arg(1).arg(row); setColumnItem(row, 0, ip); QString cpu = QString( "%1" ).arg((row * 10) % 100); setColumnItem(row, 1, cpu); QString mem = QString( "%1" ).arg((row * 12) % 100); setColumnItem(row, 2, mem); } void ModelViewTable::slotShowContextMenu( const QPoint& point) { QModelIndex index = ui.tableView->indexAt(point); if (index.isValid()) { m_contextMenu->exec(QCursor::pos()); } } void ModelViewTable::setColumnItem( int row, int column, QString ip) { m_model->setItem(row, column, new CustomStandardItem(ip)); m_model->item(row, column)->setTextAlignment(Qt::AlignCenter); } |
因为需要实现自定义的数值排序,所以要继承QStandardItem,并覆盖其中的相关函数:
// CustomStandardItem.h #pragma once #include <QStandardItem> #include <QString> // 自定义数值排序 class CustomStandardItem : public QStandardItem { // Q_OBJECT public: CustomStandardItem(); CustomStandardItem(const CustomStandardItem& other); CustomStandardItem(const QString &text); CustomStandardItem & operator =(const CustomStandardItem& other); ~CustomStandardItem(); public: virtual bool operator<(const QStandardItem& other) const override; }; //CustomStandardItem.cpp #include "CustomStandardItem.h" #include <QVariant> CustomStandardItem::CustomStandardItem() { } CustomStandardItem::CustomStandardItem(const CustomStandardItem& other) :QStandardItem(other) { } CustomStandardItem::CustomStandardItem(const QString &text) :QStandardItem(text) { } CustomStandardItem::~CustomStandardItem() { } CustomStandardItem & CustomStandardItem::operator=(const CustomStandardItem& other) { QStandardItem::operator=(other); return *this; } bool CustomStandardItem::operator<(const QStandardItem& other) const { const QVariant left = data(Qt::DisplayRole), right = other.data(Qt::DisplayRole); // 第1到2列,全部采用浮点数的大小排序 if (column() == other.column() && other.column() >= 1 && other.column() <= 2) { return left.toDouble() < right.toDouble(); } return QStandardItem::operator<(other); }
出处:https://www.cnblogs.com/foohack/p/7531446.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)