QML Quick实现一个十字路口红绿灯

页面的布局

  1. 第一层 绿色Rectangle作为打底,布满窗口
  2. 第二层 两条灰色Rectangle布局成灰色十字型 anchors.leftMarginanchors.horizontalCenter用这两个进行中心布局都可以
  3. 第三层 分流线(矩形画)和斑马线(图片)和十字路口(矩形)
  4. 第四层 车(图片)
  5. 第五层 灯 (图片)

红绿灯逻辑(Connections)

十字路口如果只考虑直行,那么只需要封装一个红绿灯就可以,考虑横竖红绿灯角度不一致,图片不一样那就写成两个组件,唯一不同的就是图片的路径不一致

接收后端红绿灯变化的信号,一旦后端信号灯变化就改变红绿灯的展示,onCurrentLightStateChanged

这边灯用了一个图片,外加三个矩形化成的圆形进行覆盖

import QtQuick 2.12

Image {
    id: lightLeftRight
    source: "qrc:/cars/light"
    sourceSize.height: 100
    Rectangle {
        id: yellowLight
        width: 17
        height: 17
        radius: 50
        color: "#808080"
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
    }
    Rectangle {
        id: redLight
        width: 17
        height: 17
        radius: 50
        color: "#808080"
        anchors.horizontalCenter: parent.horizontalCenter
        y: 20
    }
    Rectangle {
        id: greenLight
        width: 17
        height: 17
        radius: 50
        color: "#808080"
        anchors.horizontalCenter: parent.horizontalCenter
        y: 62
        visible: false
    }

    Connections {
        target: trafficLightController // 假设trafficLightController是C++对象,已在QML上下文中设置
        onCurrentLightStateChanged: {

            if (newState === "Red") {
                redLight.visible = false;
                yellowLight.visible = true;
                greenLight.visible = true;
            } else if (newState === "Yellow") {
                redLight.visible = true;
                yellowLight.visible = false;
                greenLight.visible = true;
            } else {
                redLight.visible = true;
                yellowLight.visible = true;
                greenLight.visible = false;
            }

        }
    }



}

汽车运动的逻辑(Timer)

  1. 设置两个Timer,一个控制循环走,一个控制遇到信号灯处理
  2. 第一个Timer interval: 16 //每16毫秒检查一次位置repeat: true // 重复触发running: true // 开始时即运行

onTriggered触发

  • 没到底按正常走
  • 到底了重新设置x或y
  1. 第二个
  • 红灯停 moveTimer.running = false;(moveTimer是第一个Timer的名称)
  • 绿灯 moveTimer2.running = true; 启动 speed3 = fasterSpeed; 恢复正常速度
  • 快到斑马线的某段距离减速 speed3 = slowerSpeed;
  • 其他时候正常速度

 Image {
        id: downcar
        source: "qrc:/cars/downcar"
        sourceSize.height: 100
        anchors.left: loadCenter.left
        y: -downcar.height
        // 定时器组件
        Timer {
            id: moveTimer2
            interval: 16 // 约60fps
            running: true // 默认开始运行
            repeat: true
            onTriggered: {
                if (downcar.y < window.height) {
                    downcar.y += speed3;
                } else {
                    downcar.y = -downcar.height;
                }
            }
        }
        // 定时器组件
        Timer {
           id: positionCheckTimer2
           interval: 16 // 每50毫秒检查一次位置
           repeat: true // 重复触发
           running: true // 开始时即运行

           onTriggered: {
               if(downcar.y > positionCheckHeight-positionCheckLengthRange  && downcar.y< positionCheckHeight &&
                             trafficLightController1.currentLightState === "Red"){
                    moveTimer2.running = false;

                   } else if(trafficLightController1.currentLightState === "Green") {
                   moveTimer2.running = true;
                   speed3 = fasterSpeed;

                   } else if(downcar.y > positionCheckHeight-positionCheckLengthRange  && downcar.y< positionCheckHeight &&
                             (trafficLightController1.currentLightState === "Yellow" ||
                              trafficLightController1.currentLightState === "Red")) {
                   speed3 = slowerSpeed;

                   } else {
                       speed3 = fasterSpeed;
                   }
           }
       }

    }

后端逻辑代码

逻辑梳理

  1. Timer计时器 初始化时就设置好时间,当Timer一完成就改变信号灯
  2. 当信号灯改变,重新设置Timer计时器,并发出灯已经改变的信号
  3. 灯的属性值发生改变,发出currentLightStateChanged信号
  4. 前端通过onCurrentLightStateChanged获取信号 再根据newState判断信号灯
  5. 车的话就直接获取当前的信号灯trafficLightController1.currentLightState
