qt usa QCustomplot para dibujar gráficos de uso de memoria y CPU

1. Introducción a QCustomPlot

            QCustomPlot es una biblioteca de gráficos Qt C++ de código abierto para visualizar datos. La biblioteca proporciona muchos tipos de gráficos personalizables, incluidos diagramas de dispersión, diagramas de líneas, histogramas y diagramas de contorno. También admite dibujos personalizados, lo que le permite crear elementos de cualquier forma y tamaño y hacerlos interactuar con otros elementos. QCustomPlot es fácil de integrar en aplicaciones Qt existentes y admite interacciones de gráficos comunes como selección del mouse, zoom y panorámica. Además, puede generar imágenes de alta calidad y resultados en PDF. La documentación de QCustomplot detalla su uso y API, lo que la convierte en una herramienta poderosa y conveniente para los desarrolladores que necesitan agregar capacidades de visualización de datos a sus aplicaciones.

2. Vista previa de la interfaz

Insertar descripción de la imagen aquí

3. Implementación del código

1. Descarga de Qcustomplot

Puede descargar QCustomPlot desde el sitio web oficial de QCustomPlot (https://www.qcustomplot.com/index.php/download). En el sitio web puede encontrar la última versión estable, así como enlaces de descarga para todas las versiones históricas.
Insertar descripción de la imagen aquí

2. Agregue Qcustomplot a su proyecto

Descomprima el paquete comprimido Qcustomplot descargado, luego cópielo qcustomplot.cppy qcustomplot.ha su proyecto
Insertar descripción de la imagen aquí
, luego haga clic derecho en el proyecto -> Agregar archivos existentes a su proyecto.
Insertar descripción de la imagen aquí

3. Modificación de archivos de proyecto

Abra el archivo .pro del proyecto y agregue printsupportsoporte para componentes.
Nota: Si la versión de su compilador es 6.5, también debe agregar QMAKE_CXXFLAGS += -Wa,-mbig-obj,esta oración, de la siguiente manera
Insertar descripción de la imagen aquí

4. Escritura de código

a. Crear una nueva clase

Primero, cree una nueva clase de interfaz de diseñador, luego coloque un widget en la interfaz de diseñador y luego actualícelo a QCustomPlot, de la siguiente manera:
Insertar descripción de la imagen aquí

4. Código fuente del proyecto

archivo .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

La clase AxisTag es la pequeña etiqueta en el lado derecho de la imagen que muestra el valor único.
Archivo .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. Escribir código de prueba

1. Primero defina una interfaz y un temporizador en mainwindow.h

    SystemStatisticsWidget *systemStatisticsWidget;
    QTimer mDataTimer;

Insertar descripción de la imagen aquí

2. Cree una instancia y conecte la ranura en mainwindow.cpp y agregue datos con regularidad.

#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. Descarga completa del proyecto

Haga clic en el enlace para descargar
la versión de compilación.
Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_15181569/article/details/132730079
Recomendado
Clasificación