接上篇

​​​​​​基于QT的智慧交通管理系统(Day1)

基于QT的智慧交通管理系统(Day2)

本文用于记录学期期末实训内容,尽可能做到保姆级别的详细步骤,跟着做准能成

第一次写博客,请多担待

声明:我也只是个学习一般的学生,这是记录课上老师讲的内容,我现在只能说这么做能行,但我还不清楚为什么这样做,还在努力学习中。

创建虚拟车辆项目 

点击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());//消息会发送给服务器
    }
}

效果

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