TrafficLight example as a widget in MainWindow



  • Hi everybody,

    I have a problem and I don't know what to do.
    I want to use the trafficlight example as a smaller widget in my mainwindow. So that the trafficlight is running in my mainwindow and not as a seperate window.

    What I have done....
    I used the source code of the trafficlight example and divided it into more files (seperated the classes to files). Then I modified the code at some places to get more overview. At last I create my mainwindow class and there I show my trafficlightwidget.

    My problem...
    The trafficlightwidget will be displayed in my mainwindow, as I want (black area). But the lightwidgets (green, yellow, red) will not be shown. When I show my trafficlightwidget in a seperate window everything is fine. But within the mainwindow it don't show the lightwidgets.
    I have also tried to use the update() function of the trafficlightwidget and the mainwindow, but nothing happens. :-(

    Can anybody help me? Thank you in advance!!!

    Best regards
    Tobias

    My code:
    main.cpp

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        MainWindow w;
        TrafficLightWidget tl;
        TrafficLightController tlc;
    
        QObject::connect(&tlc, SIGNAL(greenChanged(bool)), &tl, SLOT(greenisOn(bool)));
        QObject::connect(&tlc, SIGNAL(yellowChanged(bool)), &tl, SLOT(yellowisOn(bool)));
        QObject::connect(&tlc, SIGNAL(redChanged(bool)), &tl, SLOT(redisOn(bool)));
    
        w.show();
    
        return a.exec();
    }
    

    mainwindow.h

    namespace Ui
    {
    class MainWindow;
    }
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    private:
        Ui::MainWindow *ui;
        TrafficLightWidget * trafficlight;
    };
    

    mainwindow.cpp

    MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        trafficlight = new TrafficLightWidget(this);
        trafficlight->setGeometry(50,50,100,275);
        trafficlight->show();
    }
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    trafficlightwidget.h

    class TrafficLightWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit TrafficLightWidget(QWidget *parent = 0);
        ~TrafficLightWidget();
    public slots:
        void greenisOn(bool on);
        void yellowisOn(bool on);
        void redisOn(bool on);
    protected:
        void paintEvent(QPaintEvent * paint);
    private:
        TrafficLightWidget *ui;
        LightWidget *red;
        LightWidget *yellow;
        LightWidget *green;
        QVBoxLayout *vbox;
    };
    

    trafficlightwidget.cpp

    TrafficLightWidget::TrafficLightWidget(QWidget *parent) : QWidget(parent)
    {
        vbox = new QVBoxLayout(this);
        red = new LightWidget(Qt::red, this);
        yellow = new LightWidget(Qt::yellow, this);
        green = new LightWidget(Qt::green, this);
    
        vbox->addWidget(red);
        vbox->addWidget(yellow);
        vbox->addWidget(green);
    
        QPalette pal = this->palette();
        pal.setColor(QPalette::Background, Qt::black);
        this->setPalette(pal);
        this->setAutoFillBackground(true);
    }
    TrafficLightWidget::~TrafficLightWidget()
    {
    
    }
    void TrafficLightWidget::greenisOn(bool on)
    {
        if (on == true)
        {
            green->turnOn();
        }
        else
        {
            green->turnOff();
        }
    }
    void TrafficLightWidget::yellowisOn(bool on)
    {
        if (on == true)
        {
            yellow->turnOn();
        }
        else
        {
            yellow->turnOff();
        }
    }
    void TrafficLightWidget::redisOn(bool on)
    {
        if (on == true)
        {
            red->turnOn();
        }
        else
        {
            red->turnOff();
        }
    }
    void TrafficLightWidget::paintEvent(QPaintEvent *paint)
    {
    
    }
    

    lightwidget.h

    class LightWidget : public QWidget
    {
        Q_OBJECT
        Q_PROPERTY(bool on READ isOn WRITE setOn)
    public:
        explicit LightWidget(const QColor &color, QWidget *parent = nullptr);
        bool isOn();
        void setOn(bool on);
    public slots:
        void turnOff();
        void turnOn();
    protected:
        void paintEvent(QPaintEvent * paint);
    private:
        QColor light_color;
        bool light_on;
    };
    

    lightwidget.cpp

    LightWidget::LightWidget(const QColor &color, QWidget *parent) : QWidget(parent)
    {
        light_color = color;
        light_on = false;
    }
    bool LightWidget::isOn()
    {
        return light_on;
    }
    void LightWidget::setOn(bool on)
    {
        if (on == light_on)
        {
            return;
        }
        light_on = on;
        this->update();
    }
    void LightWidget::turnOff()
    {
        setOn(false);
    }
    void LightWidget::turnOn()
    {
        setOn(true);
    }
    void LightWidget::paintEvent(QPaintEvent *paint)
    {
        if (!light_on)
        {
            return;
        }
    
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setBrush(light_color);
        painter.drawEllipse(0, 0, width(), height());
    }
    

    trafficlightcontroller.h

    class TrafficLightController : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(bool redOn READ getred WRITE setred NOTIFY redChanged)
        Q_PROPERTY(bool yellowOn READ getyellow WRITE setyellow NOTIFY yellowChanged)
        Q_PROPERTY(bool greenOn READ getgreen WRITE setgreen NOTIFY greenChanged)
    public:
        explicit TrafficLightController(QObject *parent = nullptr);
        bool getred();
        bool getgreen();
        bool getyellow();
        void setred(bool on);
        void setgreen(bool on);
        void setyellow(bool on);
    signals:
        void redChanged(bool on);
        void greenChanged(bool on);
        void yellowChanged(bool on);
    private:
        QStateMachine *machine;
        QState *greenState;
        QState *redState;
        QState *yellowState;
        QState *redyellowState;
        QTimer *timer;
        bool green;
        bool red;
        bool yellow;
    };
    

    trafficlightcontroller.cpp

    TrafficLightController::TrafficLightController(QObject *parent) : QObject(parent)
    {
        machine = new QStateMachine(this);
        redState = new QState(machine);
        yellowState = new QState(machine);
        greenState = new QState(machine);
        redyellowState = new QState(machine);
        timer = new QTimer(machine);
    
        green = false;
        red = false;
        yellow = false;
    
        redState->assignProperty(this, "redOn", true);
        redState->assignProperty(this, "yellowOn", false);
        redState->assignProperty(this, "greenOn", false);
        redState->assignProperty(timer, "interval", 2000);
        yellowState->assignProperty(this, "redOn", false);
        yellowState->assignProperty(this, "yellowOn", true);
        yellowState->assignProperty(this, "greenOn", false);
        yellowState->assignProperty(timer, "interval", 2000);
        greenState->assignProperty(this, "redOn", false);
        greenState->assignProperty(this, "yellowOn", false);
        greenState->assignProperty(this, "greenOn", true);
        greenState->assignProperty(timer, "interval", 2000);
        redyellowState->assignProperty(this, "redOn", true);
        redyellowState->assignProperty(this, "yellowOn", true);
        redyellowState->assignProperty(this, "greenOn", false);
        redyellowState->assignProperty(timer, "interval", 2000);
    
        redState->addTransition(timer, SIGNAL(timeout()), redyellowState);
        redyellowState->addTransition(timer, SIGNAL(timeout()), greenState);
        greenState->addTransition(timer, SIGNAL(timeout()), yellowState);
        yellowState->addTransition(timer, SIGNAL(timeout()), redState);
    
        machine->setInitialState(redState);
    
        machine->start();
    
        timer->start();
    }
    void TrafficLightController::setred(bool on)
    {
        if (red != on)
        {
            red = on;
            emit redChanged(on);
        }
    }
    void TrafficLightController::setgreen(bool on)
    {
        if (green != on)
        {
            green = on;
            emit greenChanged(on);
        }
    }
    void TrafficLightController::setyellow(bool on)
    {
        if (yellow != on)
        {
            yellow = on;
            emit yellowChanged(on);
        }
    }
    bool TrafficLightController::getred()
    {
        return red;
    }
    
    bool TrafficLightController::getgreen()
    {
        return green;
    }
    
    bool TrafficLightController::getyellow()
    {
        return yellow;
    }
    

  • Qt Champions 2017

    Hi

    when you use TrafficLightWidget in main window, do you remember to hook it up to a TrafficLightController ?
    Like show in main.cpp ?

     QObject::connect(&tlc, SIGNAL(greenChanged(bool)), &tl, SLOT(greenisOn(bool)));
     QObject::connect(&tlc, SIGNAL(yellowChanged(bool)), &tl, SLOT(yellowisOn(bool)));
     QObject::connect(&tlc, SIGNAL(redChanged(bool)), &tl, SLOT(redisOn(bool)));
    


  • What do you mean exactly?

    I have already tried to update mainwindow as well as trafficlightwidget with this 3 signals.


  • Qt Champions 2017

    @Tobias89

    That the code shown des not seems to connect but i could have missed it.

    MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    trafficlight = new TrafficLightWidget(this);

    no controller and no connects. ?



  • I have tried to connect it in main.cpp and in the constructor of mainwindow.cpp.
    (This lines are not shown in the above code)
    But it didn't work.

    I tried:
    QObject::connect(&tlc, SIGNAL(lightChanged()), &tl, SLOT(repaint()));
    QObject::connect(&tlc, SIGNAL(lightChanged()), &tl, SLOT(update()));
    QObject::connect(&tlc, SIGNAL(lightChanged()), &tl, SLOT(show()));


  • Qt Champions 2017

    @Tobias89

    When you tried in constructor, did you remember to new the TrafficLightController also ?

    if you did
    TrafficLightController tlc;

    it would be deleted as soon as main window constructor was finished.

    the code from main.cpp can not just be copied to main window.
    The objects need to be NEW.ed.



  • In the constructor of mainwindow I tried this version:

    TrafficLightController * controller = new TrafficLightController();
    connect(controller, SIGNAL(lightChanged()), this, SLOT(repaint()));
    connect(controller, SIGNAL(lightChanged()), this, SLOT(update()));
    connect(controller, SIGNAL(lightChanged()), this, SLOT(show()));


  • Qt Champions 2017

    @Tobias89

    but in original it was greenisOn(bool)

    is that the same as some widget update ???

    in original its from

    TrafficLightController to the TrafficLightWidget ?

    should that still not be the case???



  • Now I tried this versions in mainwindow constructor.

    controller = new TrafficLightController();
    connect(controller, SIGNAL(lightChanged()), trafficlight, SLOT(repaint()));
    connect(controller, SIGNAL(lightChanged()), trafficlight, SLOT(update()));
    connect(controller, SIGNAL(greenChanged(bool)), trafficlight, SLOT(greenisOn(bool)));

    green = new LightWidget(Qt::green);
    red = new LightWidget(Qt::red);
    yellow = new LightWidget(Qt::yellow);
    connect(controller, SIGNAL(lightChanged()), red, SLOT(repaint()));
    connect(controller, SIGNAL(lightChanged()), green, SLOT(update()));
    connect(controller, SIGNAL(lightChanged()), yellow, SLOT(greenisOn(bool)));

  • Qt Champions 2017

    Hi

    The only difference from main should be.

    TrafficLightWidget tl = new TrafficLightWidget ;
    TrafficLightController tlc =new TrafficLightController;
    
    QObject::connect(tlc, SIGNAL(greenChanged(bool)), tl, SLOT(greenisOn(bool)));
    QObject::connect(tlc, SIGNAL(yellowChanged(bool)), tl, SLOT(yellowisOn(bool)));
    QObject::connect(tlc, SIGNAL(redChanged(bool)), &tl, SLOT(redisOn(bool)));
    

    unless you change some other code. ??

    If it could paint by itself in main.cpp
    there should be no need to connect to update/repaint even if you
    now do it in main window. It works the same regardless of what
    it is put into.



  • @Tobias89 I took traffic light example and using Qt Creator created default new project (Qt Widgets Application) and added individual Qt classes (LightWidget, TrafficLightWidget and TrafficLight, all based on QWidget). So far it should be pretty much what I imagine you have done.

    Then I used Qt Creator to edit the only form in the project (mainwindow.ui) and added a Widget object from component palette (section Containers). The magic now is to promote that QWidget into the TrafficLight class, and that's it. No need to do anything else in main.cpp. Please see mine below, no references to any widget, as the TrafficLight component is encapsulated into QMainWindow (because you added it with the form designer)

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    You may have more info about Integrating a Custom Widget into Qt Designer here.



  • To promote is the correct keyword, I think.
    But it still didn't refresh, when a light changes.



  • @Tobias89 this project is working fine for me, Qt 5.9.1 / lubuntu 17.10 (Virtualbox VM)



  • @Pablo-J-Rogina
    Thanks a lot!!
    This works fantastic! :-)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.