多个通道采集的数据存放到数据库,然后把数据在取出来放到数组,丛数组里取数据进行绘制曲线图,要实现随时间变化形成动态图,并且要实现可以选择某个通道的某个传感器的数据进行曲线图的显示,写一个使用qt6.2 c++实现的例子,尽可能详细,并且有注释

时间: 2024-03-08 21:46:05 浏览: 27
好的,以下是一个使用Qt6.2 C++实现的例子,实现多个通道数据存放到数据库,绘制曲线图并实现动态图以及选择某个通道的某个传感器的数据进行曲线图的显示。 1. 创建Qt项目 首先创建一个Qt Widgets Application项目,并在项目中包含Qt Charts模块。 2. 设计UI界面 在Qt Designer中设计一个简单的UI界面,包括一个QComboBox用于选择通道和传感器,一个QChartView用于显示曲线图,一个QPushButton用于开始/停止动态图的绘制,以及一些QLabel和QLineEdit用于显示和输入一些信息。 3. 创建数据库 使用Qt提供的QSqlDatabase类连接到SQLite数据库,并创建一个名为"sensor_data.db"的数据库。可以在程序启动时创建数据库,也可以事先用SQLite Studio等工具创建好数据库。 ```c++ #include <QtSql> // 创建数据库连接 QSqlDatabase db; db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("sensor_data.db"); // 打开数据库 if (!db.open()) { qDebug() << "Failed to open database!"; return; } // 创建数据表 QSqlQuery query; query.exec("CREATE TABLE IF NOT EXISTS SensorData (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "channel INTEGER NOT NULL, " "sensor INTEGER NOT NULL, " "value REAL NOT NULL, " "timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"); ``` 4. 采集数据并存入数据库 使用Qt提供的QSerialPort类或其他方式采集传感器数据,并将数据存入数据库中。下面是一个简单的示例代码: ```c++ // 假设采集到了一个数据,数据来自通道1的传感器2,数值为3.14 int channel = 1; int sensor = 2; double value = 3.14; // 将数据插入到数据库中 QSqlQuery query; query.prepare("INSERT INTO SensorData (channel, sensor, value) VALUES (:channel, :sensor, :value)"); query.bindValue(":channel", channel); query.bindValue(":sensor", sensor); query.bindValue(":value", value); query.exec(); ``` 可以将采集数据的代码放入一个线程中进行,以避免阻塞主线程。 5. 从数据库中取出数据并绘制曲线图 使用Qt Charts模块绘制曲线图,可以先从数据库中取出所有数据,然后根据选择的通道和传感器过滤数据,并将数据添加到曲线图中。下面是一个简单的示例代码: ```c++ // 创建曲线图 QChart *chart = new QChart(); chart->setTitle("Sensor Data"); // 创建坐标轴 QValueAxis *axisX = new QValueAxis(); axisX->setTitleText("Time"); chart->addAxis(axisX, Qt::AlignBottom); QValueAxis *axisY = new QValueAxis(); axisY->setTitleText("Value"); chart->addAxis(axisY, Qt::AlignLeft); // 从数据库中取出数据 QSqlQuery query; query.exec("SELECT * FROM SensorData"); // 遍历数据并添加到曲线图中 while (query.next()) { int channel = query.value("channel").toInt(); int sensor = query.value("sensor").toInt(); double value = query.value("value").toDouble(); QDateTime timestamp = query.value("timestamp").toDateTime(); // 只添加选择的通道和传感器的数据 if (channel == selectedChannel && sensor == selectedSensor) { QLineSeries *series = new QLineSeries(); series->append(timestamp.toMSecsSinceEpoch(), value); chart->addSeries(series); series->attachAxis(axisX); series->attachAxis(axisY); } } // 显示曲线图 QChartView *chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); ui->chartLayout->addWidget(chartView); ``` 6. 实现动态图 在上述代码的基础上,可以使用Qt提供的QTimer类定时取出最新的数据并添加到曲线图中,实现动态图的效果。下面是一个简单的示例代码: ```c++ // 创建QTimer对象 QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [=]() { // 从数据库中取出最新的数据 QSqlQuery query; query.exec("SELECT * FROM SensorData ORDER BY timestamp DESC LIMIT 1"); query.next(); int channel = query.value("channel").toInt(); int sensor = query.value("sensor").toInt(); double value = query.value("value").toDouble(); QDateTime timestamp = query.value("timestamp").toDateTime(); // 只添加选择的通道和传感器的数据 if (channel == selectedChannel && sensor == selectedSensor) { // 遍历曲线图的系列并找到对应的系列 QList<QAbstractSeries *> seriesList = chart->series(); for (int i = 0; i < seriesList.size(); ++i) { QLineSeries *series = qobject_cast<QLineSeries *>(seriesList.at(i)); if (series->name() == QString("%1-%2").arg(channel).arg(sensor)) { // 在系列末尾添加新的数据点 series->append(timestamp.toMSecsSinceEpoch(), value); break; } } } }); timer->start(1000); // 每秒钟更新一次 ``` 7. 实现选择通道和传感器的功能 使用QComboBox和信号槽机制,实现选择通道和传感器的功能。下面是一个简单的示例代码: ```c++ // 创建QComboBox对象并添加选项 QComboBox *channelComboBox = new QComboBox(); channelComboBox->addItem("Channel 1", 1); channelComboBox->addItem("Channel 2", 2); connect(channelComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) { selectedChannel = channelComboBox->currentData().toInt(); updateChart(); // 更新曲线图 }); ui->channelLayout->addWidget(channelComboBox); QComboBox *sensorComboBox = new QComboBox(); sensorComboBox->addItem("Sensor 1", 1); sensorComboBox->addItem("Sensor 2", 2); connect(sensorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) { selectedSensor = sensorComboBox->currentData().toInt(); updateChart(); // 更新曲线图 }); ui->sensorLayout->addWidget(sensorComboBox); ``` 其中,selectedChannel和selectedSensor是类成员变量,表示当前选择的通道和传感器。 8. 完整代码 以下是一个完整的示例代码,包括采集数据、存入数据库、绘制曲线图、实现动态图和选择通道和传感器的功能。需要注意的是,这只是一个简单的示例代码,实际应用中需要更加完善和健壮。 ```c++ #include "mainwindow.h" #include "ui_mainwindow.h" #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> #include <QtCharts> #include <QTimer> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 连接到数据库并创建数据表 QSqlDatabase db; db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("sensor_data.db"); if (!db.open()) { qDebug() << "Failed to open database!"; return; } QSqlQuery query; query.exec("CREATE TABLE IF NOT EXISTS SensorData (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "channel INTEGER NOT NULL, " "sensor INTEGER NOT NULL, " "value REAL NOT NULL, " "timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"); // 创建QComboBox对象并添加选项 QComboBox *channelComboBox = new QComboBox(); channelComboBox->addItem("Channel 1", 1); channelComboBox->addItem("Channel 2", 2); connect(channelComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) { selectedChannel = channelComboBox->currentData().toInt(); updateChart(); // 更新曲线图 }); ui->channelLayout->addWidget(channelComboBox); QComboBox *sensorComboBox = new QComboBox(); sensorComboBox->addItem("Sensor 1", 1); sensorComboBox->addItem("Sensor 2", 2); connect(sensorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) { selectedSensor = sensorComboBox->currentData().toInt(); updateChart(); // 更新曲线图 }); ui->sensorLayout->addWidget(sensorComboBox); // 创建曲线图 chart = new QChart(); chart->setTitle("Sensor Data"); // 创建坐标轴 axisX = new QValueAxis(); axisX->setTitleText("Time"); chart->addAxis(axisX, Qt::AlignBottom); axisY = new QValueAxis(); axisY->setTitleText("Value"); chart->addAxis(axisY, Qt::AlignLeft); // 显示曲线图 chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); ui->chartLayout->addWidget(chartView); // 创建QTimer对象 timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [=]() { // 从数据库中取出最新的数据 QSqlQuery query; query.exec("SELECT * FROM SensorData ORDER BY timestamp DESC LIMIT 1"); query.next(); int channel = query.value("channel").toInt(); int sensor = query.value("sensor").toInt(); double value = query.value("value").toDouble(); QDateTime timestamp = query.value("timestamp").toDateTime(); // 只添加选择的通道和传感器的数据 if (channel == selectedChannel && sensor == selectedSensor) { // 遍历曲线图的系列并找到对应的系列 QList<QAbstractSeries *> seriesList = chart->series(); for (int i = 0; i < seriesList.size(); ++i) { QLineSeries *series = qobject_cast<QLineSeries *>(seriesList.at(i)); if (series->name() == QString("%1-%2").arg(channel).arg(sensor)) { // 在系列末尾添加新的数据点 series->append(timestamp.toMSecsSinceEpoch(), value); break; } } } }); // 开始采集数据 startDataCollection(); } MainWindow::~MainWindow() { // 停止采集数据 stopDataCollection(); delete ui; } void MainWindow::startDataCollection() { // 开始采集数据的线程 dataThread = new QThread(this); dataThread->start(); connect(dataThread, &QThread::finished, dataThread, &QThread::deleteLater); // 创建采集数据的对象并移动到线程中 dataWorker = new DataWorker(); dataWorker->moveToThread(dataThread); // 开始采集数据 connect(dataThread, &QThread::started, dataWorker, &DataWorker::start); // 停止采集数据 connect(this, &MainWindow::stopDataCollectionSignal, dataWorker, &DataWorker::stop); // 存储数据到数据库中 connect(dataWorker, &DataWorker::dataReady, this, [=](int channel, int sensor, double value) { QSqlQuery query; query.prepare("INSERT INTO SensorData (channel, sensor, value) VALUES (:channel, :sensor, :value)"); query.bindValue(":channel", channel); query.bindValue(":sensor", sensor); query.bindValue(":value", value); query.exec(); }); // 更新曲线图 connect(dataWorker, &DataWorker::dataReady, this, &MainWindow::updateChart); } void MainWindow::stopDataCollection() { // 停止采集数据 emit stopDataCollectionSignal(); if (dataThread->isRunning()) { dataThread->quit(); dataThread->wait(); } } void MainWindow::updateChart() { // 清空曲线图 chart->removeAllSeries(); axisX->setRange(0, QDateTime::currentMSecsSinceEpoch()); axisY->setRange(-10, 10); // 从数据库中取出数据 QSqlQuery query; query.exec("SELECT * FROM SensorData"); // 遍历数据并添加到曲线图中 while (query.next()) { int channel = query.value("channel").toInt(); int sensor = query.value("sensor").toInt(); double value = query.value("value").toDouble(); QDateTime timestamp = query.value("timestamp").toDateTime(); // 只添加选择的通道和传感器的数据 if (channel == selectedChannel && sensor == selectedSensor) { QLineSeries *series = new QLineSeries(); series->setName(QString("%1-%2").arg(channel).arg(sensor)); series->append(timestamp.toMSecsSinceEpoch(), value); chart->addSeries(series); series->attachAxis(axisX); series->attachAxis(axisY); } } } DataWorker::DataWorker(QObject *parent) : QObject(parent) { // 初始化随机数生成器 qsrand(QTime::currentTime().msec()); } void DataWorker::start() { // 模拟采集数据,并发射dataReady信号 while (true) { int channel = qrand() % 2 + 1; int sensor = qrand() % 2 + 1; double value = (qrand() % 21 - 10) / 10.0; emit dataReady(channel, sensor, value); QThread::usleep(100); // 模拟采集数据的时间 } } void DataWorker::stop() { // 停止采集数据 QThread::currentThread()->exit(); } ```

