qt は QCustomplot を使用して CPU とメモリ使用量のグラフを描画します

1. QCustomPlot の概要

            QCustomPlot は、データを視覚化するためのオープンソースの Qt C++ グラフ作成ライブラリです。このライブラリには、散布図、折れ線グラフ、ヒストグラム、等高線図など、カスタマイズ可能なさまざまな種類のグラフが用意されています。また、カスタム描画もサポートしているため、任意の形状やサイズの要素を作成し、他の要素と相互作用させることができます。QCustomPlot は既存の Qt アプリケーションに簡単に統合でき、マウス選択、ズーム、パンなどの一般的なチャート操作をサポートします。さらに、高品質の画像と PDF 出力を生成できます。QCustomplot のドキュメントにはその使用法と API が詳しく記載されており、アプリケーションにデータ視覚化機能を追加する必要がある開発者にとって強力で便利なツールとなっています。

2.インターフェースのプレビュー

ここに画像の説明を挿入します

3. コードの実装

1.Qcustomplotのダウンロード

QCustomPlot は、QCustomPlot 公式 Web サイト (https://www.qcustomplot.com/index.php/download) からダウンロードできます。この Web サイトでは、最新の安定バージョンとすべての過去のバージョンのダウンロード リンクを見つけることができます。
ここに画像の説明を挿入します

2. Qcustomplot をプロジェクトに追加します

ダウンロードした Qcustomplot 圧縮パッケージを解凍し、 とqcustomplot.cppqcustomplot.hプロジェクトにコピーして
ここに画像の説明を挿入します
、プロジェクトを右クリックし、 [既存のファイルをプロジェクトに追加] を選択します。
ここに画像の説明を挿入します

3. プロジェクトファイルの修正

プロジェクトの .pro ファイルを開き、printsupportコンポーネントのサポートを追加します。注: コンパイラのバージョンが 6.5 の場合は、次のようにこの文も
追加する必要があります。QMAKE_CXXFLAGS += -Wa,-mbig-obj,
ここに画像の説明を挿入します

4. コードの書き方

a. 新しいクラスを作成する

まず、新しいデザイナー インターフェイス クラスを作成し、次にデザイナー インターフェイスにウィジェットを配置して、QCustomPlot次のように にアップグレードします。
ここに画像の説明を挿入します

4. プロジェクトのソースコード

.h ファイル

#ifndef SYSTEMSTATISTICSWIDGET_H
#define SYSTEMSTATISTICSWIDGET_H

#include <QWidget>
#include <QPixmap>
#include <QTextEdit>
#include <QObject>
#include <QTextObjectInterface>
#include <QPicture>
#include <QVariant>
#include <QPainter>

#include "qcustomplot.h"

namespace Ui {
    
    
class SystemStatisticsWidget;
}

class AxisTag : public QObject
{
    
    
public:
    explicit AxisTag(QCPAxis *parentAxis):QObject(parentAxis),mAxis(parentAxis)
    {
    
    
        mDummyTracer = new QCPItemTracer(mAxis->parentPlot());
        mDummyTracer->setVisible(false);
        mDummyTracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
        mDummyTracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
        mDummyTracer->position->setAxisRect(mAxis->axisRect());
        mDummyTracer->position->setAxes(0, mAxis);
        mDummyTracer->position->setCoords(1, 0);

        mArrow = new QCPItemLine(mAxis->parentPlot());
        mArrow->setLayer("overlay");
        mArrow->setClipToAxisRect(false);
        mArrow->setHead(QCPLineEnding::esSpikeArrow);
        mArrow->end->setParentAnchor(mDummyTracer->position);
        mArrow->start->setParentAnchor(mArrow->end);
        mArrow->start->setCoords(15, 0);

        mLabel = new QCPItemText(mAxis->parentPlot());
        mLabel->setLayer("overlay");
        mLabel->setClipToAxisRect(false);
        mLabel->setPadding(QMargins(3, 0, 3, 0));
        mLabel->setBrush(QBrush(Qt::white));
        mLabel->setPen(QPen(Qt::blue));
        mLabel->setPositionAlignment(Qt::AlignLeft|Qt::AlignVCenter);
        mLabel->position->setParentAnchor(mArrow->start);
    }

    virtual ~AxisTag()
    {
    
    
        if (mDummyTracer)
            mDummyTracer->parentPlot()->removeItem(mDummyTracer);
        if (mArrow)
            mArrow->parentPlot()->removeItem(mArrow);
        if (mLabel)
            mLabel->parentPlot()->removeItem(mLabel);
    }

    // setters:
    void setPen(const QPen &pen)
    {
    
    
        mArrow->setPen(pen);
        mLabel->setPen(pen);
    }
    void setBrush(const QBrush &brush)
    {
    
    
        mLabel->setBrush(brush);
    }
    void setText(const QString &text)
    {
    
    
        mLabel->setText(text);
    }

    // getters:
    QPen pen() const {
    
     return mLabel->pen(); }
    QBrush brush() const {
    
     return mLabel->brush(); }
    QString text() const {
    
     return mLabel->text(); }

    // other methods:
    void updatePosition(double value)
    {
    
    
        mDummyTracer->position->setCoords(1, value);
        mArrow->end->setCoords(mAxis->offset(), 0);
    }


protected:
    QCPAxis *mAxis;
    QPointer<QCPItemTracer> mDummyTracer;
    QPointer<QCPItemLine> mArrow;
    QPointer<QCPItemText> mLabel;
};


class SystemStatisticsWidget : public QWidget
{
    
    
    Q_OBJECT

public:
    enum {
    
    
        PlotTextFormat = QTextFormat::UserObject + 3902
    };
    enum {
    
    
        PicturePropertyId = 1
    };
    explicit SystemStatisticsWidget(QWidget *parent = nullptr);
    ~SystemStatisticsWidget();

    void addData(double cpuUsage,double memoryUsage);
    void popWindow(int x,int y,int width,int height);
protected:
    void showEvent(QShowEvent *event) override;
private:
    void controlInit();
    void setLabelText(double cpuUsage,double memoryUsage);
private slots:
    void btnClickedSlot();
private:
    Ui::SystemStatisticsWidget *ui;

    QPointer<QCPGraph> graphCpu;
    QPointer<QCPGraph> graphMemory;
    AxisTag *tagCpu;
    AxisTag *tagMemory;

    QString filePath;
};




#endif // SYSTEMSTATISTICSWIDGET_H

AxisTag クラスは、単一の値を表示する画像の右側にある小さなラベルです。
.cpp ファイル:

#include "systemStatisticsWidget.h"
#include "ui_systemStatisticsWidget.h"

SystemStatisticsWidget::SystemStatisticsWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SystemStatisticsWidget),
    tagCpu(0),
    tagMemory(0)
{
    
    
    ui->setupUi(this);
    this->controlInit();
}