Connections {
        target: trafficLightController1
        onCurrentLightStateChanged: {// 业务代码}
        }

两部分代码

TrafficLightController .h

#ifndef TRAFFICLIGHTCONTROLLER_H
#define TRAFFICLIGHTCONTROLLER_H

#include <QObject>
#include <QTimer>

class TrafficLightController : public QObject
{
    Q_OBJECT  // 宏

    Q_PROPERTY(QString currentLightState READ currentLightState NOTIFY currentLightStateChanged)

public:
    explicit TrafficLightController(QObject *parent = nullptr);

    QString currentLightState() const;  //  返回当前的红绿灯状态

signals:
    void currentLightStateChanged(QString newState); //  当前红绿灯信号改变

private slots:
    void changeLight(); //  改变红绿灯信号

private:
    enum LightState { Green, Yellow, Red };  // 枚举类型设置灯的信号
    int durations[3] = {7000, 3000, 7000}; // 持续时间:绿灯5秒,黄灯2秒,红灯5秒 水平方向信号灯
//  int durations[3] = {10000, 4000, 3000}; // 持续时间:红灯7秒,绿灯4秒,黄灯1秒,垂直方向信号灯
    LightState currentState;  // 当前的红绿灯状态
    QTimer timer;  // 控制红绿灯时间 
    QString lightStateToString(LightState state) const; // 返回红绿灯使用String类型返回
};

#endif // TRAFFICLIGHTCONTROLLER_H

TrafficLightController.cpp 

#include "TrafficLightController.h"

TrafficLightController::TrafficLightController(QObject *parent)
    : QObject(parent), currentState(Green)   // 初始化信号灯为绿灯
{
    connect(&timer, &QTimer::timeout, this, &TrafficLightController::changeLight); // Timer到时间发出信号改变信号灯
    timer.start(durations[currentState]);

}

QString TrafficLightController::currentLightState() const
{
    return lightStateToString(currentState);
}

void TrafficLightController::changeLight()
{
    static const int nextStateIndices[] = {1, 2, 0}; // 下一个状态索引
    int nextStateIndex = nextStateIndices[static_cast<int>(currentState)];
    currentState = static_cast<LightState>(nextStateIndex);

    timer.setInterval(durations[currentState]);
    emit currentLightStateChanged(lightStateToString(currentState));
}

QString TrafficLightController::lightStateToString(LightState state) const
{
    switch (state) {
    case Green:
        return "Green";
    case Yellow:
        return "Yellow";
    case Red:
        return "Red";
    default:
        return "Unknown";
    }
}

解释一下

Q_PROPERTY(QString currentLightState READ currentLightState NOTIFY currentLightStateChanged)

完整代码

代码目录

App.qml 

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
ApplicationWindow {
    id: window
    visible: true
    width: 1200
    height: 800
    title: qsTr("模拟十字路口车流")

    /**

// 十字路口 模拟车辆在十字路口 运动 图像的动画 运行轨迹 红绿灯显示 画一个矩形 设置不同
// 颜色 定时器(C++)变化 影响车的流动
    // 界面 十字路口
    // 红绿灯
    // 运动 红灯绿灯 走直线 定时器(C++)控制变化

      */

// 背景图片 绿地
    property real grassWidth: 50
    property real treeWidth: 66
    Rectangle {
        color: "#2a4d00"
        width: parent.width
        height: parent.height
    }



// 上下方向的道路
    Rectangle {
        id: upDownLoad
        color:  "grey";
        height: parent.height
        width: 200
//        anchors.left: parent.left
//        anchors.leftMargin: (parent.width-200)/2
        anchors.horizontalCenter: parent.horizontalCenter
        Rectangle {
            color:  "lightyellow";
            height: parent.height
            width: 10
            anchors.left: parent.left
            anchors.centerIn: parent;
        }
    }


// 左右方向的道路
    Rectangle {
        id: leftRightLoad
        color:  "grey";
        width: parent.width
        height: 200
        anchors.top: parent.top
        anchors.topMargin: (parent.height-200)/2

        Rectangle {
            color:  "lightyellow";
            width: parent.width
            height: 10
            anchors.left: parent.left
            anchors.centerIn: parent;
        }


    }


// 中间十字路口
    Rectangle {
        id: loadCenter
        color:  "grey";
        width: 200
        height: 200
        anchors.centerIn: parent;
    }
    property real zebraCrossingLength: 35
    // 斑马线 水平方向
    Image {
        source: "qrc:/cars/zebraCrossing"
        anchors.right: loadCenter.left
        height: 120
        width: zebraCrossingLength
        y: window.height/2 - 120
    }
    Image {
        source: "qrc:/cars/zebraCrossing"
        anchors.right: loadCenter.left
        height: 120
        width: zebraCrossingLength
        y: window.height/2
    }
    Image {
        source: "qrc:/cars/zebraCrossing"
        anchors.left: loadCenter.right
        height: 120
        width: zebraCrossingLength
        y: window.height/2 - 120
    }
    Image {
        source: "qrc:/cars/zebraCrossing"
        anchors.left: loadCenter.right
        height: 120
        width: zebraCrossingLength
        y: window.height/2
    }
    // 斑马线 垂直方向
    Image {
        source: "qrc:/cars/zebraCrossing1"
        anchors.bottom: loadCenter.top
        width: 120
        height: zebraCrossingLength
        x: window.width/2
    }
    Image {
        source: "qrc:/cars/zebraCrossing1"
        anchors.bottom: loadCenter.top
        width: 120
        height: zebraCrossingLength
        x: window.width/2 - 120
    }
    Image {
        source: "qrc:/cars/zebraCrossing1"
        anchors.top: loadCenter.bottom
        width: 120
        height: zebraCrossingLength
        x: window.width/2
    }
    Image {
        source: "qrc:/cars/zebraCrossing1"
        anchors.top: loadCenter.bottom
        width: 120
        height: zebraCrossingLength
        x: window.width/2 - 120
    }



    // 车辆停止的范围
    property real speed1: 7
    property real speed2: 7
    property real speed3: 7
    property real speed4: 7
    property real fasterSpeed: 7
    property real slowerSpeed: 4
    property real slowerslowerSpeed: 2

    property real carLength: 100
    property real loadCenterLength: 200
    property real positionCheckLength: (window.width - loadCenterLength) / 2 - carLength
    property real positionCheckLength1: (window.width - loadCenterLength) / 2 + loadCenterLength
    property real positionCheckLengthRange: 50
    property real positionCheckHeight: (window.height - loadCenterLength) / 2 - carLength
    property real positionCheckHeight1: (window.height - loadCenterLength) / 2 + loadCenterLength
    // 左右方向的车辆
    Image {
        id: rightcar
        source: "qrc:/cars/rightcar"
        sourceSize.height: 100
        anchors.bottom: loadCenter.bottom
        x: -rightcar.width
        // 定时器组件
        Timer {
            id: moveTimer
            interval: 16 // 约60fps
            running: true // 默认开始运行
            repeat: true
            onTriggered: {
                if (rightcar.x < window.width) {
                    rightcar.x += speed1;
                } else {
                    rightcar.x = -rightcar.width;
                }
            }
        }
        // 定时器组件

        Timer {
           id: positionCheckTimer
           interval: 16 // 每50毫秒检查一次位置
           repeat: true // 重复触发
           running: true // 开始时即运行

           onTriggered: {
//               console.log(rightcar.x)
               if(rightcar.x > positionCheckLength-positionCheckLengthRange  && rightcar.x< positionCheckLength&&
                             trafficLightController.currentLightState === "Red"){

                    moveTimer.running = false;

                   } else if(trafficLightController.currentLightState === "Green") {
                   moveTimer.running = true;
                   speed1 = fasterSpeed;

                   } else if(rightcar.x > positionCheckLength-positionCheckLengthRange  && rightcar.x< positionCheckLength &&
                             (trafficLightController.currentLightState === "Yellow" ||
                              trafficLightController.currentLightState === "Red")) {
                   speed1 = slowerslowerSpeed;

                   } else {
                       speed1 = fasterSpeed;
                   }
           }
       }

    }
    Image {
        id: leftcar
        source: "qrc:/cars/leftcar"
        sourceSize.height: 100
        anchors.top: loadCenter.top
        // 定时器组件
        Timer {
            id: moveTimer1
            interval: 16 // 约60fps
            running: true // 默认开始运行
            repeat: true
            onTriggered: {
//                console.log(leftcar.x)
                if (leftcar.x < -leftcar.width) {
                    leftcar.x = window.width + leftcar.width;
                } else {
                    leftcar.x -= speed2;
                }
            }
        }
        // 定时器组件
        Timer {
           id: positionCheckTimer1
           interval: 16 // 每50毫秒检查一次位置
           repeat: true // 重复触发
           running: true // 开始时即运行

           onTriggered: {
//               console.log(leftcar.x)
               if(leftcar.x > positionCheckLength1  && leftcar.x< positionCheckLength1 + positionCheckLengthRange &&
                             trafficLightController.currentLightState === "Red"){

                    moveTimer1.running = false;

                   } else if(
                             trafficLightController.currentLightState === "Green") {

                   moveTimer1.running = true;
                   speed2 = fasterSpeed;

                   } else if(leftcar.x > positionCheckLength1  && leftcar.x< positionCheckLength1 + positionCheckLengthRange &&
                             (trafficLightController.currentLightState === "Yellow" ||
                              trafficLightController.currentLightState === "Red")) {
//                   console.log(leftcar.x)
                   speed2 = slowerslowerSpeed;

                   } else {
                   speed2 = fasterSpeed;
                   }
           }
       }

    }

    // 上下方向的车辆
    Image {
        id: downcar
        source: "qrc:/cars/downcar"
        sourceSize.height: 100
//        anchors.top : loadCenter.top
        anchors.left: loadCenter.left
        y: -downcar.height
        // 定时器组件
        Timer {
            id: moveTimer2
            interval: 16 // 约60fps
            running: true // 默认开始运行
            repeat: true
            onTriggered: {
                if (downcar.y < window.height) {
                    downcar.y += speed3;
                } else {
                    downcar.y = -downcar.height;
                }
            }
        }
        // 定时器组件
        Timer {
           id: positionCheckTimer2
           interval: 16 // 每50毫秒检查一次位置
           repeat: true // 重复触发
           running: true // 开始时即运行

           onTriggered: {
               if(downcar.y > positionCheckHeight-positionCheckLengthRange  && downcar.y< positionCheckHeight &&
                             trafficLightController1.currentLightState === "Red"){
//                   console.log(downcar.y)
                    moveTimer2.running = false;

                   } else if(trafficLightController1.currentLightState === "Green") {
                   moveTimer2.running = true;
                   speed3 = fasterSpeed;

                   } else if(downcar.y > positionCheckHeight-positionCheckLengthRange  && downcar.y< positionCheckHeight &&
                             (trafficLightController1.currentLightState === "Yellow" ||
                              trafficLightController1.currentLightState === "Red")) {
                   speed3 = slowerSpeed;

                   } else {
                       speed3 = fasterSpeed;
                   }
           }
       }

    }
    Image {
        id: upcar
        source: "qrc:/cars/upcar"
        sourceSize.height: 100
        anchors.right: loadCenter.right
        y: window.height
        // 定时器组件
        Timer {
            id: moveTimer3
            interval: 16 // 约60fps
            running: true // 默认开始运行
            repeat: true
            onTriggered: {
                if (upcar.y < -upcar.height) {
                    upcar.y = window.height+upcar.height;
                } else {
                    upcar.y -= speed4;
                }
            }
        }
        // 定时器组件
        Timer {
           id: positionCheckTimer3
           interval: 16 // 每50毫秒检查一次位置
           repeat: true // 重复触发
           running: true // 开始时即运行

           onTriggered: {
//               console.log(upcar.x)
               if(upcar.y > positionCheckHeight1  && upcar.y< positionCheckHeight1 + positionCheckLengthRange &&
                             trafficLightController1.currentLightState === "Red"){
                    moveTimer3.running = false;

                   } else if(trafficLightController1.currentLightState === "Green") {
                   moveTimer3.running = true;
                   speed4 = fasterSpeed;

                   } else if(upcar.y > positionCheckHeight1  && upcar.y< positionCheckHeight1 + positionCheckLengthRange &&
                             (trafficLightController1.currentLightState === "Yellow" ||
                              trafficLightController1.currentLightState === "Red")) {
                   speed4 = slowerSpeed;

                   } else {
                       speed4 = fasterSpeed;
                   }
           }

    }

}




    // 向右红绿灯
    LightLeftRight {
        id: lightright
        anchors.left: loadCenter.right
        y: window.height/2-loadCenter.height/8

    }
    // 向左红绿灯
    LightLeftRight {
        id: lightleft
        anchors.right: loadCenter.left
        y: window.height/2-loadCenter.height/8*3

    }
    // 向上红绿灯
    LightUpDown {
        id: lightup
        anchors.bottom: loadCenter.top
        x: window.width/2-loadCenter.height/8

    }

    // 向下红绿灯
    LightUpDown {
        id: lightdown
        anchors.top: loadCenter.bottom
        x: window.width/2-loadCenter.height/8*3

    }




}

App.cpp 

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "MyCppClass.h"
#include "MyListModel.h"
#include "TrafficLightController.h"
#include "TrafficLightController1.h"
#include <QIcon>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/images/music.png"));

    // 创建TrafficLightController实例
    TrafficLightController trafficLightController;
    TrafficLightController1 trafficLightController1;

    QQmlApplicationEngine engine;

    // ... 添加更多项目
    MyListModel model;

    // 创建C++对象实例
    MyCppClass cppObject;

    // 将C++对象注册到QML上下文中
    engine.rootContext()->setContextProperty("myCppObject", &cppObject);
    engine.rootContext()->setContextProperty("myListModel", &model);
    // 将TrafficLightController实例设置为QML的上下文属性
    // 这样就可以在QML文件中通过id "trafficLightController" 访问它了
    engine.rootContext()->setContextProperty("trafficLightController", &trafficLightController);
    engine.rootContext()->setContextProperty("trafficLightController1", &trafficLightController1);

    const QUrl url(QStringLiteral("qrc:/App.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    // 加载QML文件
    engine.load(url);

    return app.exec();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值