QT-模拟电梯上下楼


一、演示效果

在这里插入图片描述

二、核心程序

#include "ElevatorController.h"
#include <QGridLayout>
#include <QLabel>
#include <QGroupBox>
#include <QGridLayout>
#include <QPushButton>
#include <QDebug>
#include <QChar>
#include <QGuiApplication>
#include <QScreen>
#include <queue>

ElevatorController::ElevatorController(Ui::MainWindow* u, int numElevators, int numFloors)
{
    // create/populate ui ComboBox elements
    ui = u;
    QStringList evs;
    for (int elevator = 1; elevator <= numElevators; ++elevator)
    {
        evs << QString("Elevator: %1").arg(elevator);
    }
    ui->comboElevatorBox->addItems(evs);
    connect(ui->comboElevatorBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &ElevatorController::elevatorSelected);

    evs.clear();

    for (int floorc = 1; floorc <= numFloors; ++floorc)
    {
        evs << QString("Floor: %1").arg(floorc);
    }
    ui->comboFloorBox->addItems(evs);

    // buttons connected
    connect(ui->pushElevatorButton, &QPushButton::clicked, this, &ElevatorController::buttonElevatorSubmit);
    connect(ui->pushHelpButton, &QPushButton::clicked, this, &ElevatorController::buttonElevatorHelp);
    connect(ui->pushPlaceButton, &QPushButton::clicked, this, &ElevatorController::buttonPlaceOnFloor);
    connect(ui->pushMoveButton, &QPushButton::clicked, this, &ElevatorController::buttonMoveToElevator);
    connect(ui->pushAdd10FloorButton, &QPushButton::clicked, this, &ElevatorController::add10ToEachFloor);
    connect(ui->pushBuildingEmergencyButton, &QPushButton::clicked, this, &ElevatorController::triggerBuildingEmergency);
    connect(ui->pushEmergencyResetAllButton, &QPushButton::clicked, this, &ElevatorController::resetAllElevatorsEmergency);
    connect(ui->pushLeaveButton, &QPushButton::clicked, this, &ElevatorController::buttonLeaveElevator);

    // spin box buttons:
    connect(ui->spinBoxMove, qOverload<int>(&QSpinBox::valueChanged), this, &ElevatorController::moveComboBoxChange);
    connect(ui->spinBoxLeaveElevator, qOverload<int>(&QSpinBox::valueChanged), this, &ElevatorController::moveLeaveElevatorBoxChange);

    // combo box change:
    connect(ui->comboFloorBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &ElevatorController::floorSelected);

    // keep in mind: "setWidget" and "setLayout" etc add to the ui tree, memory managed by Qt not Me :-)

    // widget to hold the grid layout
    QWidget* elevatorWidget = new QWidget();
    ui->elevatorScrollArea->setWidget(elevatorWidget); // Set the content widget of the ElevatorController

    // QGridLayout* elevatorGridLayout
    elevatorGridLayout = new QGridLayout(elevatorWidget);
    elevatorWidget->setLayout(elevatorGridLayout);



    // Add buttons or labels to the grid layout based on dimensions
    for (int floor = numFloors - 1; floor >= 0; floor--)
    {
        for (int elevator = 1; elevator <= numElevators; ++elevator)
        {
            // Create a QLabel for each position
            QLabel* cube = new QLabel;
            cube->setText(" ");
            cube->setFixedSize(CUBE_SIZE, CUBE_SIZE);
            QString color = "gray";

            if(numFloors - floor - 1 == 0) // all ev's start at 0
                color = "red";

            cube->setStyleSheet(QString("background-color: %1").arg(color));

            // Add the widget to the grid layout at the specified position
            elevatorGridLayout->addWidget(cube, floor, elevator);
        }

        Floor* flr = new Floor(floor + 1); // floor class is a part of the UI

        // Connect the signals from the Floor to the slots in the ElevatorController
        connect(flr, &Floor::upButtonPressed, this, &ElevatorController::buttonPressedUp);
        connect(flr, &Floor::downButtonPressed, this, &ElevatorController::buttonPressedDown);

        // adds the floor at the start (far left)
        elevatorGridLayout->addWidget(flr, numFloors - floor - 1, 0);
        floors.push_back(flr);
    }

    // create elevators
    for (int elevator = 1; elevator <= numElevators; ++elevator)
    {
        Elevator* ev = new Elevator(elevator);
        elevators.push_back(ev);
        updateDisplays();
        // should be connecting slot in elevator to signals in elevator controller
        connect(this, &ElevatorController::resetEmergency, ev, &Elevator::resetEmergencyInElevator);
        connect(this, &ElevatorController::sendRequestToElevator, ev, &Elevator::pressButton);
        connect(this, &ElevatorController::helpButton, ev, &Elevator::helpButtonPressed);
        connect(this, &ElevatorController::moveElevatorToFloor, ev, &Elevator::moveTofloor);
        connect(this, &ElevatorController::removeElevatorPassengers, ev, &Elevator::removePassengers);
        connect(this, &ElevatorController::addElevatorPassengers, ev, &Elevator::addPassengers);
        connect(this, &ElevatorController::buildingEmergency, ev, &Elevator::emergency);
        connect(this, &ElevatorController::pressButton, ev, &Elevator::pressButton);
        connect(this, &ElevatorController::unpressButton, ev, &Elevator::unpressButton);
        connect(ev, &Elevator::floorChanged, this, &ElevatorController::elevatorFloorChanged);
        connect(ev, &Elevator::doorOpened, this, &ElevatorController::doorOpened);
        connect(ev, &Elevator::doorClosed, this, &ElevatorController::doorClosed);
        connect(ev, &Elevator::doorBlocked, this, &ElevatorController::doorBlocked);
        connect(ev, &Elevator::overloaded, this, &ElevatorController::overloaded);
        connect(ev, &Elevator::emergencyOnBoard, this, &ElevatorController::emergency);
        connect(ev, &Elevator::updateDisplays, this, &ElevatorController::updateDisplays);

        QThread* evThread = new QThread;
        ev->moveToThread(evThread);
        evThread->start();
        threads.push_back(evThread);
    }

    requestScanTimer = new QTimer(this);
    connect(requestScanTimer, &QTimer::timeout, this, &ElevatorController::scanRequestTree);
    requestScanTimer->start(SCAN_REQUEST_TREE_SECS);  // Scan backup request tree every 15 seconds, in case overflow

    qDebug() << "Elevator Controller Initialized";
}

