數據可視化即採用圖形圖表等對採集的數據進行展現,能夠很是直觀的查看傳感器採集到的數據。本文將使用Qt的標準組件QTableWidget、標準模型、自定義模型分別實現對數據的表格展現。性能優化
我的PC:ThinkPad T450
操做系統:RHEL7.3 WorkStation
內存容量:8G
磁盤容量:SSD 100G
CPU:Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz數據結構
MainWindow.h文件:app
#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
MainWindow.cpp文件:ide
#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; }
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(); }
二、性能分析
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倍,數據量越大插入越耗時,頭部插入耗時遠遠大於尾部追加插入。this
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
StudentTableModel.cpp文件:code
#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; }
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
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); }
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(); }
根據生成的不一樣數量規模的數據,其程序佔用的內存以下:
使用QStandardItemModel與QTableView展現數據,每條數據實際佔用內存的大小是數據自己大小的15倍,數據量越大插入越耗時,頭部插入耗時遠遠大於尾部追加插入,其性能表現與QTableWidget至關。
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
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; }
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
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; }
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(); }
二、性能分析
根據生成的不一樣數量規模的數據,其程序佔用的內存以下:
使用QAbstractTableModel派生類與QTableView展現數據,每條數據實際佔用內存的大小是數據自己大小的1.5倍,數據量越大插入越耗時,因爲底層數據結構採用鏈表實現,頭部插入耗時與尾部追加插入耗時至關,但內存空間佔用大幅降低。
將底層數據結構換成QVector,根據生成的不一樣數量規模的數據,其程序佔用的內存以下:
使用QVector做爲模型的底層數據結構存儲數據,其內存佔用與QList至關,尾部追加插入耗時與QList至關,但頭部插入比QList耗時較多。