开源 C++ QT Widget 开发(十二)图表--环境监测表盘

发布于:2025-09-04 ⋅ 阅读:(18) ⋅ 点赞:(0)

  文章的目的为了记录使用C++ 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
 
相关链接:

开源 C++ QT Widget 开发(一)工程文件结构-CSDN博客

开源 C++ QT Widget 开发(二)基本控件应用-CSDN博客

开源 C++ QT Widget 开发(三)图表--波形显示器-CSDN博客

开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑-CSDN博客

 开源 C++ QT Widget 开发(五)通讯--串口调试-CSDN博客

开源 C++ QT Widget 开发(六)通讯--TCP调试-CSDN博客

开源 C++ QT Widget 开发(七)线程--多线程及通讯-CSDN博客

开源 C++ QT Widget 开发(八)网络--Http文件下载-CSDN博客

开源 C++ QT Widget 开发(九)图表--仪表盘-CSDN博客

开源 C++ QT Widget 开发(十)IPC进程间通信--共享内存-CSDN博客

开源 C++ QT Widget 开发(十一)进程间通信--Windows 窗口通信-CSDN博客

开源 C++ QT Widget 开发(十二)图表--环境监测表盘-CSDN博客



推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

内容:环境传感器监测面板

目录:

1.功能介绍

2.核心代码分析

3.所有源码

4.显示效果

一、功能介绍

实时数据监测:显示温度、湿度、PM2.5、光照强度和大气压力

可视化仪表盘:温度和PM2.5使用圆形仪表盘显示,带有彩色刻度

数据卡片:湿度、光照和压力使用卡片式布局

空气质量评级:根据PM2.5值自动显示空气质量等级

实时时钟:显示当前日期和时间

模拟数据更新:每2秒自动生成新的模拟传感器数据

二、核心代码分析

1.抗锯齿渲染:QPainter的Antialiasing确保平滑图形

使用setViewport和setWindow实现坐标系统一化

锥形渐变(QConicalGradient)创建彩色刻度弧

三角函数计算指针角度和位置

保存和恢复 painter 状态确保绘制隔离
 

2.自定义控件:GaugeWidget(仪表盘)和DataCardWidget(数据卡片)

CSS样式:使用QSS实现现代化界面风格

布局管理:嵌套布局实现灵活的界面结构

3.定时器系统:QTimer实现数据刷新和时钟更新

定时器系统:多定时器分别处理数据和时钟更新

三、所有源码

1.mainwindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include <QLabel>
#include <QGridLayout>
#include <QWidget>
#include <QTime>
#include <QVBoxLayout>
#include <QHBoxLayout>

// 自定义仪表盘控件
class GaugeWidget : public QWidget
{
    Q_OBJECT
public:
    explicit GaugeWidget(QWidget *parent = nullptr, const QString &title = "",
                        double minValue = 0, double maxValue = 100,
                        const QString &unit = "", const QColor &color = Qt::blue);
    void setValue(double value);
    void setAlertLevels(double low, double medium, double high);

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    QString m_title;
    double m_minValue;
    double m_maxValue;
    double m_currentValue;
    QString m_unit;
    QColor m_color;
    double m_lowAlert;
    double m_mediumAlert;
    double m_highAlert;
};

// 数据卡片控件
class DataCardWidget : public QWidget
{
    Q_OBJECT
public:
    explicit DataCardWidget(QWidget *parent = nullptr,
                           const QString &title = "",
                           const QString &icon = "",
                           const QString &unit = "");
    void setValue(double value);

private:
    QLabel *m_valueLabel;
    QLabel *m_unitLabel;
    QLabel *m_titleLabel;
    QLabel *m_iconLabel;
    QString m_unit;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void updateData();
    void updateTime();

private:
    void setupUI();
    void setupSignals();

    QTimer *m_dataTimer;
    QTimer *m_clockTimer;

    // 主控件
    QWidget *m_centralWidget;
    QVBoxLayout *m_mainLayout;

    // 标题区域
    QLabel *m_titleLabel;
    QLabel *m_timeLabel;

