多个通道采集的数据存放到数据库,然后把数据在取出来放到数组,丛数组里取数据进行绘制曲线图,要实现随时间变化形成动态图,并且要实现可以选择某个通道的某个传感器的数据进行曲线图的显示,写一个使用qt6.2 c++实现的例子,尽可能详细,并且有注释
时间: 2024-03-08 14:46:05 浏览: 131
多曲线采样_labview多曲线_labview_数据采样_
好的,以下是一个使用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();
}
```
阅读全文