ElevatorController::~ElevatorController() // clean up floors
{
    for(int i = 0; i < floors.size(); i++)
        delete floors[i];

    requestScanTimer->stop();
    delete requestScanTimer;

    for(int i = 0; i < threads.size(); i++)
    {
        threads[i]->quit();
        threads[i]->wait();
        delete threads[i];
    }
}

// --- UI INPUT & CALLBACK FUNCS ---


void ElevatorController::handleScreenResized(int w, int h)
{
    int bufferGap = 10;
    ui->elevatorScrollArea->resize(w - ui->InputTerminal->width() - 3*bufferGap, h - bufferGap*6);
    qDebug() << "Reinit scale -- uiWidth: " << w << " uiHeight: " << h;

    ui->InputTerminal->move(ui->elevatorScrollArea->x() + w - ui->InputTerminal->width() - 2*bufferGap, ui->InputTerminal->y());
    ui->InputTerminal->resize(ui->InputTerminal->width(), h - bufferGap*5);
}

void ElevatorController::updateDisplays()
{
    int ev = ui->comboElevatorBox->currentText().remove(0, 10).toInt(); // stored from 0


    QString buttonList = "";
    const std::set<int>& blist = elevators[ev - 1]->getButtonsPressed();
    for(const int& a : blist)
    {
        buttonList += QString::number(a) + " ";
    }
    ui->textBrowserButtonsPressed->setPlainText(buttonList);

    const int flr = ui->comboFloorBox->currentText().remove(0, 7).toInt();
    ui->passengerOnFloorNumber->display(floors[flr - 1]->peopleOnFloor());
    ui->passengerNumber->display(elevators[ev - 1]->numPassengers());
}