SystemStatisticsWidget::~SystemStatisticsWidget()
{
    
    
    delete ui;
}

void SystemStatisticsWidget::controlInit()
{
    
    
    this->ui->widgetPlot->yAxis->setTickLabels(false);
    connect(this->ui->widgetPlot->yAxis2, SIGNAL(rangeChanged(QCPRange)), this->ui->widgetPlot->yAxis, SLOT(setRange(QCPRange)));


    this->ui->widgetPlot->yAxis2->setVisible(true);
    this->ui->widgetPlot->axisRect()->addAxis(QCPAxis::atRight);
    this->ui->widgetPlot->axisRect()->axis(QCPAxis::atRight, 0)->setPadding(30);
    this->ui->widgetPlot->axisRect()->axis(QCPAxis::atRight, 1)->setPadding(30);


    graphCpu = this->ui->widgetPlot->addGraph(this->ui->widgetPlot->xAxis, this->ui->widgetPlot->axisRect()->axis(QCPAxis::atRight, 0));
    graphMemory = this->ui->widgetPlot->addGraph(this->ui->widgetPlot->xAxis, this->ui->widgetPlot->axisRect()->axis(QCPAxis::atRight, 1));
    graphCpu->setPen(QPen(QColor(250, 120, 0)));
    graphMemory->setPen(QPen(QColor(0, 180, 60)));

    this->graphCpu->setName(tr("CPU使用率"));
    this->graphMemory->setName(tr("内存使用率"));
    this->ui->widgetPlot->legend->setVisible(true);


    tagCpu = new AxisTag(graphCpu->valueAxis());
    tagCpu->setPen(graphCpu->pen());
    tagMemory = new AxisTag(graphMemory->valueAxis());
    tagMemory->setPen(graphMemory->pen());


    connect(this->ui->btnClearData,&QPushButton::clicked,this,&SystemStatisticsWidget::btnClickedSlot);
    connect(this->ui->btnScreenshotAndExport,&QPushButton::clicked,this,&SystemStatisticsWidget::btnClickedSlot);
    connect(this->ui->btnPause,&QPushButton::clicked,this,&SystemStatisticsWidget::btnClickedSlot);
}