    // 仪表盘区域
    QHBoxLayout *m_gaugeLayout;
    GaugeWidget *m_temperatureGauge;
    GaugeWidget *m_airQualityGauge;
    QLabel *m_airQualityLabel;

    // 数据卡片区域
    QHBoxLayout *m_dataCardLayout;
    DataCardWidget *m_humidityCard;
    DataCardWidget *m_lightCard;
    DataCardWidget *m_pressureCard;
};

#endif // MAINWINDOW_H

2.mainwindow.cpp文件

#include "mainwindow.h"
#include <QPainter>
#include <QFont>
#include <QFontDatabase>
#include <QLinearGradient>
#include <QtMath>
#include <QRandomGenerator>

// GaugeWidget 实现
GaugeWidget::GaugeWidget(QWidget *parent, const QString &title,
                         double minValue, double maxValue,
                         const QString &unit, const QColor &color)
    : QWidget(parent), m_title(title), m_minValue(minValue), m_maxValue(maxValue),
      m_currentValue(minValue), m_unit(unit), m_color(color),
      m_lowAlert(0.3), m_mediumAlert(0.6), m_highAlert(0.8)
{
    setMinimumSize(250, 250); // 稍微调小一点
}

void GaugeWidget::setValue(double value)
{
    m_currentValue = qBound(m_minValue, value, m_maxValue);
    update();
}

void GaugeWidget::setAlertLevels(double low, double medium, double high)
{
    m_lowAlert = low;
    m_mediumAlert = medium;
    m_highAlert = high;
}

void GaugeWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    int side = qMin(width(), height());
    painter.setViewport((width() - side) / 2, (height() - side) / 2, side, side);
    painter.setWindow(-50, -50, 100, 100);

    // 绘制外圆
    painter.setPen(Qt::NoPen);
    QLinearGradient gradient(-40, -40, 40, 40);
    gradient.setColorAt(0, QColor(30, 30, 40));
    gradient.setColorAt(1, QColor(50, 50, 60));
    painter.setBrush(gradient);
    painter.drawEllipse(-40, -40, 80, 80);

    // 绘制刻度
    painter.save();
    painter.setPen(QPen(Qt::white, 0.5));
    for (int i = 0; i <= 10; ++i) {
        painter.drawLine(30, 0, 35, 0);
        painter.rotate(27);
    }
    painter.restore();

    // 绘制彩色弧
    QConicalGradient conicGradient(0, 0, -90);
    conicGradient.setColorAt(0.0, Qt::green);
    conicGradient.setColorAt(0.4, Qt::yellow);
    conicGradient.setColorAt(0.8, Qt::red);

    QPen arcPen;
    arcPen.setWidth(5);
    arcPen.setBrush(conicGradient);
    painter.setPen(arcPen);
    painter.drawArc(-30, -30, 60, 60, 30 * 16, 240 * 16);

    // 绘制指针 - 使用科技蓝色 (#3a7eff)
    QColor techBlue(58, 126, 255); // 科技蓝色
    painter.save();
    double valueRatio = (m_currentValue - m_minValue) / (m_maxValue - m_minValue);
    double angle = 30 + valueRatio * 240; // 从30度到270度
    painter.rotate(angle);
    painter.setPen(QPen(techBlue, 1));
    painter.setBrush(techBlue);
    QPointF points[3] = {QPointF(0, -5), QPointF(30, 0), QPointF(0, 5)};
    painter.drawPolygon(points, 3);
    painter.restore();

    // 绘制中心圆
    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor(40, 40, 50));
    painter.drawEllipse(-10, -10, 20, 20);

    // 绘制文本 - 调小字体
    painter.setPen(Qt::white);
    QFont font = painter.font();
    font.setPointSize(4); // 调小字体
    painter.setFont(font);

    painter.drawText(-40, -45, 80, 20, Qt::AlignCenter, m_title);

    font.setPointSize(6); // 调小字体
    font.setBold(true);
    painter.setFont(font);
    painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter,
                     QString::number(m_currentValue, 'f', 1));

    font.setPointSize(4); // 调小字体
    font.setBold(false);
    painter.setFont(font);
    painter.drawText(QRect(-20, 10, 40, 10), Qt::AlignCenter, m_unit);
}