void ElevatorController::buttonElevatorSubmit()
{
    // get the int values from the combo boxes
    int ev = ui->comboElevatorBox->currentText().remove(0, 10).toInt();
    int fb = ui->comboFloorBox->currentText().remove(0, 7).toInt();

    qDebug() << "BUTTON - elevator submit pressed elev: " << ev << " floor button: " << fb;

    if(elevators[ev - 1]->getButtonsPressed().count(fb) > 0)
        emit unpressButton(ev, fb);
    else
        emit pressButton(ev, fb);
}

void ElevatorController::buttonPlaceOnFloor()
{
    qDebug() << "BUTTON buttonPlaceOnFloor.... spawning ppl on floor";

    const int flr = ui->comboFloorBox->currentText().remove(0, 7).toInt() - 1;

    floors[flr]->addPeople(ui->spinBoxPlace->value());
    ui->passengerOnFloorNumber->display(floors[flr]->peopleOnFloor());

    ui->spinBoxPlace->setValue(0);
}

void ElevatorController::buttonMoveToElevator()
{
    qDebug() << "BUTTON: buttonMoveToElevator.... moving ppl ";

    const int flr = ui->comboFloorBox->currentText().remove(0, 7).toInt();
    int evweak = ui->comboElevatorBox->currentText().remove(0, 10).toInt() - 1; // if this is on the same floor its used

    Elevator* availableEv = nullptr;
    Elevator* weakEv = nullptr;
    bool potentialEvPassed = false;

    if(elevators[evweak]->currentFloor() == flr) // soft lock the current elevator
        weakEv = elevators[evweak];

    for(Elevator* ev : elevators) // unless theres one that makes more sense
    {
        if(ev->currentFloor() == flr && ev->currentState() == Elevator::DoorsOpen)
        {
            availableEv = ev;
            if(weakEv == ev && weakEv != nullptr)
            {
                availableEv = weakEv;
                break;
            }
        }
    }

    if(!availableEv)
        return;

    const int val = ui->spinBoxMove->value(); //usr input
    ui->spinBoxMove->setValue(0);

    floors[flr - 1]->removePeople(val);
    //    emit addElevatorPassengers(availableEv->getId(), flr, val);
    elevators[availableEv->getId() - 1]->addPassengers(availableEv->getId(), flr, val);
    // just set the combo box option to the one that people were put into automatically... for visibility
    ui->comboElevatorBox->setCurrentIndex(availableEv->getId() - 1);

    // update the floor on people display
    updateDisplays();
}

void ElevatorController::buttonLeaveElevator()
{

    int ev = ui->comboElevatorBox->currentText().remove(0, 10).toInt();

    qDebug() << "BUTTON: buttonLeaveElevator.... moving ppl EV: " << ev << " FLR: " << elevators[ev - 1]->currentFloor();


    const int val = ui->spinBoxLeaveElevator->value(); //usr input
    ui->spinBoxLeaveElevator->setValue(0);

    emit removeElevatorPassengers(elevators[ev - 1]->getId(), elevators[ev - 1]->currentFloor(), val);
    floors[elevators[ev - 1]->currentFloor() - 1]->addPeople(val);

    // just set the combo box option to the one that people were put into automatically... for visibility
    ui->comboFloorBox->setCurrentIndex(elevators[ev - 1]->currentFloor() - 1);
    ui->passengerNumber->display(elevators[ev-1]->numPassengers());
    updateDisplays();

    const int flr = ui->comboFloorBox->currentText().remove(0, 7).toInt();
    if(elevators[ev - 1]->currentFloor() != flr)
        return;

    // update the floor on people display
    ui->passengerOnFloorNumber->display(floors[elevators[ev - 1]->currentFloor()]->peopleOnFloor());
    updateDisplays();

    controlMoveButtonActivated();
}


void ElevatorController::add10ToEachFloor()
{
    qDebug() << "BUTTON add 10 To Each Floor.... spawning 10 ppl on each floor!";

    for(Floor* f : floors)
    {
        f->addPeople(10);
    }

    const int flr = ui->comboFloorBox->currentText().remove(0, 7).toInt() - 1;
    ui->passengerOnFloorNumber->display(floors[flr]->peopleOnFloor());
    ui->spinBoxPlace->setValue(0);
}

