Real-Time CPU Temperature Monitoring with QCustomPlot in Qt

When developing system monitoring applications, visualizing hardware metrics like CPU temperature is crucial. While specialized tools like CPU-Z or HWMonitor use low-level drivers for hardware access, Qt provides a more accessible approach through system APIs and libraries like QCustomPlot for data visualization. This article demonstrates how to create real-time CPU temperature monitoring graphs using QCustomPlot in a Windows environment.

Introduction to QCustomPlot

QCustomPlot is a comprehensive 2D plotting libray for Qt applications that enables developers to create high-quality graphs and charts with minimal effort. It supports various chart types, real-time data updates, and extensive customization options.

Key features of QCustomPlot include:

  • Multiple chart types (line, scatter, bar, pie, histogram)
  • Advenced data visualization capabilities
  • Customizable axes and grid
  • Interactive elements (zoom, pan, selection)
  • Export functionality for various image formats
  • Layer management for complex visualizations
  • Real-time data streaming support

The library requires only the qcustomplot.h and qcustomplot.cpp files and the QT += printsupport directive in the project file.

System Setup

To implement CPU temperature monitoring, we'll need:

  • Qt Creator with MSVC2022 compiler
  • QCustomPlot library integration
  • System API access for temperature data
  • Timer mechanism for periodic updates

Visualization Style 1: Basic Temperature Graph

This style creates a clean, informative temperature graph with time-based x-axis and gradient backgrounds.

Plot Configuration

void configurePlot(QCustomPlot* plot) {
    // Configure grid appearance
    plot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
    plot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
    plot->xAxis->grid()->setSubGridVisible(true);
    plot->yAxis->grid()->setSubGridVisible(true);

    // Enable interactions
    plot->setInteractions(QCP::iSelectLegend | QCP::iSelectPlottables);

    // Set axis ranges
    plot->xAxis->setRange(QDateTime::currentSecsSinceEpoch() - 120, QDateTime::currentSecsSinceEpoch());
    plot->yAxis->setRange(0, 100);

    // Configure axis labels
    plot->xAxis->setLabel("Time (S)");
    plot->yAxis->setLabel("Temperature (°C)");

    // Add title
    plot->plotLayout()->insertRow(0);
    QCPTextElement* title = new QCPTextElement(plot, "CPU Temperature Monitor", QFont("sans", 17, QFont::Bold));
    plot->plotLayout()->addElement(0, 0, title);

    // Enable legend
    plot->legend->setVisible(true);
    plot->legend->setSelectableParts(QCPLegend::spItems);
    plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop|Qt::AlignLeft);
}

Time-Based X-Axis

void setupTimeAxis(QCustomPlot* plot) {
    QSharedPointer<QCPAxisTickerDateTime> ticker(new QCPAxisTickerDateTime);
    ticker->setDateTimeSpec(Qt::LocalTime);
    ticker->setTickCount(5);
    ticker->setDateTimeFormat("yyyy-MM-dd \n hh:mm:ss");
    plot->xAxis->setTicker(ticker);
}

Interactive Elements

void addInteractiveElements(QCustomPlot* plot) {
    // Vertical line for mouse tracking
    QPointer<QCPItemLine> verticalLine = new QCPItemLine(plot);
    verticalLine->start->setType(QCPItemPosition::ptPlotCoords);
    verticalLine->start->setCoords(QDateTime::currentSecsSinceEpoch() + 5, 0);
    verticalLine->end->setType(QCPItemPosition::ptPlotCoords);
    verticalLine->end->setCoords(QDateTime::currentSecsSinceEpoch() + 5, 100);
    verticalLine->setPen(QPen(Qt::red, 2));

    // Text box for displaying values
    QPointer<QCPItemText> infoBox = new QCPItemText(plot);
    infoBox->setPositionAlignment(Qt::AlignRight|Qt::AlignTop);
    infoBox->position->setType(QCPItemPosition::ptAxisRectRatio);
    infoBox->position->setCoords(0.4, 0.05);
    infoBox->setText("Temperature: -- °C");
    infoBox->setPen(QPen(Qt::white));
    infoBox->setPadding(QMargins(2,2,2,2));
    infoBox->position->setParentAnchorX(verticalLine->anchor("start"));
    infoBox->setColor(Qt::white);
    infoBox->setBrush(QColor("#383F5B"));
    infoBox->setVisible(false);
}

Gradient Effects

QPen createGradientPen(const QSize& size) {
    QLinearGradient gradient(0, 15, 0, size.height() - 25);
    gradient.setColorAt(0, QColor(255, 255, 255, 0));
    gradient.setColorAt(0.5, Qt::black);
    gradient.setColorAt(1, QColor(255, 255, 255, 0));
    QBrush brush(gradient);
    
    QPen pen;
    pen.setColor(Qt::black);
    pen.setWidth(3);
    pen.setBrush(brush);
    return pen;
}

