🎩 欢迎来到技术探索的奇幻世界👨💻
📜 个人主页:@一伦明悦-CSDN博客
✍🏻 作者简介:C++软件开发、Python机器学习爱好者
🗣️ 互动与支持:💬评论 👍🏻点赞 📂收藏 👀关注+
如果文章有所帮助,欢迎留下您宝贵的评论!
欢迎点赞加收藏支持我,点击关注,一起进步!
前言
本篇在该篇博客的基础上,继续进行系统功能的完善操作,比如,一般生产国臣各种,跟定希望机器是能自动化的,这样即使工作人员不在,生产依然在进行。
【C++ QT项目实战-02】---- C++ QT系统实现基于QT调用RESTful接口访问JSON文件中数据-CSDN博客文章浏览阅读457次,点赞5次,收藏3次。本篇在做项目的基础上进行了项目中难点的一些总结,我们都知道,在如今大数据时代下,数据对项目系统开发起到决定性的作用,可以帮助企业实现实时决策、提升用户体验、实现业务智能、提高系统性能、提供定制化服务和增强业务竞争力等方面的优势,有利于项目系统的发展和成功。因此,在项目系统开发过程中,需要充分重视数据的快速读取和处理能力,以满足日益增长的数据需求和用户期望。https://blog.csdn.net/m0_59951855/article/details/139065776
项目中的计算等功能已经是自动化模式的,这里的难题就是如何在读取数据的过程中也实现自动化模式,当然,为了便于操作,不仅需要自动化模式,也需要随时可以切换到手动模式。
这里包含了以下几个难点:
(1)主系统线程与计算线程是双线程运行,两种模式下,如何进行线程通信?
(2)自动模式下,系统访问平台的方式,或者说是否需要给定时间,定时访问平台?而不是不停歇的访问。
(3)自动模式下如何实现系统读完数据直接进行计算,手动模式下又怎样切换?这些也需要进行解决。
(4)如何判断平台中是否存在数据,当判断之后,又该怎样运行?
带着这四个问题,将进行详细分析如何实现这些功能,并给出代码解释和功能演示。
正文
01- 双模式下,主线程与计算线程通信实现
主界面上的自动和手动两种模式通过控件进行选择,当选择自动模式时,主线程发送一个信号,通过信号与槽函数的方式与计算线程中的函数进行连接。
在自动模式下,发送信号 send_cmBox_ToWFC,计算线程中使用函数cmBox_switch()和model_switch()来接收信号并实现各种功能。在手动模式下,发送信号 send_modelcmBox_ToWFC,计算线程中使用函数model_switch_0来接收信号。
这种设计模式可以让你在不同模式下灵活地控制计算线程的行为,实现自动化或手动化操作。
mainwindow.h文件#ifndef MAINWINDOW_H
#define MAINWINDOW_H
/*#include "Mp_Pred.h"*/
#include"ui_mainwindow.h"
#include <QMainWindow>
#include <QLabel>#include "spdlog/fmt/ostr.h"
#include "Zanj_WFC_ctrl.h"
#include <QVariant>
#include "wfc_to_main.h"#include <QtSql/QtSql>
#include <QDateTime>
#include <QTimer>
#include <qtextcodec.h>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QBarSeries>
#include <QtCharts/QBarSet>
#include <QtCharts/QLegend>
#include <QtCharts/QBarCategoryAxis>
#include <QMouseEvent>
//一定要声明!!!
#include"dialog_data_log.h"namespace Ui {class MainWindow;
}};
class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();Zanj_WFC_ctrl * m_Zanj_WFC_ctrl; // 预报计算的类QThread * m_Zanj_WFC_ctrl_Thread; //m_Mp_Pred将被移动到此线程执行void connectZanj_WFC_ctrl(Zanj_WFC_ctrl *m_Zanj_WFC_ctrl);signals:void send_cmBox_ToWFC();void send_modelcmBox_ToWFC();mainwindow.cpp文件#include <QTimer>
#include <time.h>
#include <QLabel>
#include <QValueAxis>
#include <QMargins>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QBarSeries>
#include <QtCharts/QBarSet>
#include <QtCharts/QLegend>
#include <QtCharts/QBarCategoryAxis>
#include <ctime> using namespace std::literals;
// using namespace fmt;
using namespace std;
namespace spd = spdlog;
auto console_mainWindow = spd::stdout_color_mt("主界面控制台");
auto rotating_logger_mainWindow = spdlog::rotating_logger_mt("baori_CAO8_Winmain_rotating", "logs/baori_CAO8_rotating.logger", 1048576 * 5, 12);MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);OpenDatabase();//Matlab_mcl_Init();setWindowTitle(QString::fromLocal8Bit("主系统")); // 此处写应用程序在标题栏上显示的名称setStyleSheet("background - color:pink; ");reshow();data_log_tblview();connect(this, &MainWindow::send_cmBox_ToWFC, m_Zanj_WFC_ctrl, &Zanj_WFC_ctrl::cmBox_switch);connect(this, &MainWindow::send_cmBox_ToWFC, m_Zanj_WFC_ctrl, &Zanj_WFC_ctrl::model_switch);connect(this, &MainWindow::send_modelcmBox_ToWFC, m_Zanj_WFC_ctrl, &Zanj_WFC_ctrl::model_switch_0);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::deploy_cmBox_switch()
{if (ui->deploy_cmBox->currentText() == QString::fromLocal8Bit("自动模式")){ui->Iplate4j_IP_QLE->setText("127.0.0.1");ui->model_PC_IP_QLE->setText("127.0.0.1");emit send_cmBox_ToWFC();}else if (ui->deploy_cmBox->currentText() == QString::fromLocal8Bit("手动模式")){emit send_modelcmBox_ToWFC();}
}
02-cmBox_switch()函数实现
这里接受信号的计算线程的函数分为两个,第一个cmBox_switch()函数是实现打开配置文件和定时访问数据,定时访问数据这里加入死循环,设置30s的时间间隔。
startSystem()函数的这段代码是一个无限循环,在每次循环中执行以下操作:
调用
OnGETSlot()
函数:这个函数用于执行数据读取和预测的操作。具体实现可能涉及从网络或文件系统中读取数据,并对数据进行处理和预测。调用
this_thread::sleep_for(chrono::seconds(30))
:这行代码会使当前线程暂停执行,模拟定时器或轮询间隔。在这个例子中,线程会休眠30秒钟,然后再次执行循环中的操作。整体来说,这段代码实现了一个简单的定时器功能,每隔30秒钟执行一次数据读取和预测的操作,然后再次休眠30秒钟,循环执行这个过程
计算线程.cpp文件void Zanj_WFC_ctrl::cmBox_switch()
{configuration_read();startSystem();
}bool Zanj_WFC_ctrl::configuration_read()
{string err;QFile config_ini("config.ini");//QFile config_ini("config_baori.ini"); 打开baori配置文件,如果需要访问宝日大数据平台,就需要打开baori配置文件if (!config_ini.open(QIODevice::ReadOnly | QIODevice::Text)){console_WFC_thread->critical("配置文件config.ini不能打开!");rlogger_WFC_thread->critical("配置文件config.ini不能打开!");// std::cout << "configuration.ini Open failed." << endl;return false;}console_WFC_thread->info("配置文件config.ini已打开! ");rlogger_WFC_thread->info("配置文件config.ini已打开! ");QTextStream config_txtInput(&config_ini);QString config_lineStr;config_lineStr = config_txtInput.readLine();config_lineStr = config_txtInput.readLine();clientID = config_lineStr.mid(9);config_lineStr = config_txtInput.readLine();clientSecret = config_lineStr.mid(13);config_lineStr = config_txtInput.readLine();serverIP = config_lineStr.mid(9);config_lineStr = config_txtInput.readLine();serviceID_get = config_lineStr.mid(14);config_lineStr = config_txtInput.readLine();serviceID_post = config_lineStr.mid(15);config_lineStr = config_txtInput.readLine();name = config_lineStr.mid(5);config_lineStr = config_txtInput.readLine();unit = config_lineStr.mid(5);config_lineStr = config_txtInput.readLine();user_ID = config_lineStr.mid(8);config_lineStr = config_txtInput.readLine();companyCode = config_lineStr.mid(12);config_lineStr = config_txtInput.readLine();mssql_serverName = config_lineStr.mid(17);config_lineStr = config_txtInput.readLine();mssql_dbName = config_lineStr.mid(13);config_lineStr = config_txtInput.readLine();mssql_username = config_lineStr.mid(15);config_lineStr = config_txtInput.readLine();mssql_pwd = config_lineStr.mid(10);config_lineStr = config_txtInput.readLine();mssql_datasource = config_lineStr.mid(17);return true;
}void Zanj_WFC_ctrl::startSystem() {while (true) {// 每隔一定时间执行一次数据读取和预测OnGETSlot();//Temp_KNNval_Auto_Cal();// 休眠一段时间,模拟定时器或轮询间隔this_thread::sleep_for(chrono::seconds(30)); // 30秒钟间隔}
}
03-model_switch()函数实现
实现另一个函数之前,先定义了一个全局变量,用于设置工作模式,这里设置的是,当变量为0,为手动模式,变量为1,为自动模式,在读取数据函数那里,加入if判断语句,如果变量为1,则直接进行计算,否则,需要手动计算
如果变量为1,直接调用该函数Temp_KNNval_Auto_Cal()进行计算,如果为0,则手动操作进行计算。
计算线程.cpp文件void Zanj_WFC_ctrl::json_doc_get_parse()
{//总的思路是:对象.value(),如果取到string、int、double类型 就直接.toString()等输出;//如果取到object或array类型 ,就通过toObject()或toArray() 转到对象或数组类型,接着取值。。循环if (json_doc_get.isNull()){console_WFC_thread->critical("unable to parse! ");rlogger_WFC_thread->critical("unable to parse! ");}else{console_WFC_thread->info("parse start! ");rlogger_WFC_thread->info("parse start! ");}QJsonObject::Iterator it;for (it = doc_get_Obj.begin(); it != doc_get_Obj.end(); ++it) {HdglPredict tempData;QString aentid, atentid, atime, acode, agrade, asource;float ahthick, athick, awidth, CT_TMP, FT_TMP, DSH, SPEED, TPM;float C, Si, Mn, P, S, Cu, Ni, Cr, Mo, Nb, Ti, B, N, Al;int st_product_no;QString zoneKey = it.key();QJsonObject zoneObj = it.value().toObject();// 检查钢卷是否已经读取过,如果已经读取过,则跳过if (readCoils.contains(zoneKey)){console_WFC_thread->warn("文件里没有其他钢卷! ");continue;}// 将已读取的钢卷添加到集合中readCoils.insert(zoneKey);aentid = zoneObj["aentid"].toString();atentid = zoneObj["atentid"].toString();atime = zoneObj["atime"].toString();acode = zoneObj["acode"].toString();agrade = zoneObj["agrade"].toString();asource = zoneObj["asource"].toString();tempData.ZoneKey = zoneKey;tempData.ENTID = aentid;tempData.AENTID = atentid;tempData.ATIME = atime;tempData.ST_code = acode;tempData.ST_grade = agrade;tempData.ST_source = asource;tempData.CGL_SPEED_INPUT = SPEED;tempData.SPM_ELONG_INPUT = TPM;tempData.st_product_no = st_product_no_determin();// 将结构体对象添加到容器中hdglPredictList.append(tempData);strt_hdgl_predict.ENTID = aentid;strt_hdgl_predict.AENTID = atentid;strt_hdgl_predict.ATIME = atime;strt_hdgl_predict.ST_code = acode;strt_hdgl_predict.ST_grade = agrade;strt_hdgl_predict.ST_source = asource;strt_hdgl_predict.CGL_SPEED_INPUT = SPEED;strt_hdgl_predict.SPM_ELONG_INPUT = TPM;if (model_switch_num == 1){Temp_KNNval_Auto_Cal();} else{continue;}}}void Zanj_WFC_ctrl::model_switch() {model_switch_num = 1;}
void Zanj_WFC_ctrl::model_switch_0() {model_switch_num = 0;}
04-数据存在判断操作实现
最后实现系统对平台是否存在新的数据的判断,定义了一个字符串变量readCoils,用于存储已经读取的钢卷,对于已经读取过的钢卷,直接跳过,不进行计算,若是没有钢卷存在,系统也会发出警告。通过下面这部分代码判断即可
if (readCoils.contains(zoneKey))
{
console_WFC_thread->warn("文件里没有其他钢卷! ");
continue;
}// 将已读取的钢卷添加到集合中
readCoils.insert(zoneKey);
void Zanj_WFC_ctrl::json_doc_get_parse()
{//总的思路是:对象.value(),如果取到string、int、double类型 就直接.toString()等输出;//如果取到object或array类型 ,就通过toObject()或toArray() 转到对象或数组类型,接着取值。。循环if (json_doc_get.isNull()){console_WFC_thread->critical("unable to parse! ");rlogger_WFC_thread->critical("unable to parse! ");}else{console_WFC_thread->info("parse start! ");rlogger_WFC_thread->info("parse start! ");}QJsonObject::Iterator it;for (it = doc_get_Obj.begin(); it != doc_get_Obj.end(); ++it) {HdglPredict tempData;QString aentid, atentid, atime, acode, agrade, asource;float ahthick, athick, awidth, CT_TMP, FT_TMP, DSH, SPEED, TPM;float C, Si, Mn, P, S, Cu, Ni, Cr, Mo, Nb, Ti, B, N, Al;int st_product_no;QString zoneKey = it.key();QJsonObject zoneObj = it.value().toObject();// 检查钢卷是否已经读取过,如果已经读取过,则跳过if (readCoils.contains(zoneKey)){console_WFC_thread->warn("文件里没有其他钢卷! ");continue;}// 将已读取的钢卷添加到集合中readCoils.insert(zoneKey);aentid = zoneObj["aentid"].toString();atentid = zoneObj["atentid"].toString();atime = zoneObj["atime"].toString();acode = zoneObj["acode"].toString();agrade = zoneObj["agrade"].toString();asource = zoneObj["asource"].toString();tempData.ZoneKey = zoneKey;tempData.ENTID = aentid;tempData.AENTID = atentid;tempData.ATIME = atime;tempData.ST_code = acode;tempData.ST_grade = agrade;tempData.ST_source = asource;tempData.CGL_SPEED_INPUT = SPEED;tempData.SPM_ELONG_INPUT = TPM;tempData.st_product_no = st_product_no_determin();// 将结构体对象添加到容器中hdglPredictList.append(tempData);strt_hdgl_predict.ENTID = aentid;strt_hdgl_predict.AENTID = atentid;strt_hdgl_predict.ATIME = atime;strt_hdgl_predict.ST_code = acode;strt_hdgl_predict.ST_grade = agrade;strt_hdgl_predict.ST_source = asource;strt_hdgl_predict.CGL_SPEED_INPUT = SPEED;strt_hdgl_predict.SPM_ELONG_INPUT = TPM;if (model_switch_num == 1){Temp_KNNval_Auto_Cal();} else{continue;}}}
05-功能演示
下面对上述介绍的功能进行演示:
如下图所示,为系统登录界面,登录之后,才可以对各种功能进行操作。
主界面如下图所示:仅展示部分主界面,分为自动模式和手动模式
选择自动模式之后,就可以持续进行计算,不断进行访问数据文件
当再次访问,发现数据文件中没有数据之后,便会发出警告,如下图所示。
总结
在C++ QT系统中实现自动化读取JSON数据文件的过程有几个好处:
提高效率:自动化读取JSON数据文件可以省去手动操作的时间和精力,提高系统运行效率。特别是在需要定期更新或获取数据时,自动化读取可以保证数据及时可用,减少了人为干预的需要。
减少错误:手动处理JSON数据文件容易出现错误,例如文件路径错误、解析错误等。自动化读取通过编程实现,可以减少人为错误的发生,提高系统的稳定性和可靠性。
增强灵活性:自动化读取JSON数据文件的实现可以根据需求进行定制化,例如可以设置读取频率、读取条件等,从而增强了系统的灵活性和可配置性。
方便维护:通过自动化读取,可以将数据获取的逻辑封装在函数或模块中,便于维护和修改。当需求变化时,只需要修改相应的代码逻辑,而不必修改大量的手动操作步骤。
综上所述,自动化读取JSON数据文件可以提高系统效率、减少错误、增强灵活性,并方便系统的维护和升级。