void ElevatorController::triggerBuildingEmergency()
{
    emit buildingEmergency(-1);
}

void ElevatorController::buttonElevatorHelp()
{
    int ev = ui->comboElevatorBox->currentText().remove(0, 10).toInt();
    emit helpButton(ev);
    updateDisplays();
}

void ElevatorController::resetAllElevatorsEmergency()
{
    emit resetEmergency(-1);
    updateDisplays();
}

void ElevatorController::controlMoveButtonActivated(Elevator* availableEv)
{
    // we want to check if there is an elevator on the floor in door open state
    // & set the control button to active or not based on it
    //qDebug() << "BUTTON ACTIVATE: Activating/Deactivating the Move Button to allow moving ppl ";

    const int flr = ui->comboFloorBox->currentText().remove(0, 7).toInt();
    const int evNum = ui->comboElevatorBox->currentText().remove(0, 10).toInt();

    for(Elevator* ev : elevators)
    {
        if(availableEv != nullptr)
            break;
        if(ev->currentFloor() == flr && ev->currentState() == Elevator::DoorsOpen || elevators[evNum - 1]->currentState() == Elevator::Overload)
            availableEv = ev;
    }

    if(elevators[evNum - 1]->currentState() == Elevator::DoorsOpen || elevators[evNum - 1]->currentState() == Elevator::Overload || elevators[evNum - 1]->currentState() == Elevator::Emergency)
        ui->pushLeaveButton->setEnabled(true);
    else if(ui->pushLeaveButton->isEnabled())
        ui->pushLeaveButton->setEnabled(false);

    if(availableEv != nullptr && flr == availableEv->currentFloor())
        ui->pushMoveButton->setEnabled(true);
    else if(ui->pushMoveButton->isEnabled())
        ui->pushMoveButton->setEnabled(false);
}

void ElevatorController::elevatorSelected(int index)
{
    ui->passengerNumber->display(elevators[index]->numPassengers());

    updateDisplays();

    controlMoveButtonActivated(elevators[index]);


    qDebug()  << "COMBO BOX: Elevator selected. Elevator: " << index;
}

void ElevatorController::floorSelected(int index)
{
    // update the segment display for passangers
    ui->passengerOnFloorNumber->display(floors[index]->peopleOnFloor());
    qDebug()  << "COMBO BOX: Floor selected. Floor: " << index;

    ui->spinBoxMove->setValue(0); // wipe this since its different # ppl
    controlMoveButtonActivated(); // potentially changes move buttons state
}

void ElevatorController::moveComboBoxChange(int index)
{
    if(index > ui->passengerOnFloorNumber->value())
    {
        ui->spinBoxMove->setValue(ui->passengerOnFloorNumber->value());
    }
}

void ElevatorController::moveLeaveElevatorBoxChange(int index)
{
    if(index > ui->passengerNumber->value())
    {
        ui->spinBoxLeaveElevator->setValue(ui->passengerNumber->value());
    }
}

// --- UI UPDATE / EV SOCKET FUNCS ---

void ElevatorController::elevatorFloorChanged(int floor, int ev, bool up)
{
    // each elevator emits this when the moved to new floor
    ev -= 1;
    qDebug() << "EV signal: Elevator floor changed, floor: " << floor << " elevator: " << ev << " up dir: " << up;
    qDebug() << "(X, Y) : " << floor << ", " << (ev + 1);


    const int x = floors.size() - floor; // as the floors decrease, x increases (flr increase, x decrease)
    const int y = ev + 1;

    QLayoutItem* layoutItem = elevatorGridLayout->itemAtPosition(x, y); // check if we are looking at a valid ev
    if (!layoutItem)
    {

        qDebug() << "No layout item at this position.";
        return;
    }

    QWidget* widget = layoutItem->widget();
    if (!widget)
    {
        qDebug() << "No widget at this position.";
        return;
    }

    const QMetaObject* metaObject = widget->metaObject();
    QString widgetType = QString::fromUtf8(metaObject->className());

    if (widgetType == "QLabel")
    {
        QLabel* square = qobject_cast<QLabel*>(widget);
        QLabel* squarePrev;
    
        squarePrev = qobject_cast<QLabel*>(elevatorGridLayout->itemAtPosition((x - 1 + floors.size()) % floors.size(), y)->widget());
        squarePrev->setStyleSheet(QString("background-color: gray;"));
    
        squarePrev = qobject_cast<QLabel*>(elevatorGridLayout->itemAtPosition((x + 1)%floors.size(), y)->widget());
        squarePrev->setStyleSheet(QString("background-color: gray;"));
    
        if(elevators[ev]->currentState() == Elevator::Emergency)
            square->setStyleSheet("background-color: yellow;");
        else
            square->setStyleSheet("background-color: red;");
    }

    qDebug() << "Widget type: " << widgetType;
}