QBrush createGraphBrush(const QSize& size, const QColor& color) {
    QLinearGradient gradient(0, 10, 0, size.height() - 20);
    gradient.setColorAt(0, color);
    gradient.setColorAt(1, QColor(255, 255, 255, 0));
    return QBrush(gradient);
}

Graph Initialization

void initializeGraphs(QCustomPlot* plot, const QStringList& coreNames) {
    QVector<QColor> colors;
    QVector<QCPGraph*> graphs;

    for (int i = 0; i < coreNames.size(); ++i) {
        QCPGraph* graph = plot->addGraph();
        
        // Generate random color for each core
        QColor coreColor(qrand() % 245 + 10, qrand() % 245 + 10, qrand() % 245 + 10);
        colors.append(coreColor);
        
        // Configure graph appearance
        QPen pen;
        pen.setColor(coreColor);
        pen.setWidthF(2);
        graph->setPen(pen);
        graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 2));
        graph->setBrush(createGraphBrush(plot->size(), coreColor));
        graph->setName(coreNames[i]);
        graph->setLineStyle(QCPGraph::lsLine);
        
        // Add layer for proper rendering order
        plot->addLayer(coreNames[i].toStdString().c_str(), plot->layer("main"), QCustomPlot::limAbove);
        graph->setLayer(coreNames[i].toStdString().c_str());
        
        graphs.append(graph);
    }
    
    plot->replot();
}

Data Update Mechanism

void updateTemperatureData(QCustomPlot* plot, qint64 timestamp, const QList<double>& temperatures) {
    plot->xAxis->setRange(timestamp, 120, Qt::AlignRight);
    
    for (int i = 0; i < temperatures.size() && i < plot->graphCount(); ++i) {
        plot->graph(i)->addData(timestamp, temperatures[i]);
    }
    
    plot->replot();
}

Visualization Style 2: Detailed Temperature Display

This style adds additional information displays and axis tags for precise temperature readings.

Enhanced Graph Initialization

void initializeDetailedGraphs(QCustomPlot* plot, const QStringList& coreNames) {
    QVector<QColor> colors;
    QVector<QCPGraph*> graphs;
    QVector<AxisTag*> axisTags;

    for (int i = 0; i < coreNames.size(); ++i) {
        QCPGraph* graph = plot->addGraph();
        
        // Generate random color
        QColor coreColor(qrand() % 245 + 10, qrand() % 245 + 10, qrand() % 245 + 10);
        colors.append(coreColor);
        
        // Configure graph
        QPen pen;
        pen.setColor(coreColor);
        pen.setWidthF(2);
        graph->setPen(pen);
        graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 2));
        graph->setBrush(createGraphBrush(plot->size(), coreColor));
        graph->setName(coreNames[i]);
        graph->setLineStyle(QCPGraph::lsLine);
        
        // Add secondary axis for temperature display
        QCPAxis* tempAxis = plot->axisRect()->addAxis(QCPAxis::atRight);
        tempAxis->setRange(0, 100);
        tempAxis->setTickLabels(false);
        tempAxis->setPadding(55);
        
        // Create axis tag for temperature display
        AxisTag* tag = new AxisTag(tempAxis);
        tag->setPen(pen);
        axisTags.append(tag);
        
        // Add layer
        plot->addLayer(coreNames[i].toStdString().c_str(), plot->layer("main"), QCustomPlot::limAbove);
        graph->setLayer(coreNames[i].toStdString().c_str());
        
        graphs.append(graph);
    }
    
    plot->replot();
}

Enhanced Data Update

void updateDetailedTemperatureData(QCustomPlot* plot, qint64 timestamp, const QList<double>& temperatures) {
    plot->xAxis->setRange(timestamp, 120, Qt::AlignRight);
    
    for (int i = 0; i < temperatures.size() && i < plot->graphCount(); ++i) {
        plot->graph(i)->addData(timestamp, temperatures[i]);
        axisTags[i]->updatePosition(temperatures[i]);
        axisTags[i]->setText(QString::number(temperatures[i], 'f', 2));
    }
    
    plot->replot();
}

Temperature Data Acquisition

To obtain CPU temperature data in Windows, you can use the Windows Management Instrumentation (WMI) API or specialized libraries that provide access to system sensors. The data acquisition should be performed in a separate thread to avoid blocking the UI, with results passed to the main thread for visualization.

This implementation provides a robust foundation for real-time CPU temperature monitoring with customizable visualization options, suitable for system monitoring applications or performance analysis tools.

Tags: qcustomplot Qt CPU monitoring Data Visualization real-time plotting

Posted on Sun, 23 Aug 2026 16:05:06 +0000 by Gregg