void SystemStatisticsWidget::setLabelText(double cpuUsage, double memoryUsage)
{
    
    
#define WARNING_VALUE 70
#define ERROR_VALUE 90

    if(cpuUsage > 90)
        this->ui->labelCpuUasge->setStyleSheet("color: rgb(255, 0, 0);font: 700 11pt \"Microsoft YaHei UI\";");
    else if(cpuUsage >= 70)
        this->ui->labelCpuUasge->setStyleSheet("color: rgb(255, 255, 0);font: 700 11pt \"Microsoft YaHei UI\";");
    else
        this->ui->labelCpuUasge->setStyleSheet("color: rgb(255, 255, 255);font: 700 11pt \"Microsoft YaHei UI\";");
    this->ui->labelCpuUasge->setText(QString::number(cpuUsage,'f',2));
    if(memoryUsage > 90)
    {
    
    
        this->ui->labelMemoryUsage->setStyleSheet("color: rgb(255, 0, 0);font: 700 11pt \"Microsoft YaHei UI\";");
    }
    else if(memoryUsage >= 70)
    {
    
    
        this->ui->labelMemoryUsage->setStyleSheet("color: rgb(255, 255, 0);font: 700 11pt \"Microsoft YaHei UI\";");
    }
    else
    {
    
    
        this->ui->labelMemoryUsage->setStyleSheet("color: rgb(255, 255, 255);font: 700 11pt \"Microsoft YaHei UI\";");
    }
    this->ui->labelMemoryUsage->setText(QString::number(cpuUsage,'f',2));
}

void SystemStatisticsWidget::addData(double cpuUsage, double memoryUsage)
{
    
    
    if(this->isHidden())
        return;
    if(this->ui->btnPause->isChecked())
        return;

    graphCpu->addData(graphCpu->dataCount(), cpuUsage);
    graphMemory->addData(graphMemory->dataCount(), memoryUsage);

    this->ui->widgetPlot->xAxis->rescale();
    graphCpu->rescaleValueAxis(false, true);
    graphMemory->rescaleValueAxis(false, true);
    this->ui->widgetPlot->xAxis->setRange(this->ui->widgetPlot->xAxis->range().upper, 100, Qt::AlignRight);


    double graphCpuValue = graphCpu->dataMainValue(graphCpu->dataCount()-1);
    double graphMemoryValue = graphMemory->dataMainValue(graphMemory->dataCount()-1);
    tagCpu->updatePosition(graphCpuValue);
    tagMemory->updatePosition(graphMemoryValue);
    tagCpu->setText(QString::number(graphCpuValue, 'f', 2));
    tagMemory->setText(QString::number(graphMemoryValue, 'f', 2));

    this->ui->widgetPlot->replot();

    this->setLabelText(cpuUsage,memoryUsage);
}

void SystemStatisticsWidget::popWindow(int x, int y, int width, int height)
{
    
    
    //实例阴影shadow
    QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this->ui->frame);
    shadow->setOffset(0, 0);
    shadow->setColor(QColor(32, 101, 165));
    shadow->setBlurRadius(10);
    this->ui->frame->setGraphicsEffect(shadow);

    this->ui->frame->setStyleSheet("QFrame#frame{border:1px groove gray;"
                                   "border-radius:10px;padding:5px;"
                                   "background-color: rgb(255, 255, 255);}");


    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
    this->setAttribute(Qt::WA_TranslucentBackground, true);

    //计算显示位置
#define DIST_TO_MOUISE 10
    int screenWidth = QGuiApplication::screenAt(QCursor().pos())->geometry().width();
    int screenHeight = QGuiApplication::screenAt(QCursor().pos())->geometry().height();

    int showX,showY;

    if(x + width + DIST_TO_MOUISE > screenWidth)
        showX = x-width-DIST_TO_MOUISE;
    else
        showX = x + DIST_TO_MOUISE;
    if(y + height + DIST_TO_MOUISE > screenHeight)
        showY = y - height - DIST_TO_MOUISE;
    else
        showY = y + DIST_TO_MOUISE;

    this->setGeometry(showX,showY,width,height);

    this->show();
}

void SystemStatisticsWidget::showEvent(QShowEvent *event)
{
    
    
    Q_UNUSED(event);
    this->graphCpu->data().data()->clear();
    this->graphMemory->data().data()->clear();
}