void ElevatorController::doorOpened(int flr, int ev)
{
    // a door has opened
    qDebug()  << "EV signal: Door opened! Elevator: " << ev;
    const int x = floors.size() - flr; // as the floors decrease, x increases (flr increase, x decrease)
    const int y = ev;
    if (!elevatorGridLayout->itemAtPosition(x, y))
    {
        qDebug()  << "doorOpened(): No Item at position:  (" << x << ", " << y <<  ")";
        return;
    }
    QWidget* wdg = elevatorGridLayout->itemAtPosition(x, y)->widget();
    if(QString::fromUtf8(wdg->metaObject()->className()) != "QLabel")
    {
        qDebug()  << "doorOpened(): Item at position:  (" << x << ", " << y <<  ") " << "is a: " << QString::fromUtf8(wdg->metaObject()->className());
        return;
    }
    QLabel* squarePrev = qobject_cast<QLabel*>(wdg);
    squarePrev->setStyleSheet(QString("background-color: green;"));
    controlMoveButtonActivated(elevators[ev - 1]);
    updateDisplays();
}

void ElevatorController::doorClosed(int flr, int ev)
{
    // a door has closed
    qDebug()  << "EV signal: Door closed!! Elevator: " << ev;
    const int x = floors.size() - flr; // as the floors decrease, x increases (flr increase, x decrease)
    const int y = ev;

    if (!elevatorGridLayout->itemAtPosition(x, y))
    {
        qDebug()  << "doorClosed(): No Item at position:  (" << x << ", " << y <<  ")";
        return;
    }
    QWidget* wdg = elevatorGridLayout->itemAtPosition(x, y)->widget();
    if(QString::fromUtf8(wdg->metaObject()->className()) != "QLabel")
    {
        qDebug()  << "doorClosed(): Item at position:  (" << x << ", " << y <<  ") " << "is a: " << QString::fromUtf8(wdg->metaObject()->className());
        return;
    }
    QLabel* squarePrev = qobject_cast<QLabel*>(wdg);
    squarePrev->setStyleSheet(QString("background-color: purple;"));
}

void ElevatorController::doorBlocked(int flr, int ev)
{
    // a door has closed
    qDebug()  << "EV signal: Alert! Door blocked... reopening door... Elevator: " << ev;
    const int x = floors.size() - flr; // as the floors decrease, x increases (flr increase, x decrease)
    const int y = ev;

    if (!elevatorGridLayout->itemAtPosition(x, y))
    {
        qDebug()  << "doorBlocked(): No Item at position:  (" << x << ", " << y <<  ")";
        return;
    }
    QWidget* wdg = elevatorGridLayout->itemAtPosition(x, y)->widget();
    if(QString::fromUtf8(wdg->metaObject()->className()) != "QLabel")
    {
        qDebug()  << "doorBlocked(): Item at position:  (" << x << ", " << y <<  ") " << "is a: " << QString::fromUtf8(wdg->metaObject()->className());
        return;
    }
    QLabel* squarePrev = qobject_cast<QLabel*>(wdg);
    squarePrev->setStyleSheet(QString("background-color: blue;"));
}