// DataCardWidget 实现
DataCardWidget::DataCardWidget(QWidget *parent, const QString &title,
                               const QString &icon, const QString &unit)
    : QWidget(parent), m_unit(unit)
{
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setSpacing(5); // 减小间距

    QHBoxLayout *headerLayout = new QHBoxLayout();
    m_titleLabel = new QLabel(title);
    m_iconLabel = new QLabel(icon);

    QFont font = m_titleLabel->font();
    font.setPointSize(8); // 调小字体
    m_titleLabel->setFont(font);
    m_iconLabel->setFont(font);

    headerLayout->addWidget(m_iconLabel);
    headerLayout->addWidget(m_titleLabel);
    headerLayout->addStretch();

    m_valueLabel = new QLabel("0.0");
    font = m_valueLabel->font();
    font.setPointSize(12); // 调小字体
    font.setBold(true);
    m_valueLabel->setFont(font);
    m_valueLabel->setAlignment(Qt::AlignCenter);

    m_unitLabel = new QLabel(unit);
    m_unitLabel->setAlignment(Qt::AlignCenter);
    font.setPointSize(8); // 调小字体
    m_unitLabel->setFont(font);

    layout->addLayout(headerLayout);
    layout->addWidget(m_valueLabel);
    layout->addWidget(m_unitLabel);

    // 设置卡片样式
    setStyleSheet("DataCardWidget {"
                  "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
                  "stop: 0 #2a2a3a, stop: 1 #1a1a2a);"
                  "border-radius: 8px;"
                  "padding: 8px;"
                  "}");

    m_titleLabel->setStyleSheet("color: #a0a0b0;");
    m_valueLabel->setStyleSheet("color: white;");
    m_unitLabel->setStyleSheet("color: #707090;");
    m_iconLabel->setStyleSheet("color: #3a7eff;"); // 使用科技蓝色
}

void DataCardWidget::setValue(double value)
{
    m_valueLabel->setText(QString::number(value, 'f', 1));
}

// MainWindow 实现
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // 设置窗口属性
    setWindowTitle("环境监测中心");
    resize(900, 600); // 稍微调小窗口尺寸

    // 创建中央部件和主布局
    m_centralWidget = new QWidget(this);
    m_mainLayout = new QVBoxLayout(m_centralWidget);
    m_mainLayout->setSpacing(15); // 减小间距
    m_mainLayout->setContentsMargins(15, 15, 15, 15);

    // 设置背景
    m_centralWidget->setStyleSheet("background-color: #121218;");
    setCentralWidget(m_centralWidget);

    setupUI();
    setupSignals();

    // 启动定时器
    m_dataTimer = new QTimer(this);
    connect(m_dataTimer, &QTimer::timeout, this, &MainWindow::updateData);
    m_dataTimer->start(2000);

    m_clockTimer = new QTimer(this);
    connect(m_clockTimer, &QTimer::timeout, this, &MainWindow::updateTime);
    m_clockTimer->start(1000);

    // 初始化数据
    updateTime();
    updateData();
}

MainWindow::~MainWindow()
{
}