void SystemStatisticsWidget::btnClickedSlot()
{
    
    
    QPushButton *btn = static_cast<QPushButton *>(sender());

    if( btn == this->ui->btnClearData)
    {
    
    
        this->graphCpu->data().data()->clear();
        this->graphMemory->data().data()->clear();
        this->ui->widgetPlot->replot();
    }
    else if(btn == this->ui->btnScreenshotAndExport)
    {
    
    
//        if(this->filePath.isEmpty())
//        {
    
    
//            this->filePath = QFileDialog::getSaveFileName(this, "Save document...", qApp->applicationDirPath(), "*.pdf");
//        }
//        if(this->filePath.isEmpty())
//            return;
        QScreen *screen = QGuiApplication::primaryScreen();

        int x = this->ui->widgetPlot->mapToGlobal(QPoint(0,0)).x();
        int y = this->ui->widgetPlot->mapToGlobal(QPoint(0,0)).y();

        QPixmap pixmapGrab = screen->grabWindow(0,x,y,this->ui->widgetPlot->width(),this->ui->widgetPlot->height());
        QString fileName = QDateTime::currentDateTime().toString("yyyy.MM.dd.hh.mm.ss")+".png";
        pixmapGrab.save(fileName);
//        // 打印和绘图对象
//        QPrinter printer;
//        QPainter painter;
//        printer.setOutputFormat(QPrinter::PdfFormat);
//        printer.setOutputFileName(this->filePath);
//        QMargins pageMargins(20, 20, 20, 20);
//        QPageLayout pageLayout;
//        pageLayout.setMode(QPageLayout::StandardMode);
//        pageLayout.setOrientation(QPageLayout::Portrait);
//        pageLayout.setPageSize(QPageSize(QPageSize::A4));
//        pageLayout.setUnits(QPageLayout::Millimeter);
//        pageLayout.setMargins(QMarginsF(pageMargins));
//        printer.setPageLayout(pageLayout);

//        // QPrinter 和 QPainter关联
//        painter.begin(&printer);
//        painter.setFont(QFont("微软雅黑", 20));

//        // 尺寸根据pdf的页面宽度缩放
//        if(pixmapGrab.width() > printer.width())
//        {
    
    
//            pixmapGrab = pixmapGrab.scaledToWidth(printer.width(), Qt::TransformationMode::SmoothTransformation);
//        }
//        // 生成新的一页并绘制上去
//        //printer.newPage();
//        painter.drawPixmap(0, 0, pixmapGrab.width(), pixmapGrab.height(), pixmapGrab);

//        QString str = "\n"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
//        QRect textRect(0,pixmapGrab.height(),printer.width(),20);
//        painter.drawText(textRect, Qt::AlignCenter, str);
//        // 关闭绘制
//        painter.end();
    }
    else if(btn == this->ui->btnPause)
    {
    
    

    }
}

5. テストコードを書く

1. まず mainwindow.h でインターフェイスとタイマーを定義します。

    SystemStatisticsWidget *systemStatisticsWidget;
    QTimer mDataTimer;

ここに画像の説明を挿入します

2. mainwindow.cpp のスロットをインスタンス化して接続し、定期的にデータを追加します

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    ,systemStatisticsWidget(new SystemStatisticsWidget())
{
    
    
    ui->setupUi(this);

    connect(&mDataTimer, SIGNAL(timeout()), this, SLOT(timeroutSlot()));
    mDataTimer.start(40);

    this->ui->btnPopwindow->installEventFilter(this);
}

MainWindow::~MainWindow()
{
    
    
    delete ui;
}


void MainWindow::on_btnShow_clicked()
{
    
    
    this->systemStatisticsWidget->show();
}

void MainWindow::timeroutSlot()
{
    
    
    if(!systemStatisticsWidget->isHidden())
    {
    
    
        static uint64_t dataPoint = 0;
        dataPoint++;
        double cpu = qSin(dataPoint/50.0)+qSin(dataPoint/50.0/0.3843)*0.25;
        double memory = qCos(dataPoint/50.0)+qSin(dataPoint/50.0/0.4364)*0.15;
        this->systemStatisticsWidget->addData(cpu,memory);
    }
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    
    
    if(obj == this->ui->btnPopwindow)
    {
    
    
        if(event->type() == QEvent::Enter)
        {
    
    
           // auto evt = dynamic_cast<QEnterEvent *>(event);
          //  systemStatisticsWidget->popWindow(evt->globalPosition().x(),evt->globalPosition().y(),500,400);

        }
        else if(event->type() == QEvent::Leave)
        {
    
    
           // systemStatisticsWidget->close();
        }
    }
    return QMainWindow::eventFilter(obj,event);
}

6. プロジェクトのダウンロードを完了する

リンクをクリックして
ビルド バージョンをダウンロードします
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/qq_15181569/article/details/132730079