void ElevatorController::overloaded(int flr, int ev)
{
    // a door has closed
    qDebug()  << "EV signal: Elevator overloaded!! Elevator: " << ev;
    const int x = floors.size() - flr; // as the floors decrease, x increases (flr increase, x decrease)
    const int y = ev;
    if (!elevatorGridLayout->itemAtPosition(x, y))
    {
        qDebug()  << "doorClosed(): No Item at position:  (" << x << ", " << y <<  ")";
        return;
    }
    QWidget* wdg = elevatorGridLayout->itemAtPosition(x, y)->widget();
    if(QString::fromUtf8(wdg->metaObject()->className()) != "QLabel")
    {
        qDebug()  << "overloaded(): Item at position:  (" << x << ", " << y <<  ") " << "is a: " << QString::fromUtf8(wdg->metaObject()->className());
        return;
    }
    QLabel* squarePrev = qobject_cast<QLabel*>(wdg);
    squarePrev->setStyleSheet(QString("background-color: orange;"));
}

void ElevatorController::emergency(int flr, int ev)
{
    // a door has closed
    qDebug()  << "EV signal: Elevator emergency!! Elevator: " << ev;

    if(flr != SAFE_FLOOR)
        return;

    QLayoutItem* layoutItem = elevatorGridLayout->itemAtPosition(floors.size() - SAFE_FLOOR, ev); // check if we are looking at a valid ev
    if (!layoutItem)
    {
        qDebug() << "No layout item at this position.";
        return;
    }
    
    QWidget* widget = layoutItem->widget();
    if (!widget)
    {
        qDebug() << "No widget at this position.";
        return;
    }
    
    const QMetaObject* metaObject = widget->metaObject();
    QString widgetType = QString::fromUtf8(metaObject->className());
    if (widgetType == "QLabel")
    {
        QLabel* square = qobject_cast<QLabel*>(widget);
    
        if(elevators[ev - 1]->currentState() == Elevator::Idle)
            square->setStyleSheet(QString("background-color: red;"));
        else
            square->setStyleSheet(QString("background-color: yellow;"));
    } 

    qDebug() << "Widget type: " << widgetType;
}

// --- EV REQUEST FUNCS ---

void ElevatorController::buttonPressedUp(int floor)
{
    // an up button on a floor has been pressed
    qDebug()  << "Floor signal: Floor up button pressed: " << floor;
    handleFlrPressed(FloorDirection(floor, true));
}

void ElevatorController::buttonPressedDown(int floor)
{
    // a down button on a floor has been pressed
    qDebug() << "Floor signal: Floor down button pressed: " << floor;
    handleFlrPressed(FloorDirection(floor, false));
}

void ElevatorController::handleFlrPressed(FloorDirection fd)
{
    // maybe this had some use in some implementtation? ev->getNumFloorsReserved();

    Elevator* bestElevator = nullptr;
    Elevator* idleEv = nullptr; // lower prio
    for(Elevator* pEv : elevators)
    {
        if(fd.up && pEv->lastDirMovingUp() && fd.num >= pEv->currentFloor())
        {
            bestElevator = pEv;
            break;
        }
        if(!fd.up && !pEv->lastDirMovingUp() && fd.num <= pEv->currentFloor())
        {
            bestElevator = pEv;
            break;
        }

        if(pEv->currentState() == Elevator::Idle)
            idleEv = pEv;
    }

    if(bestElevator)
        emit moveElevatorToFloor(bestElevator->getId(), fd.num);
    else if(idleEv)
        emit moveElevatorToFloor(idleEv->getId(), fd.num);
    else
        earliestRequestTree.push(fd);
}

void ElevatorController::scanRequestTree()
{
    // happen on a timer, scan request tree realloc elevators if free
    if(AGGRESSIVE_LOGGING && !earliestRequestTree.empty())
        qDebug() << "scanRequestTree-> Request floor:  " << earliestRequestTree.top().num << " up: " << earliestRequestTree.top().up; // << i++;
    if (earliestRequestTree.empty())
    {
        return;
    }

    FloorDirection fd = earliestRequestTree.top();
    earliestRequestTree.pop();
    handleFlrPressed(FloorDirection(fd.num, fd.up));
}
xt

三、下载链接

https://download.csdn.net/download/u013083044/88861542

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的大海贼

联系博主,为您提供有价值的资源

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值