void MainWindow::setupUI()
{
    // 创建标题标签 - 调小字体
    m_titleLabel = new QLabel("环境监测中心");
    m_titleLabel->setAlignment(Qt::AlignCenter);
    m_titleLabel->setStyleSheet("QLabel {"
                                "color: #3a7eff;" // 使用科技蓝色
                                "font-size: 22px;" // 调小字体
                                "font-weight: bold;"
                                "margin: 8px;"
                                "}");

    // 创建时间标签 - 调小字体
    m_timeLabel = new QLabel();
    m_timeLabel->setAlignment(Qt::AlignCenter);
    m_timeLabel->setStyleSheet("QLabel {"
                               "color: #a0a0b0;"
                               "font-size: 12px;" // 调小字体
                               "margin-bottom: 15px;"
                               "}");

    // 创建仪表盘布局
    m_gaugeLayout = new QHBoxLayout();
    m_gaugeLayout->setSpacing(25);

    // 创建温度仪表盘 - 使用科技蓝色
    QColor techBlue(58, 126, 255);
    m_temperatureGauge = new GaugeWidget(nullptr, "温度", -10, 50, "°C", techBlue);
    m_temperatureGauge->setAlertLevels(10, 25, 35);

    // 创建空气质量仪表盘 - 使用科技蓝色
    m_airQualityGauge = new GaugeWidget(nullptr, "PM2.5", 0, 300, "μg/m³", techBlue);
    m_airQualityGauge->setAlertLevels(35, 75, 150);

    // 创建空气质量标签 - 调小字体
    m_airQualityLabel = new QLabel("优");
    m_airQualityLabel->setAlignment(Qt::AlignCenter);
    m_airQualityLabel->setStyleSheet("QLabel {"
                                     "color: #00ff00;"
                                     "font-size: 14px;" // 调小字体
                                     "font-weight: bold;"
                                     "background-color: #202830;"
                                     "border-radius: 8px;"
                                     "padding: 8px;"
                                     "}");

    // 将仪表盘添加到布局
    m_gaugeLayout->addWidget(m_temperatureGauge);

    QVBoxLayout *airLayout = new QVBoxLayout();
    airLayout->setSpacing(10);
    airLayout->addWidget(m_airQualityGauge);
    airLayout->addWidget(m_airQualityLabel);
    m_gaugeLayout->addLayout(airLayout);

    // 创建数据卡片布局
    m_dataCardLayout = new QHBoxLayout();
    m_dataCardLayout->setSpacing(15);

    // 创建数据卡片
    m_humidityCard = new DataCardWidget(nullptr, "湿度", "💧", "%RH");
    m_lightCard = new DataCardWidget(nullptr, "光照", "☀️", "Lux");
    m_pressureCard = new DataCardWidget(nullptr, "气压", "🌪️", "hPa");

    // 将卡片添加到布局
    m_dataCardLayout->addWidget(m_humidityCard);
    m_dataCardLayout->addWidget(m_lightCard);
    m_dataCardLayout->addWidget(m_pressureCard);

    // 将所有部件添加到主布局
    m_mainLayout->addWidget(m_titleLabel);
    m_mainLayout->addWidget(m_timeLabel);
    m_mainLayout->addLayout(m_gaugeLayout);
    m_mainLayout->addLayout(m_dataCardLayout);
    m_mainLayout->addStretch();
}

void MainWindow::setupSignals()
{
    // 连接信号和槽
}

void MainWindow::updateData()
{
    // 生成模拟数据
    double temperature = 20.0 + QRandomGenerator::global()->bounded(15.0);
    double pm25 = QRandomGenerator::global()->bounded(150.0);
    double humidity = 30.0 + QRandomGenerator::global()->bounded(50.0);
    double light = QRandomGenerator::global()->bounded(1000.0);
    double pressure = 1000.0 + QRandomGenerator::global()->bounded(20.0);

    // 更新仪表盘
    m_temperatureGauge->setValue(temperature);
    m_airQualityGauge->setValue(pm25);

    // 更新空气质量标签
    QString airQuality;
    QString color;
    if (pm25 <= 35) {
        airQuality = "优";
        color = "#00ff00";
    } else if (pm25 <= 75) {
        airQuality = "良";
        color = "#ffff00";
    } else if (pm25 <= 115) {
        airQuality = "轻度污染";
        color = "#ff7f00";
    } else {
        airQuality = "污染";
        color = "#ff0000";
    }

    m_airQualityLabel->setText(airQuality);
    m_airQualityLabel->setStyleSheet(QString("QLabel {"
                                             "color: %1;"
                                             "font-size: 14px;"
                                             "font-weight: bold;"
                                             "background-color: #202830;"
                                             "border-radius: 8px;"
                                             "padding: 8px;"
                                             "}").arg(color));

    // 更新数据卡片
    m_humidityCard->setValue(humidity);
    m_lightCard->setValue(light);
    m_pressureCard->setValue(pressure);
}

void MainWindow::updateTime()
{
    QDateTime current = QDateTime::currentDateTime();
    m_timeLabel->setText(current.toString("yyyy-MM-dd hh:mm:ss"));
}

四、显示效果


网站公告

今日签到

点亮在社区的每一天
去签到