Ampel

Das Beispiel „Ampel“ zeigt, wie man mit „Qt State Machine -Übersicht“ den Kontrollfluss einer Ampel implementiert.

Ampel, bei der das grüne Licht leuchtet

In diesem Beispiel erstellen wir eine Klasse namens „TrafficLightWidget“. Die Ampel verfügt über drei Lichter: Rot, Gelb und Grün. Die Ampel wechselt in bestimmten Intervallen von einem Licht zum nächsten (rot → gelb → grün → gelb → wieder rot).

class LightWidget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(bool on READ isOn WRITE setOn)
public:
    explicit LightWidget(const QColor &color, QWidget *parent = nullptr)
        : QWidget(parent), m_color(color)
    {
    }

    bool isOn() const { return m_on; }

    void setOn(bool on)
    {
        if (on == m_on)
            return;
        m_on = on;
        update();
    }

public slots:
    void turnOff() { setOn(false); }
    void turnOn() { setOn(true); }

protected:
    void paintEvent(QPaintEvent *) override
    {
        if (!m_on)
            return;
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setBrush(m_color);
        painter.drawEllipse(rect());
    }

private:
    QColor m_color;
    bool m_on = false;
};

Die Klasse „LightWidget“ repräsentiert eine einzelne Ampelphase der Ampel. Sie verfügt über eine Eigenschaft „ on “ sowie zwei Slots, „turnOn()“ und „turnOff()“, um die Ampelphase einzuschalten bzw. auszuschalten. Das Widget zeichnet sich selbst in der Farbe, die an den Konstruktor übergeben wird.

class TrafficLightWidget : public QWidget
{
    Q_OBJECT
public:
    explicit TrafficLightWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        auto vbox = new QVBoxLayout(this);
        m_red = new LightWidget(Qt::red);
        vbox->addWidget(m_red);
        m_yellow = new LightWidget(Qt::yellow);
        vbox->addWidget(m_yellow);
        m_green = new LightWidget(Qt::green);
        vbox->addWidget(m_green);
        auto pal = palette();
        pal.setColor(QPalette::Window, Qt::black);
        setPalette(pal);
        setAutoFillBackground(true);
    }

    LightWidget *redLight() const { return m_red; }
    LightWidget *yellowLight() const { return m_yellow; }
    LightWidget *greenLight() const { return m_green; }

private:
    LightWidget *m_red;
    LightWidget *m_yellow;
    LightWidget *m_green;
};

Die Klasse „TrafficLightWidget“ repräsentiert den visuellen Teil der Ampel; es handelt sich um ein Widget, das drei vertikal angeordnete Lichter enthält und Zugriffsfunktionen für diese bereitstellt.

QState *createLightState(LightWidget *light, int duration, QState *parent = nullptr)
{
    auto lightState = new QState(parent);
    auto timer = new QTimer(lightState);
    timer->setInterval(duration);
    timer->setSingleShot(true);
    auto timing = new QState(lightState);
    QObject::connect(timing, &QAbstractState::entered, light, &LightWidget::turnOn);
    QObject::connect(timing, &QAbstractState::entered, timer, QOverload<>::of(&QTimer::start));
    QObject::connect(timing, &QAbstractState::exited, light, &LightWidget::turnOff);
    auto done = new QFinalState(lightState);
    timing->addTransition(timer, &QTimer::timeout, done);
    lightState->setInitialState(timing);
    return lightState;
}

Die Funktion `createLightState()` erstellt einen Zustand, der eine Ampel ein- schaltet, wenn der Zustand erreicht wird, und ausschaltet, wenn der Zustand verlassen wird. Der Zustand verwendet einen Timer, und wie wir noch sehen werden, wird die Zeitüberschreitung genutzt, um von einem `LightState` in einen anderen überzugehen. Hier ist das Zustandsdiagramm für den Ampelzustand:

LightState mit Zeit-Teilzustand: Beim Eintritt wird das Licht eingeschaltet und der Timer gestartet, beim Verlassen wird es ausgeschaltet, bei Ablauf der Zeit erfolgt der Übergang in den Endzustand

class TrafficLight : public QWidget
{
    Q_OBJECT
public:
    explicit TrafficLight(QWidget *parent = nullptr) : QWidget(parent)
    {
        auto vbox = new QVBoxLayout(this);
        auto widget = new TrafficLightWidget;
        vbox->addWidget(widget);
        vbox->setContentsMargins(QMargins());

        auto machine = new QStateMachine(this);
        auto redGoingYellow = createLightState(widget->redLight(), 3000);
        redGoingYellow->setObjectName("redGoingYellow");
        auto yellowGoingGreen = createLightState(widget->yellowLight(), 1000);
        yellowGoingGreen->setObjectName("yellowGoingGreen");
        redGoingYellow->addTransition(redGoingYellow, &QState::finished, yellowGoingGreen);
        auto greenGoingYellow = createLightState(widget->greenLight(), 3000);
        greenGoingYellow->setObjectName("greenGoingYellow");
        yellowGoingGreen->addTransition(yellowGoingGreen, &QState::finished, greenGoingYellow);
        auto yellowGoingRed = createLightState(widget->yellowLight(), 1000);
        yellowGoingRed->setObjectName("yellowGoingRed");
        greenGoingYellow->addTransition(greenGoingYellow, &QState::finished, yellowGoingRed);
        yellowGoingRed->addTransition(yellowGoingRed, &QState::finished, redGoingYellow);

        machine->addState(redGoingYellow);
        machine->addState(yellowGoingGreen);
        machine->addState(greenGoingYellow);
        machine->addState(yellowGoingRed);
        machine->setInitialState(redGoingYellow);
        machine->start();
    }
};

Die Klasse „TrafficLight“ kombiniert das „TrafficLightWidget“ mit einer Zustandsmaschine. Das Zustandsdiagramm umfasst vier Zustände: Rot-zu-Gelb, Gelb-zu-Grün, Grün-zu-Gelb und Gelb-zu-Rot. Der Anfangszustand ist „rot-zu-gelb“; wenn der Timer des Zustands abgelaufen ist, wechselt die Zustandsmaschine zu „gelb-zu-grün“. Der gleiche Vorgang wiederholt sich bei den anderen Zuständen. So sieht das Zustandsdiagramm aus:

Ampelzyklus: Rot→Gelb, Gelb→Grün, Grün→Gelb, Gelb→Rot

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    TrafficLight widget;
    widget.resize(110, 300);
    widget.show();

    return app.exec();
}

Die Funktion `main()` erstellt eine `TrafficLight`-Instanz und zeigt sie an.

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.