溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Qt高級(jí)——Qt數(shù)據(jù)可視化性能優(yōu)化

發(fā)布時(shí)間:2020-08-09 22:19:17 來(lái)源:網(wǎng)絡(luò) 閱讀:2233 作者:天山老妖S 欄目:編程語(yǔ)言

Qt高級(jí)——Qt數(shù)據(jù)可視化性能優(yōu)化

一、數(shù)據(jù)可視化簡(jiǎn)介

1、數(shù)據(jù)可視化簡(jiǎn)介

數(shù)據(jù)可視化即采用圖形圖表等對(duì)采集的數(shù)據(jù)進(jìn)行展示,可以非常直觀的查看傳感器采集到的數(shù)據(jù)。本文將使用Qt的標(biāo)準(zhǔn)組件QTableWidget、標(biāo)準(zhǔn)模型、自定義模型分別實(shí)現(xiàn)對(duì)數(shù)據(jù)的表格展示。

2、系統(tǒng)環(huán)境

個(gè)人PC:ThinkPad T450
操作系統(tǒng):RHEL7.3 WorkStation
內(nèi)存容量:8G
磁盤容量:SSD 100G
CPU:Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz

二、標(biāo)準(zhǔn)界面組件實(shí)現(xiàn)

1、代碼實(shí)現(xiàn)

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 生成數(shù)據(jù)
     * @param size,生成數(shù)據(jù)的規(guī)模
     */
    void generateData(int size);
private:
    /**
     * @brief 生成一行數(shù)據(jù)
     * @param item,數(shù)據(jù)項(xiàng)
     * @return 返回?cái)?shù)據(jù)項(xiàng)鏈表
     */
    QList<QTableWidgetItem*> generateRow(const Student& item);
private:
    QTableWidget* m_table;
};

#endif // MAINWINDOW_H

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()
{

}
// 頭部插入實(shí)現(xiàn)
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);

}
// 尾部插入實(shí)現(xiàn)
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();
}

2、性能分析
Student結(jié)構(gòu)體如下:

struct Student
{
    char name[16];
    char id[24];
    char sex[8];
    int age;
    char phone[16];
    char hobby[24];
    char company[16];
};

Student結(jié)構(gòu)體大小為108字節(jié),根據(jù)生成的不同數(shù)量規(guī)模的數(shù)據(jù),其程序占用的內(nèi)存如下:
Qt高級(jí)——Qt數(shù)據(jù)可視化性能優(yōu)化
根據(jù)上述數(shù)據(jù),在大規(guī)模數(shù)據(jù)量下,使用QTableWidget展示數(shù)據(jù)時(shí),每條數(shù)據(jù)實(shí)際占用的內(nèi)存是數(shù)據(jù)本身大小的15倍,數(shù)據(jù)量越大插入越耗時(shí),頭部插入耗時(shí)遠(yuǎn)遠(yuǎn)大于尾部追加插入。

三、標(biāo)準(zhǔn)模型實(shí)現(xiàn)

1、代碼實(shí)現(xiàn)

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 生成數(shù)據(jù)
     * @param size,數(shù)據(jù)規(guī)模
     */
    void generateData(int size);
    /**
     * @brief 生成一行數(shù)據(jù)
     * @param item,數(shù)據(jù)對(duì)象
     * @return 返回?cái)?shù)據(jù)項(xiàng)鏈表
     */
    QList<QStandardItem*> generateRow(const Student& item);
    /**
     * @brief 追加一行
     * @param item,數(shù)據(jù)對(duì)象
     */
    void appendRow(const Student& item);

private:
    QStandardItem* m_root;//模型虛擬根節(jié)點(diǎn)
};

#endif // STUDENTTABLEMODEL_H

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;
}

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();
}

2、性能分析

根據(jù)生成的不同數(shù)量規(guī)模的數(shù)據(jù),其程序占用的內(nèi)存如下:
Qt高級(jí)——Qt數(shù)據(jù)可視化性能優(yōu)化
使用QStandardItemModel與QTableView展示數(shù)據(jù),每條數(shù)據(jù)實(shí)際占用內(nèi)存的大小是數(shù)據(jù)本身大小的15倍,數(shù)據(jù)量越大插入越耗時(shí),頭部插入耗時(shí)遠(yuǎn)遠(yuǎn)大于尾部追加插入,其性能表現(xiàn)與QTableWidget相當(dāng)。

四、自定義模型實(shí)現(xiàn)

1、代碼實(shí)現(xiàn)

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();
}

2、性能分析
根據(jù)生成的不同數(shù)量規(guī)模的數(shù)據(jù),其程序占用的內(nèi)存如下:
Qt高級(jí)——Qt數(shù)據(jù)可視化性能優(yōu)化
使用QAbstractTableModel派生類與QTableView展示數(shù)據(jù),每條數(shù)據(jù)實(shí)際占用內(nèi)存的大小是數(shù)據(jù)本身大小的1.5倍,數(shù)據(jù)量越大插入越耗時(shí),由于底層數(shù)據(jù)結(jié)構(gòu)采用鏈表實(shí)現(xiàn),頭部插入耗時(shí)與尾部追加插入耗時(shí)相當(dāng),但內(nèi)存空間占用大幅下降。
將底層數(shù)據(jù)結(jié)構(gòu)換成QVector,根據(jù)生成的不同數(shù)量規(guī)模的數(shù)據(jù),其程序占用的內(nèi)存如下:
Qt高級(jí)——Qt數(shù)據(jù)可視化性能優(yōu)化
使用QVector作為模型的底層數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)數(shù)據(jù),其內(nèi)存占用與QList相當(dāng),尾部追加插入耗時(shí)與QList相當(dāng),但頭部插入比QList耗時(shí)較多。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI