基于QT的智慧交通管理系统(Day3)
接上篇本文用于记录学期期末实训内容,尽可能做到保姆级别的详细步骤,跟着做准能成第一次写博客,请多担待声明:我也只是个学习一般的学生,这是记录课上老师讲的内容,我现在只能说这么做能行,但我还不清楚为什么这样做,还在努力学习中。
接上篇
本文用于记录学期期末实训内容,尽可能做到保姆级别的详细步骤,跟着做准能成
第一次写博客,请多担待
声明:我也只是个学习一般的学生,这是记录课上老师讲的内容,我现在只能说这么做能行,但我还不清楚为什么这样做,还在努力学习中。
创建虚拟车辆项目
点击QT Creator左侧的“欢迎”,然后新建工程

Application->QT Widget Application

给孩子起名VirtualCar

类名Virtual,基类Widget

创建完成以后打开VirtualCar.pro,在最上面写上 network
之后打开virtualcar.h,添加头文件#include<QTcpSocket>,然后在下面写

打开virtualcar.cpp,添加一句代码(是127.0.0.1,截图时不知道怎么不小心删掉了)

然后依次运行SmartTraffic和VirtualCar(右击项目点击运行)

在串口助手开着的情况下,会有如下结果


那么现在要解决一个问题就是当再次运行VirtualCar时,客户端不会再向服务器端发出连接请求,服务器也不会再去处理请求
在VIrtualCar.cpp,写一个信号槽的绑定,这个位置
信号与槽的绑定
connect函数的五个参数 信号发送者,信号,信号接收对象,接收到处理的槽函数, 默认值(使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型)
槽函数

connect(&socket,&QTcpSocket::stateChanged,
this,&VirtualCar::slot_stateChanged);
然后打开virtualcar.h,在这里写槽函数
槽的声明:
存取权限(public|private|protected) slots: 槽函数的声明

然后在括号里面补上
QAbstractSocket::SocketState,即
private slots:
void slot_stateChanged(QAbstractSocket::SocketState);
写好后Alt+enter去添加定义
到这里写如下代码:

if(state == QAbstractSocket::UnconnectedState) {
//连接失败 重新链接
socket.connectToHost("127.0.0.1",10086);
this->setWindowTitle("小车 "+QString::number(id)+" - 链接失败");
} else if (state == QAbstractSocket::ConnectedState) {
//链接成功 暂时什么都不干
this->setWindowTitle("小车" +QString::number(id)+" - 链接成功");
QTimer::singleShot(500,[this](){
sendId();
});
sendId();
}else if (state == QAbstractSocket::ConnectingState) {
this->setWindowTitle("小车 "+QString::number(id)+" - 正在链接");
}
先不管报错,然后打开virtualcar.h找到这里

写void sendId(); ,然后Alt+enter添加定义

先添加头文件

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QTimer>
然后在拉到最下面写代码

//发送身份ID
//code表示身份信息,type表示身份,id表示id
QJsonObject obj;
obj.insert("code",20001);//发送身份信息
obj.insert("type","car");
obj.insert("id",id);
socket.write(QJsonDocument(obj).toJson());//消息会发送给服务器
打开virtualcar.h的这里补一个const int id;

上面的这里补一个const类型的引用id

这里也补上(virtualcar.cpp),还有那个id(id)也补上,和图一样就行,这时代码应该就没有报错,但如果有的话,那可能是我有所疏漏,请移步到本节最后的可运行的项目代码,比对一下。
打开VirtualCar的main.cpp,改成这样↓

此时运行成功应该是这样子
打开Smart Traffic的netserver.h在如图位置添加void slot_readyRead();然后Alt+enter添加定义

先在netserver.cpp里添加头文件
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
写上如下代码:
void NetServer::slot_readyRead()
{
QTcpSocket *socket = dynamic_cast<QTcpSocket *>(sender());
QByteArray data = socket->readAll();
QJsonObject obj = QJsonDocument::fromJson(data).object();
if(obj.contains("code")){
//所有信息都会包含该字段
int code = obj.value("code").toInt();
switch(code){
case 20001:
QString type = obj.value("type").toString();
int id = obj.value("id").toInt();
qDebug() << "新的连接为" << type << ", id =" << id;
}
}
}
然后先运行SmartTraffic,后运行Virtual,控制台会输出如下结果,”有新的连接为…id为…“

可运行的
SmartTraffic项目下的common.h
#ifndef COMMON_H
#define COMMON_H
#include<QPoint>
#include <qcolor.h>
#include <qmap.h>
#include <qrect.h>
//道路的构造函数
struct Road{
public:
Road(const int &id,const QPoint &start,const QPoint &end):
id(id),
start(start),
end(end)
{
}
int id;
QPoint start,end;
};
//红绿灯
struct SignalLamp{
public:
int count;//倒计时
// int r_duration;给一个总的持续时间
QColor color;//信号灯的颜色
};
//路口
struct Cross{
public:
Cross(const int &id):id(id){}
Road *N_exit,*N_entrance,
*S_exit,*S_entrance,
*E_exit,*E_entrance,
*W_exit,*W_entrance;
int id;
QRect local;
QList<SignalLamp *>list_sl;//保存路口的信号灯
QMap<Road *,SignalLamp *>road_sl;//可以得到道路和信号灯的关系
};
//小车类
struct Car{
public:
Car(const int &id, Road *road, float duration=0.0):
id(id),
road(road),
duration(duration)
{}
int id;
Road *road;
float duration;//这条路走了多远
};
#endif // COMMON_H
SmartTraffic项目下的main.cpp
#include "mainpage.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Mainpage w;
w.show();
return a.exec();
}
SmartTraffic项目下的mainpage.h
#ifndef MAINPAGE_H
#define MAINPAGE_H
#include "common.h"
#include <QWidget>
#include "netserver.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Mainpage; }
QT_END_NAMESPACE
class Mainpage : public QWidget
{
Q_OBJECT
public:
Mainpage(QWidget *parent = nullptr);
~Mainpage();
protected:
//事件过滤器,重写stackWidget中的绘图事件
bool eventFilter(QObject *obj,QEvent *event);
private slots:
void on_psbt_exit_clicked();
private:
//初始化道路信息
void initRoad();
void initCross();
void initCar();
void initNet();
Ui::Mainpage *ui;
//保存道路信息的容器
QList<Road> list_road;
QList<Cross>list_cross;
QList<Car> list_car;
NetServer ns;//NetServer对象
};
#endif // MAINPAGE_H
SmartTraffic项目下的mainpage.cpp
#include "mainpage.h"
#include "ui_mainpage.h"
#include <QPainter>
Mainpage::Mainpage(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Mainpage)
{
ui->setupUi(this);
//设置文本框名称
this->setWindowTitle(QStringLiteral("智慧交通系统"));
// 访问到资源
QIcon icon(":/icon/Image/mao.png");
// 设置图标
this->setWindowIcon(icon);
ui->page_map->installEventFilter(this);
initRoad();
initCross();
initCar();
initNet();
}
Mainpage::~Mainpage()
{
delete ui;
}
bool Mainpage::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui->page_map) {
if (event->type() == QEvent::Paint) {
// QPainter painter(ui->page_map);
QPainter painter;
QImage img(":/icon/Image/RoadMap.png");
painter.begin(&img);
//画道路
painter.save();
QPen pen;
// pen.setColor(QColor(0,255,0));
pen.setColor(Qt::green);
pen.setWidth(3);
painter.setPen(pen);
for(auto item:list_road){
painter.drawLine(item.start,item.end);
}
painter.restore();
//画路口
for(auto item:list_cross){
painter.drawRect(item.local);
//画红绿灯
for(auto key:item.road_sl.keys()){
painter.save();
SignalLamp *sl = item.road_sl.value(key);
painter.setBrush(QBrush(QColor(sl->color)));//给灯填充颜色
painter.drawEllipse(key->end,8,8);
painter.drawText(key->end-QPoint(5,5),QString::number(sl->count));
painter.restore();
// painter.drawEllipse(key->end,5,5);
}
}
//画小车
QImage carImage(":/icon/Image/car.png");
for(auto item:list_car){
QPoint pos=item.road->start-(item.road->start-item.road->end)*item.duration;
painter.drawImage(QRect(pos-QPoint(15,15),QSize(30,30)),carImage,carImage.rect());
}
painter.end();
painter.begin(ui->page_map);
painter.drawImage(ui->page_map->rect(),img,img.rect());
painter.end();
return true;
} else {
return false;
}
} else {
// pass the event on to the parent class
return QWidget::eventFilter(obj, event);
}
}
void Mainpage::on_psbt_exit_clicked()
{
this->close();
}
void Mainpage::initRoad()
{
int id=0;
Road road1(id++,QPoint(85,34),QPoint(756,34));
list_road.append(road1);
Road road2(id++,QPoint(756,65),QPoint(85,65));
list_road.append(road2);
Road road3(id++,QPoint(31,86),QPoint(31,332));
list_road.append(road3);
Road road4(id++,QPoint(62,332),QPoint(62,86));
list_road.append(road4);
Road road5(id++,QPoint(778,86),QPoint(778,332));
list_road.append(road5);
Road road6(id++,QPoint(810,332),QPoint(810,86));
list_road.append(road6);
Road road7(id++,QPoint(756,349),QPoint(85,349));
list_road.append(road7);
Road road8(id++,QPoint(85,380),QPoint(756,380));
list_road.append(road8);
Road road9(id++,QPoint(31,404),QPoint(31,655));
list_road.append(road9);
Road road10(id++,QPoint(62,655),QPoint(62,404));
list_road.append(road10);
Road road11(id++,QPoint(778,404),QPoint(778,655));
list_road.append(road11);
Road road12(id++,QPoint(810,655),QPoint(810,404));
list_road.append(road12);
Road road13(id++,QPoint(756,675),QPoint(85,675));
list_road.append(road13);
Road road14(id++,QPoint(85,706),QPoint(756,706));
list_road.append(road14);
}
void Mainpage::initCross(){
if(list_road.count()<14)return;
int id = 0;
Cross cross1(id++);
SignalLamp *sl1 =new SignalLamp;
SignalLamp *sl2 =new SignalLamp;
sl1->color=Qt::red;
sl1->count=32;
sl2->color=Qt::green;
sl2->count=12;
cross1.list_sl.append(sl1);
cross1.list_sl.append(sl2);//信号灯和路口联合起来
cross1.N_exit=&list_road[3];//如果不做安全检查 此处会报错
cross1.N_entrance=&list_road[2];
cross1.E_exit=&list_road[7];
cross1.E_entrance=&list_road[6];
cross1.S_exit=&list_road[8];
cross1.S_entrance=&list_road[9];
cross1.W_exit=nullptr;
cross1.W_entrance=nullptr;
cross1.road_sl.insert(cross1.S_entrance,cross1.list_sl[0]);
cross1.road_sl.insert(cross1.N_entrance,cross1.list_sl[0]);
cross1.road_sl.insert(cross1.E_entrance,cross1.list_sl[1]);
cross1.local=QRect(cross1.N_entrance->end-QPoint(8,-8),
cross1.S_entrance->end-QPoint(-8,8));
list_cross.append(cross1);
Cross cross2(id++);
SignalLamp *sl3=new SignalLamp;
SignalLamp *sl4=new SignalLamp;
sl3->color=Qt::red;
sl3->count=32;
sl4->color=Qt::green;
sl4->count=12;
cross2.list_sl.append(sl3);
cross2.list_sl.append(sl4);//信号灯和路口联合起来
cross2.N_exit=&list_road[5];//如果不做安全检查 此处会报错
cross2.N_entrance=&list_road[4];
cross2.E_exit=nullptr;
cross2.E_entrance=nullptr;
cross2.S_exit=&list_road[10];
cross2.S_entrance=&list_road[11];
cross2.W_exit=&list_road[6];
cross2.W_entrance=&list_road[7];
cross2.road_sl.insert(cross2.S_entrance,cross2.list_sl[0]);
cross2.road_sl.insert(cross2.N_entrance,cross2.list_sl[0]);
cross2.road_sl.insert(cross2.W_entrance,cross2.list_sl[1]);
cross2.local=QRect(cross2.N_entrance->end-QPoint(6,-6),
cross2.S_entrance->end-QPoint(-6,6));
list_cross.append(cross2);
/*
Cross cross3(id++);
SignalLamp *sl5=new SignalLamp;
SignalLamp *sl6=new SignalLamp;
sl5->color=Qt::red;
sl5->count=32;
sl6->color=Qt::green;
sl6->count=12;
cross3.list_sl.append(sl5);
cross3.list_sl.append(sl6);//信号灯和路口联合起来
cross3.N_exit=&list_road[5];//如果不做安全检查 此处会报错
cross3.N_entrance=&list_road[4];
cross3.E_exit=nullptr;
cross3.E_entrance=nullptr;
cross3.S_exit=&list_road[10];
cross3.S_entrance=&list_road[11];
cross3.W_exit=&list_road[6];
cross3.W_entrance=&list_road[7];
cross3.road_sl.insert(cross3.S_entrance,cross3.list_sl[0]);
cross3.road_sl.insert(cross3.N_entrance,cross3.list_sl[0]);
cross3.road_sl.insert(cross3.W_entrance,cross3.list_sl[1]);
cross3.local=QRect(cross3.N_entrance->end-QPoint(6,-6),
cross3.S_entrance->end-QPoint(-6,6));
list_cross.append(cross3);*/
}
void Mainpage::initCar()
{
srand(time(nullptr));
int id=0;
//Car car(id++,&list_road[0],1);
for(int i=0;i<20;i++){
Car car(id++,&list_road[rand()%14],(rand()%100/100.0f));
list_car.append(car);
}
}
void Mainpage::initNet()
{
ns.startListen();//开始监听
}
SmartTraffic项目下的neterver.h
#ifndef NETSERVER_H
#define NETSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
class NetServer : public QObject
{
Q_OBJECT
public:
explicit NetServer(QObject *parent = nullptr);
void startListen();//开始监听
signals:
public slots:
void slot_newConnection();
void slot_readyRead();
private:
QTcpServer server;
};
#endif // NETSERVER_H
SmartTraffic项目下的neterver.cpp
#include "netserver.h"
#include<QDebug>
#include"QJsonDocument"
#include"QJsonObject"
#include"QJsonArray"
#include"QJsonValue"
NetServer::NetServer(QObject *parent) : QObject(parent)
{
connect(&server,&QTcpServer::newConnection,
this,&NetServer::slot_newConnection);
}
void NetServer::startListen()
{
server.listen(QHostAddress::Any,10086);
//端口号随意 0-65535 但1000以内基本被占用了
}
void NetServer::slot_newConnection()
{
qDebug()<<"有新的连接";
QTcpSocket *socket = server.nextPendingConnection();//会返回连接对象的socket
connect(socket,&QTcpSocket::readyRead,
this,&NetServer::slot_readyRead);
}
void NetServer::slot_readyRead()
{
QTcpSocket *socket = dynamic_cast<QTcpSocket *>(sender());
QByteArray data = socket->readAll();
QJsonObject obj = QJsonDocument::fromJson(data).object();
if(obj.contains("code")){
//所有信息都会包含该字段
int code = obj.value("code").toInt();
switch(code){
case 20001:
QString type = obj.value("type").toString();
int id = obj.value("id").toInt();
qDebug() << "新的连接为" << type << ", id =" << id;
}
}
}
VirtualCar下的virtualcar.h
#ifndef VIRTUALCAR_H
#define VIRTUALCAR_H
#include<QTcpSocket>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class VirtualCar; }
QT_END_NAMESPACE
class VirtualCar : public QWidget
{
Q_OBJECT
public:
//VirtualCar(QWidget *parent = nullptr);
explicit VirtualCar(const int &id,QWidget *parent = nullptr);
~VirtualCar();
private slots://槽函数声明
void slot_stateChanged(QAbstractSocket::SocketState state);
private:
void sendId();
Ui::VirtualCar *ui;
QTcpSocket socket;
const int id;
};
#endif // VIRTUALCAR_H
VirtualCar下的main.cpp
#include "virtualcar.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
int id=0;
VirtualCar w(id++);
w.show();
return a.exec();
}
VirtualCar下的virtualcar.cpp
#include "virtualcar.h"
#include "ui_virtualcar.h"
#include"QJsonDocument"
#include"QJsonObject"
#include"QJsonArray"
#include"QJsonValue"
#include <QTimer>
//虚拟小车
VirtualCar::VirtualCar(const int &id,QWidget *parent)
: QWidget(parent)
, ui(new Ui::VirtualCar),
id(id)
{
ui->setupUi(this);
socket.connectToHost("127.0.0.1",10086); //信号与槽的绑定
connect(&socket,&QTcpSocket::stateChanged,
this,&VirtualCar::slot_stateChanged);
}
VirtualCar::~VirtualCar()
{
delete ui;
}
void VirtualCar::slot_stateChanged(QAbstractSocket::SocketState state)
{
if(state == QAbstractSocket::UnconnectedState) {
//连接失败 重新链接
socket.connectToHost("127.0.0.1",10086);
this->setWindowTitle("小车 "+QString::number(id)+" - 链接失败");
} else if (state == QAbstractSocket::ConnectedState) {
//链接成功 暂时什么都不干
this->setWindowTitle("小车" +QString::number(id)+" - 链接成功");
QTimer::singleShot(500,[this](){
sendId();
});
sendId();
}else if (state == QAbstractSocket::ConnectingState) {
this->setWindowTitle("小车 "+QString::number(id)+" - 正在链接");
}
}
void VirtualCar::sendId()
{
//发送身份ID
//code表示身份信息,type表示身份,id表示id
QJsonObject obj;
obj.insert("code",20001);//发送身份信息
obj.insert("type","car");
obj.insert("id",id);
socket.write(QJsonDocument(obj).toJson());//消息会发送给服务器
}
服务器-客户端
我们需要小车接入一辆显示一辆
先对Smart Traffic项目修改
打开mainpage.h
新增私有槽函数
slot_addCar(const int &id);slot_updateCar(const int &id, const int &road_id, const float &duration);
#ifndef MAINPAGE_H
#define MAINPAGE_H
#include "common.h"
#include <QWidget>
#include "netserver.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Mainpage; }
QT_END_NAMESPACE
class Mainpage : public QWidget
{
Q_OBJECT
public:
Mainpage(QWidget *parent = nullptr);
~Mainpage();
protected:
//事件过滤器,重写stackWidget中的绘图事件
bool eventFilter(QObject *obj,QEvent *event);
private slots:
void on_psbt_exit_clicked();
//添加小车
void slot_addCar(const int &id);
void slot_updateCar(const int &id,const int &road_id,
const float &duration);
private:
//初始化道路信息
void initRoad();
void initCross();
void initCar();
void initNet();
Ui::Mainpage *ui;
//保存道路信息的容器
QList<Road> list_road;
QList<Cross>list_cross;
QList<Car> list_car;
NetServer ns;//NetServer对象
};
#endif // MAINPAGE_H
打开netserver.h
删除了两个信号的声明:
void signal_addCar(const int &id);void signal_updateCar(const int &id, const int &road_id, const float &duration);删除了一个私有成员函数的声明:
QList<QJsonObject> splitJsonObject(const QByteArray &data);
#ifndef NETSERVER_H
#define NETSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
class NetServer : public QObject
{
Q_OBJECT
public:
explicit NetServer(QObject *parent = nullptr);
void startListen();//开始监听
signals:
void signal_addCar(const int &id);
void signal_updateCar(const int &id,const int &road_id,
const float &duration);
public slots:
void slot_newConnection();
void slot_readyRead();
private:
QList<QJsonObject>splitJsonObject(const QByteArray &data);
QTcpServer server;
};
#endif // NETSERVER_H
打开netserver.cpp
简化JSON 数据处理逻辑:
slot_readyRead函数直接读取数据并解析为QJsonObject,然后根据code值进行处理。减少信号处理:
slot_readyRead函数在处理特定code值(如20001和30001)时,直接使用qDebug()输出信息,而没有通过信号机制通知其他对象。
#include "netserver.h"
#include<QDebug>
#include"QJsonDocument"
#include"QJsonObject"
#include"QJsonArray"
#include"QJsonValue"
NetServer::NetServer(QObject *parent) : QObject(parent)
{
connect(&server,&QTcpServer::newConnection,
this,&NetServer::slot_newConnection);
}
void NetServer::startListen()
{
server.listen(QHostAddress::Any,10086);
//端口号随意 0-65535 但1000以内基本被占用了
}
void NetServer::slot_newConnection()
{
qDebug()<<"有新的连接";
QTcpSocket *socket = server.nextPendingConnection();//会返回连接对象的socket
connect(socket,&QTcpSocket::readyRead,
this,&NetServer::slot_readyRead);
}
/*
void NetServer::slot_readyRead()
{
QTcpSocket *socket = dynamic_cast<QTcpSocket *>(sender());
QByteArray data = socket->readAll();
QJsonObject obj = QJsonDocument::fromJson(data).object();
if(obj.contains("code")){
int code =obj.value("code").toInt();
switch(code){
case 20001:
QString type =obj.value("type").toString();
int id=obj.value("id").toInt();
qDebug()<<"有新连接为"<<type<<",id"<<id;
}
}
}
*/
void NetServer::slot_readyRead()
{
/*
QTcpSocket *socket = dynamic_cast<QTcpSocket *>(sender());
QByteArray data = socket->readAll();
//QDebug()<<data;
QJsonObject obj = QJsonDocument::fromJson(data).object();
if(obj.contains("code")){
//所有信息都会包含该字段
int code = obj.value("code").toInt();
switch(code){
case 20001:
{
//身份信息
QString type = obj.value("type").toString();
int id = obj.value("id").toInt();
qDebug() << "新的连接为" << type << ", id =" << id;
}
break;
case 30001:
{
//小车状态信息
int id = obj.value("id").toInt();
int road_id = obj.value("road_id").toInt();
float duration = obj.value("duration").toDouble();
qDebug()<<"拿到了新的小车"<<id<<"的信息,所在道路"<<road_id<<",duration"<<duration;
}
}
}
*/
QTcpSocket *socket = dynamic_cast<QTcpSocket *>(sender());
QByteArray data = socket->readAll();
QList<QJsonObject> list_obj = splitJsonObject(data);
for(auto obj : list_obj){
if(obj.contains("code")) {
// 所有的信息都会包含该字段
int code = obj.value("code").toInt();
switch (code) {
case 20001:
// 身份信息
{
QString type = obj.value("type").toString();
int id = obj.value("id").toInt();
// qDebug() << "新的连接为" << type << ",id=" << id;
if(type=="car"){
emit signal_addCar(id);
}
}
break;
case 30001:
{
// 小车状态信息
int id = obj.value("id").toInt();
int road_id = obj.value("road_id").toInt();
float duration = obj.value("duration").toDouble();
emit signal_updateCar(id,road_id,duration);
/* qDebug() << "拿到了新的小车" << id << "的信息,所处道路:" <<
road_id << ",duration:" << duration;
*/
}
}
}
}
}
QList<QJsonObject> NetServer::splitJsonObject(const QByteArray &data)
{
QList<QJsonObject> list_obj;
int braceCount = 0;
int startIndex = 0;
for (int i = 0; i < data.size(); ++i) {
if (data[i] == '{') {
if (braceCount == 0) {
startIndex = i;
}
braceCount++;
} else if (data[i] == '}') {
braceCount--;
if (braceCount == 0) {
QByteArray json = data.mid(startIndex, i - startIndex + 1);
QJsonDocument doc = QJsonDocument::fromJson(json);
QJsonObject obj = doc.object();
list_obj.append(obj);
}
}
}
return list_obj;
}
对VirtualCar项目进行修改
打开main.cpp
随机数种子初始化:使用
std::chrono::high_resolution_clock::now().time_since_epoch().count()来获取当前时间的纳秒级计数,并将其作为随机数生成器的种子。这样可以确保每次运行程序时,随机数序列都是不同的,增加了程序的随机性。循环创建多个
VirtualCar对象:使用了一个循环来创建多个VirtualCar对象,而不是只创建一个。这样可以在程序运行时同时显示多个VirtualCar窗口,增加了程序的可视化效果。动态内存分配:使用了
new操作符来动态分配VirtualCar对象的内存,并使用指针来管理这些对象。这样可以在程序运行时根据需要创建任意数量的VirtualCar对象,而不需要在编译时确定对象的数量。对象 ID 的自增:使用了一个循环变量
i来为每个创建的VirtualCar对象分配一个唯一的 ID。这样可以方便地区分不同的VirtualCar对象,并且可以在程序中对它们进行单独的操作和管理。
#include "virtualcar.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
srand(static_cast<unsigned int>(seed));
int id=1;
for(int i=0;i<5;i++){
VirtualCar *w=new VirtualCar(id++);
w->show();
}
return a.exec();
}
打开virtualcar.h
新增成员变量:
int road_id;:用于表示虚拟汽车所处的道路 ID。
float duration;:用于表示虚拟汽车在当前道路上的行驶进度。新增成员函数:
void sendState();:用于发送虚拟汽车的状态,包括所处道路和行驶进度。
#ifndef VIRTUALCAR_H
#define VIRTUALCAR_H
#include<QTcpSocket>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class VirtualCar; }
QT_END_NAMESPACE
class VirtualCar : public QWidget
{
Q_OBJECT
public:
//VirtualCar(QWidget *parent = nullptr);
explicit VirtualCar(const int &id,QWidget *parent = nullptr);
~VirtualCar();
private slots://槽函数声明
void slot_stateChanged(QAbstractSocket::SocketState state);
private:
void sendId();//发送身份信息
void sendState();//发送车的状态:所处道路
Ui::VirtualCar *ui;
QTcpSocket socket;
const int id;
int road_id;//处在哪条道路上
float duration;//进度
};
#endif // VIRTUALCAR_H
打开virtualcar.cpp
随机生成道路 ID 和持续时间:在构造函数中,添加了随机生成道路 ID(
road_id)和持续时间(duration)的代码。这两个值用于模拟小车的状态。添加了发送状态信息的功能:新增了
sendState函数,用于发送小车的状态信息。状态信息包括道路 ID 和持续时间。这个函数会在小车连接成功后,通过定时器延迟 500 毫秒后调用。在连接成功后发送状态信息:在
slot_stateChanged函数中,当连接状态变为ConnectedState时,不仅发送身份 ID,还调用sendState函数发送状态信息。
#include "virtualcar.h"
#include "ui_virtualcar.h"
#include"QJsonDocument"
#include"QJsonObject"
#include"QJsonArray"
#include"QJsonValue"
#include <QTimer>
//虚拟小车
VirtualCar::VirtualCar(const int &id,QWidget *parent)
: QWidget(parent)
, ui(new Ui::VirtualCar),
id(id)
{
ui->setupUi(this);
socket.connectToHost("127.0.0.1",10086); //信号与槽的绑定
connect(&socket,&QTcpSocket::stateChanged,
this,&VirtualCar::slot_stateChanged);
//以求连接一辆显示一辆
// srand(time(nullptr));
road_id=rand()%14;
duration=(rand()%100)/100.0f;
}
VirtualCar::~VirtualCar()
{
delete ui;
}
void VirtualCar::slot_stateChanged(QAbstractSocket::SocketState state)
{
if(state == QAbstractSocket::UnconnectedState) {
//连接失败 重新链接
socket.connectToHost("127.0.0.1",10086);
this->setWindowTitle("小车 "+QString::number(id)+" - 链接失败");
} else if (state == QAbstractSocket::ConnectedState) {
//链接成功 暂时什么都不干
this->setWindowTitle("小车" +QString::number(id)+" - 链接成功");
QTimer::singleShot(500,[this](){
sendId();
sendState();//仅作测试
});
sendId();
}else if (state == QAbstractSocket::ConnectingState) {
this->setWindowTitle("小车 "+QString::number(id)+" - 正在链接");
}
}
void VirtualCar::sendId()
{
//发送身份ID
//code表示身份信息,type表示身份,id表示id
QJsonObject obj;
obj.insert("code",20001);//发送身份信息
obj.insert("type","car");
obj.insert("id",id);
socket.write(QJsonDocument(obj).toJson());//消息会发送给服务器
}
void VirtualCar::sendState()
{
//已连接状态才需要发送
if(socket.state()==QAbstractSocket::ConnectedState){
QJsonObject obj;
obj.insert("code",30001);//发送小车状态信息
obj.insert("id",id);
obj.insert("road_id",road_id);
obj.insert("duration",duration);//float->doubl
socket.write(QJsonDocument(obj).toJson());//消息会发送给服务器
}
}
效果

更多推荐



所有评论(0)