相关推荐

最新推荐

recommend-type

Python实现读取txt文件中的数据并绘制出图形操作示例

主要介绍了Python实现读取txt文件中的数据并绘制出图形操作,涉及Python文件读取、数值运算及基于pylab库的图形绘制相关操作技巧,需要的朋友可以参考下
recommend-type

vue+echarts实现动态绘制图表及异步加载数据的方法

vue写的后台管理,需要将表格数据绘制成图表(折线图,柱状图),图表数据都是通过接口请求回来的。这篇文章主要介绍了vue+echarts 动态绘制图表及异步加载数据的相关知识,需要的朋友可以参考下
recommend-type

python matplotlib绘制动态曲线 数据流可视化

很多时候需要在程序运行过程中,查看一些数据的动态变化,最容易想到的是像opencv那样直接循环使用imshow()形成动态画面,但是由于matplotlib中的显示模式是阻塞模式,在plt.show()之后程序就会暂停在那,打开一个...
recommend-type

C#实现鼠标移动到曲线图上显示值的方法

主要介绍了C#实现鼠标移动到曲线图上显示值的方法,是C#的WinForm窗体程序设计中非常实用的技巧,需要的朋友可以参考下
recommend-type

使用java实现各种数据统计图(柱形图,饼图,折线图)

用Jfree实现条形柱状图表,java代码实现。可经常用于报表的制作,代码自动生成后可以自由查看。可以自由配置图表的各个...本文给大家介绍使用java实现各种数据统计图(柱形图,饼图,折线图),需要的朋友可以参考下
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

解释minorization-maximization (MM) algorithm,并给出matlab代码编写的例子

Minorization-maximization (MM) algorithm是一种常用的优化算法,用于求解非凸问题或含有约束的优化问题。该算法的基本思想是通过构造一个凸下界函数来逼近原问题,然后通过求解凸下界函数的最优解来逼近原问题的最优解。具体步骤如下: 1. 初始化参数 $\theta_0$,设 $k=0$; 2. 构造一个凸下界函数 $Q(\theta|\theta_k)$,使其满足 $Q(\theta_k|\theta_k)=f(\theta_k)$; 3. 求解 $Q(\theta|\theta_k)$ 的最优值 $\theta_{k+1}=\arg\min_\theta Q(
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。