Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Signal not emitted or not received



  • How can I tell if a signal is not being emitted, or not being received?

    I've been troubleshooting this for about a week and I'm stuck! As a learning project I've been extending the Qt CANBus example in Qt 5.12.3 "example sends and receives CAN bus frames". I've added a message parsing class which emits a signal with information and a QML window to receive the signal and display the data. My problem is the code reaches the emitting signal, but the QML window doesn't seem to receive it. I think I've got everything set up correctly, I've used this method in other projects, but I can't figure out why it's not working.

    My code:

    MainWindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "connectdialog.h"
    
    #include <QTimer>
    #include <QCanBus>
    #include <QDebug>
    #include <QQuickView>
    #include <QCloseEvent>
    #include <QCanBusFrame>
    #include <QDesktopServices>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        m_ui(new Ui::MainWindow)
    {
        m_ui->setupUi(this);
        m_connectDialog = new ConnectDialog;
        m_status = new QLabel;
        m_ui->statusBar->addPermanentWidget(m_status);
        m_written = new QLabel;
        m_ui->statusBar->addWidget(m_written);
        initActionsConnections();
    
        QTimer::singleShot(50, m_connectDialog, &ConnectDialog::show);
    
        engine.rootContext()->setContextProperty("pMessages", &pMessageProcessor);
        engine.rootContext()->setContextProperty("modFinder", &moduleFinder);
        engine.rootContext()->setContextProperty("mainWindow", this); 
    }
    
    ...
    
    void MainWindow::processReceivedFrames()
    {
        if (!m_canDevice)
            return;
    
        while (m_canDevice->framesAvailable()) {
            const QCanBusFrame frame = m_canDevice->readFrame();
    
            QString view;
            if (frame.frameType() == QCanBusFrame::ErrorFrame)
                view = m_canDevice->interpretErrorFrame(frame);
            else
                view = frame.toString();
    
            const QString time = QString::fromLatin1("%1.%2  ")
                    .arg(frame.timeStamp().seconds(), 10, 10, QLatin1Char(' '))
                    .arg(frame.timeStamp().microSeconds() / 100, 4, 10, QLatin1Char('0'));
    
            const QString flags = frameFlags(frame);
    
            QString canMessage;
            canMessage = view.simplified();
    
            m_ui->receivedMessagesEdit->append(time + flags + view);
    /***********************************************************************************/
            emit canMessageOut(canMessage) // <- this sends message to my parser
    /***********************************************************************************/
        }
    }
    
    // THIS OPENS MY QML WINDOW, WHICH I HAVE OPEN AND RUNNING DURING TESTING
    void MainWindow::on_actionP_Bus_triggered()
    {
        if( component->status() != component->Ready )
        {
            if( component->status() == component->Error )
                qDebug()<< "Error: " + component->errorString();
            return;
        }
    
        component->create();
    }
    
    

    mainWindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QCanBusDevice> // for CanBusError
    
    #include <QMainWindow>
    #include <QQmlContext>
    #include <QQmlComponent>
    #include <QQmlApplicationEngine>
    #include "pmessageprocessor.h"
    #include "modulefinder.h"
    
    class ConnectDialog;
    
    QT_BEGIN_NAMESPACE
    
    class QCanBusFrame;
    class QLabel;
    
    namespace Ui {
    class MainWindow;
    }
    
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow() override;
    
        QQmlApplicationEngine engine;
        QQmlComponent *component = new QQmlComponent(&engine, (QUrl(QStringLiteral("qrc:/qml/mainAppWindow.qml"))));
        void processReceivedFrames();
        pMessageProcessor pMessageProcessor; // have to declare these classes in .h not in
        moduleFinder moduleFinder;          // the .cpp or it causes issues
        QString statusMessage;
        static QDebug dStream(QString &m_outgoingMessage);
    
    signals:
        void canMessageOut(QString outGoingMessage); // send to CAN message parser
        void statusMsgChanged(const QString outGoingMessage); // send to QML receiver
    
    private slots:
        void sendFrame(const QCanBusFrame &frame) const;
        void processErrors(QCanBusDevice::CanBusError) const;
        void connectDevice();
        void disconnectDevice();
        void processFramesWritten(qint64);
        void on_actionP_Bus_triggered();
    
    protected:
        void closeEvent(QCloseEvent *event) override;
    
    private:
        void initActionsConnections();
    
        qint64 m_numberFramesWritten = 0;
        Ui::MainWindow *m_ui = nullptr;
        QLabel *m_status = nullptr;
        QLabel *m_written = nullptr;
        ConnectDialog *m_connectDialog = nullptr;
        QCanBusDevice *m_canDevice = nullptr;
    };
    
    #endif // MAINWINDOW_H
    
    

    My parser:

    #include "pmessageprocessor.h"
    #include "mainwindow.h"
    #include <QHash>
    #include <QCache>
    
    pMessageProcessor::pMessageProcessor()
    {
        pHash.insert("FF04", 1); // 1 = Analog values 
        pHash.insert("FF02", 2); // 2 = Output events - outputs on or off
    }
    
    /* ***************  RECEIVE MESSAGES AND SEND TO PARSERS  *********** */
    
    void pMessageProcessor::pIncomingMessage(QString message){
        //qDebug() << message;
        message.remove(0,2); // remove priority digits
    
        parts = message.split("[8]"); // split message at natural separator
    
        leftPart = parts.at(0).simplified(); // PGN + Source Address (remove leading and trailing whitespace)
    
        pgn = leftPart.left(4); // PGN only
    
        srcAddress = leftPart.right(2); // SA only
    
        data = parts.at(1).simplified(); // 8 bytes of data (remove leading and trailing whitespace)
    
        pgnTest = pHash[pgn];
    
        switch (pgnTest) {
        case (1):
            analogInputs(srcAddress, data);
            break;
    
        case (2):
            outputConditions(srcAddress, data);
            break;
        }
    }
    
    /*************            PARSERS              ***************/
    
    // Case 1
    void pMessageProcessor::analogInputs(QString _srcAddress, QString _data){
        QString _d0 = _data.left(2);
        QString _d1 = _data.mid(3,2);
        QString _d2 = _data.mid(6,2);
        QString _d3 = _data.mid(9,2);
        QString _d4 = _data.mid(12,2);
        QString _d5 = _data.mid(15,2);
        QString _d6 = _data.mid(18,2);
        QString _d7 = _data.right(2);
        QString _analogInputOne = _d1 + _d0; // (high byte + low byte)
        QString _analogInputTwo = _d3 + _d2;
        QString _analogInputThree = _d5 + _d4;
        QString _analogInputFour = _d7 + _d6;
        //qDebug()<< "data: " << _data <<_d0 << _d1 << _d2 << _d3 << _d4 <<_d5 << _d6 << _d7;
    
             // TODO - Conversion checking / logging
    
        qint16 analogInputOne = static_cast<qint16>(_analogInputOne.toInt(&ok, 16)*.001); // analog input 1
        qint16 analogInputTwo = static_cast<qint16>(_analogInputTwo.toInt(&ok, 16)*.001); // analog input 2
        qint16 analogInputThree = static_cast<qint16>(_analogInputThree.toInt(&ok, 16)*.001); // analog input 3
        qint16 analogInputFour = static_cast<qint16>(_analogInputFour.toInt(&ok, 16)*.001); // analog input 4
    
        analogInputsMessage(_srcAddress, analogInputOne, analogInputTwo, analogInputThree, analogInputFour);
        //qDebug() << "source address:" << _srcAddress << "A1:" << analogInputOne << "A2:" << analogInputTwo << "A3:" << analogInputThree << "A4:" << analogInputFour;
    
    }
    
    ...
    
    /**********************        SIGNALING      ********************/
    
    void pMessageProcessor::analogInputsMessage( QString _srcAddress, qint16 _analogInputOne, qint16 _analogInputTwo,
                                                                    qint16 _analogInputThree, qint16 _analogInputFour) {
        emit analogInputsValue(_srcAddress, _analogInputOne, _analogInputTwo, _analogInputThree, _analogInputFour);
    /********************************************************************/
       qDebug() << "signal reached";  // <- CODE GETS TO HERE
    /********************************************************************/
    }
    
    

    pMessageProcessor.h:

    #ifndef PMESSAGEPROCESSOR_H
    #define PMESSAGEPROCESSOR_H
    
    #include <QHash>
    #include <QObject>
    #include <QDebug>
    
    class pMessageProcessor : public QObject
    {
        Q_OBJECT
    
    public:
        
        pMessageProcessor();
    
        void analogInputs(QString, QString);
        void outputConditions(QString, QString);
        void analogInputsMessage(QString, qint16, qint16, qint16, qint16);
    
        QString statusMessage;
    
        static QDebug dStream(QString &m_outgoingMessage);
    
    public slots:
        void pIncomingMessage(QString message);
    
    signals:
        void analogInputsValue( QString srcAddressOut, qint16 analogInputOne,
                                qint16 analogInputTwo, qint16 analogInputThree,
                                qint16 analogInputFour);
    
    private:
        bool ok;
        int pgnTest;
        QString message1;
        QString message2;
        QString leftPart;
        QString pgn;
        QString data;
        QString srcAddress;
        QStringList parts;
        QHash<QString, int> pHash;
    
    };
    
    #endif // PMESSAGEPROCESSOR_H
    
    

    The QML connector:

    Connections {
            target: pMessages
            onAnalogInputsValue: {srcAddress = srcAddressOut; aInputOne = analogInputOne;
                aInputTwo = analogInputTwo; aInputThree = analogInputThree; aInputFour = analogInputFour;
                console.log("srcAddress" + srcAddress)}  //<- THIS NEVER GETS PRINTED
        }
    

    My QML windows are arranged as an ApplicationWindow, which holds two sub windows. One is hidden behind the other until needed and I control the z value to arrange them. The Connections statement is in the subwindow that will receive and display the data, though I've tried putting it in the main window with no effect.

    I don't know how to see if the signal is actually being emitted, but I know the code is at least getting to the emit statement. I read about QSignalSpy, but getting that up and running seems a little out of my league right now. I'm hoping someone can spot some stupid error that is keeping this from working.


  • Moderators

    @MScottM You're most welcome! Always happy to help a willing learner.

    With respect to QQmlEngine, I was wondering, and asked in one of my posts above, whether it was an issue to create a second one, and if that might be part of my problem.

    Yes, that is definitely part of your problem. The diagram below summarizes your code:

    Connection Diagram

    (Red arrows show signal-slot connections; Blue lines show QML contexts)

    You have created 2 separate message processors and 2 separate QML engines.

    • Your first pMessageProcessor (in main.cpp) receives the MainWindow::canMessageOut() signal. However, you have not connected anything to this pMessageProcessor's signals.
    • Your second pMessageProcessor(in mainwindow.h) has its signals connected to the signal handlers ModulePage. However, it does not receiveMainWindow::canMessageOut() so it never emits its signals.

    From the diagram, can you see what needs to happen for your code to work as you want? Try to implement the change in your code. If you can't figure it out, describe what you want to do and I'll give you some pointers.

    The simple answer is 'all of the above'. A part of my job includes working with equipment that uses CAN bus to communicate, and I thought it would be interesting to learn some more about Qt while making a tool that could be useful for me when troubleshooting.

    When learning multiple new concepts, I recommend the "divide and conquer" approach. Focus on one thing at a time -- you will be able to learn much faster this way. Mixing multiple concepts into the same study makes it much harder to troubleshoot things.

    While I've had one or two formal classes in programming (enough to make me dangerous), I'm in no way a computer science major, and I apologize for the amateur mistakes I must be making!

    You don't need a computer science major to learn Qt, but you do need to be systematic and patient.

    Integrating QML GUIs with C++ seems like the best way to make interesting useful programs.

    You can absolutely make interesting useful programs using Qt Widgets too.

    Since the CAN example already has a solid GUI based on Qt Widgets, I highly recommend you first learn by adding new functionality to that example by implementing new widgets. Leave QML out of it for now.

    Add QML after you have mastered widgets, or implement QML in a separate, smaller, and simpler project which doesn't have such a complex web of connections.


  • Lifetime Qt Champion

    Hi,

    I am not 100% sure, but shouldn't you set all the context properties before creating your component since you are connecting stuff in there from the context ?



  • Hi @SGaist ,

    thanks for taking a look. Forgive my ignorance, but could you expand on that a little? Do you mean in the MainWindow.cpp?

    These?

        engine.rootContext()->setContextProperty("pMessages", &pMessageProcessor);
        engine.rootContext()->setContextProperty("modFinder", &moduleFinder);
        engine.rootContext()->setContextProperty("mainWindow", this); 
    

  • Lifetime Qt Champion

    Yes, you are constructing your component before these are assigned.

    Move it after these three lines.



  • @SGaist

    Again - sorry for not quite getting it! Do you mean when the QML window gets created here?

    void MainWindow::on_actionP_Bus_triggered()
    {
        if( component->status() != component->Ready )
        {
            if( component->status() == component->Error )
                qDebug()<< "Error: " + component->errorString();
            return;
        }
    
        component->create();
    }
    

    this does happen after mainWindow has been created.


  • Lifetime Qt Champion

    I was thinking about the construction part:

    QQmlComponent *component = new QQmlComponent(&engine, (QUrl(QStringLiteral("qrc:/qml/mainAppWindow.qml"))));



  • Hi @SGaist

    I moved the constructor into the function and it didn't make a difference.


  • Lifetime Qt Champion

    Then I would first take these two into the main function and initialise everything there just to be sure it's working correctly.



  • @SGaist

    I tried it. The QML component initialized immediately, but there was no change in the behavior.

    I was reading this article:

    debugging-signals-and-slots-in-qt

    and tried this line:

    connect(this, SIGNAL(&analogInputsValue()), qApp, SLOT(aboutQt));
    

    I assume this is supposed to pop up the Qt About box when the signal triggers, but I get a console message:

    "qObject::connect: no such signal pMessageProcessor::&analogInputsValue()


  • Moderators

    @mscottm said in Signal not emitted or not received:

    SIGNAL(&analogInputsValue())

    Remove the &



  • Hi @JKSH,

    I removed the '&' and got the same result - "no such signal".


  • Moderators

    @mscottm said in Signal not emitted or not received:

    I removed the '&' and got the same result - "no such signal".

    Looking at your mainWindow.h, you don't have a analogInputsValue() signal. Instead, you have a analogInputsValue(QString, qint16, qint16, qint16, qint16) signal.

    So, your connection code should be
    connect(this, SIGNAL(analogInputsValue(QString, qint16, qint16, qint16, qint16)), qApp, SLOT(aboutQt()));

    NOTE: Remember the () in the slot too! Write SLOT(aboutQt()), not SLOT(aboutQt)



  • @jksh said in Signal not emitted or not received:

    connect(this, SIGNAL(analogInputsValue(QString, qint16, qint16, qint16, qint16)), qApp, SLOT(aboutQt()));

    OHHH! That did it, thanks!

    So the signal is obviously firing - the 'About' message box popped up. Now I know where to focus my troubleshooting. I know that at least the IDE is recognizing the class contextProperty, as it 'colorizes' the target class name in the connect statement.

    What else can I look at or try?


  • Lifetime Qt Champion

    Well, to ensure that the basics are working, try starting from the Embedding C++ Objects into QML with Context Properties example and then move things around until they are where you would like to have them in your application.



  • @SGaist - on that page it says:

    "If the QML item needs to receive signals from the context property, it can connect to them using the Connections type. For example, if ApplicationData has a signal named dataChanged(), this signal can be connected to using an onDataChanged handler within a Connections object:

    Text {
        text: applicationData.getCurrentDateTime()
    
        Connections {
            target: applicationData
            onDataChanged: console.log("The application data changed!")
        }
    }
    

    That is what I'm doing, and the only difference from my QML and their example is I have my Connections statement higher in the hierarchy, but I've tried it in multiple places.


  • Lifetime Qt Champion

    What I wanted you to check was that your QML + context properties are working correctly when following the same setup as the example provided in the documentation. Once that has been confirmed, we can then move these stuff in your main window class.


  • Moderators

    The code you posted is very large; it will take us a lot of time to read through and identify your problem.

    Please post a minimal example that demonstrates your problem.



  • Hi @SGaist,

    I think you put me on to something. When I created the project to test the code in the example you pointed to, I noticed in the 'boilerplate' code that was created, a QObject::connect statement that I don't have:

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

    Is this connecting the qml side to the cpp side? I didn't think about this as I was adapting an example. Do I need to add something like this?

    edit - I also just noticed that there is a QQmlApplicationEngine created in the main.cpp, and I created another one in MainWindow.cpp - that has to be an issue...doesn't it?

    @JKSH - I do apologize, I was trying to be thorough, but I understand the need for brevity when someone is trying to help and get to the heart of an issue.


  • Lifetime Qt Champion

    It can be useful to stop the application if there's a failure to create the object from the file you passed as parameter.

    It is however not directly related to the issue you are having.



  • Hi @SGaist ,

    I created a small project and adapted the example you pointed to, and created a signal in c++ that would update a text in QML every few seconds using context properties and a Connections statement in QML:

        QTimer* timer = new QTimer(this);
                timer->setInterval(3000);
                connect(timer, SIGNAL(timeout()),
                        this, SLOT(sendOutSignal()));
                timer->start();
    }
    void pMessageProcessor::sendOutSignal() {
         x+=1;
        number.setNum(x);
        emit mySignal(number);
    }
    
    Text {
            id: myText
            text: {""}
    
            Connections {
                target: applicationData
                onMySignal: myText.text = myVariable
            }
        }
    

    It works as expected.

    Next I moved the code over to my application and connected one of my QML label texts to the signal and it works - the label updates with the timer and signal, however I still can't get my original signal to work.


  • Moderators

    @mscottm said in Signal not emitted or not received:

    Next I moved the code over to my application and connected one of my QML label texts to the signal and it works - the label updates with the timer and signal, however I still can't get my original signal to work.

    Congratulations, that's good progress.

    Compare the two applications and see what's different between the way your C++ and QML objects are set up. This will lead you to the solution. It might help if you start removing parts from your original application that are not related to the connection.



  • Sorry to dig this up again, but I've been banging my head against this for more than two weeks now, and I can't figure this out. THIS SHOULD WORK!!

    The only time I can get the QML to react to a c++ signal is when it is called by my test timer:

        QTimer* timer = new QTimer(this);
                timer->setInterval(3000);
    
    
                connect(timer, SIGNAL(timeout()),
                        this, SLOT(sendOutSignal()));
    
                timer->start();
    }
    
    void pMessageProcessor::sendOutSignal() {
         x+=1;
        number.setNum(x);
        emit mySignal(number);
        qDebug() << "mySignal emitted" << number;
    }
    

    and I see QML console.log messages that the signal was received, and labels that are tied to the data update accordingly

    When I try ANY other way to get my signal to QML, it doesn't work. I've tried SO MANY other ways to send the signal that I've lost track of what I've done so far...NOTHING WORKS. Sorry, my frustration is leaking out.

    // Working Signal
    void mySignal(const QString& myVariable);
    
    // Non-Working Signal
    void srcAddressOut(const QString& sourceAddressOut);
    
    // Working emit
    emit mySignal(number);
    
    // Non-Working emit
    emit srcAddressOut(_srcAddress);
    

    (but I've proven this signal IS emitting)

    // Working QML receiver
    onMySignal: { console.log(myVariable); statusMessages2.text = myVariable; }
    
    // Non-Working QML receiver
    onSrcAddressOut: { console.log(sourceAddressOut); statusMessages2.text = sourceAddressOut; }
    

    what is different???


  • Moderators

    @mscottm said in Signal not emitted or not received:

    When I try ANY other way to get my signal to QML, it doesn't work. I've tried SO MANY other ways to send the signal that I've lost track of what I've done so far...NOTHING WORKS.

    Can you post a compilable example of what you've tried? (Try to keep the code minimal) We can look through the code for you.

    Anyway, here's a different technique that does work: https://doc.qt.io/qt-5/signalsandslots-syntaxes.html#connecting-c-objects-to-qml-objects (It makes the connection on the C++ side rather than the QML side)



  • @JKSH - regarding posting my code - I think I can pare down the code I've added to the example, but I don't think I could figure out what to cut from the example code, and maybe how I integrated it is part of the issue...? Would it be okay to just post the pared down part that I added to the example code?


  • Moderators

    @mscottm said in Signal not emitted or not received:

    I think I can pare down the code I've added to the example, but I don't think I could figure out what to cut from the example code, and maybe how I integrated it is part of the issue...? Would it be okay to just post the pared down part that I added to the example code?

    Sure, go ahead.



  • @JKSH

    Okay - I wasted another week and a half trying to solve this myself with no result :(

    Not sure how to pass along my minimized code - is there a way to attach a zip? Even though it's shortened, it seems like a lot to paste here.


  • Lifetime Qt Champion

    @MScottM
    Hi
    The upload here is not so cooperative with zip files.
    alt text

    So you have to use some upload service (google drive, pcloud or similar)
    that can give an URL to paste here.
    https://wetransfer.com/ can also do it with no install
    if you swich to "send as link" mode.
    using the the round [...] button.


  • Moderators

    @MScottM said in Signal not emitted or not received:

    Not sure how to pass along my minimized code - is there a way to attach a zip?

    Like @mrjj said, upload your zip file to an external file host and post the link here.

    Okay - I wasted another week and a half trying to solve this myself with no result :(
    ...
    Even though it's shortened, it seems like a lot to paste here.

    Thank you for making the effort. Upload the zip file containing your whole project (so that I can just click "build" and run it -- it doesn't matter if I need a CAN bus device); I'm happy to look through your work.



  • Here is the link to a zip file:

    https://we.tl/t-jlLJoUCTvs

    Notes:
    There is a text file needed (included in file) that goes into the build folder. Steps to test my non-working signal (in pMessageProcessor.cpp):

    CAN cable isn't needed - on running the program:
    Select 'virtualcan' from drop down
    Check 'Custom Configuration' and set 'Receive Own' to True - click OK
    At menu on top click Monitor -> P Bus
    In center box click 'Module 1'

    (Back to Can Example Window)
    Check 'Extended Format' and in the 'Frame ID' box type FF0400
    In the 'Payload' box type eight bytes, i.e. 11 22 33 44 55 66 77 88 and send

    Thank you for taking the time to take a look!


  • Moderators

    @MScottM OK, I've downloaded your code and am looking through it. I will probably post back in the next day or two.

    In the meantime, I've got a few questions:

    1. You have two different instances of pMessageProcessor in your code (one is a member variable in MainWindow, the other is in your main.cpp). Which one did you intend to use? (Similarly, you have 2 different instances of QQmlEngine)
      • An important part of minimizing your code for troubleshooting is to get rid of unneeded objects.
    2. You mentioned that this is a "learning project". Could you describe what you're focussing on learning?
      • Is it learning to use Qt's CAN classes? Learning to integrate C++ and QML? Learning how to create GUIs in QML? A combination of the above? Something else completely?


  • Hi @JKSH

    Again, thanks for taking the time to look through what I've done.

    To answer your questions in reverse order:

    1. The simple answer is 'all of the above'. A part of my job includes working with equipment that uses CAN bus to communicate, and I thought it would be interesting to learn some more about Qt while making a tool that could be useful for me when troubleshooting. Integrating QML GUIs with C++ seems like the best way to make interesting useful programs. While I've had one or two formal classes in programming (enough to make me dangerous), I'm in no way a computer science major, and I apologize for the amateur mistakes I must be making!

    2. With respect to QQmlEngine, I was wondering, and asked in one of my posts above, whether it was an issue to create a second one, and if that might be part of my problem. Regarding pMessageProcessor, I added that to main.cpp in order to get the connect statement working, as I couldn't seem to get it to work anywhere else.

    Edit: that's interesting...the forum is auto numbering my replies!


  • Moderators

    @MScottM You're most welcome! Always happy to help a willing learner.

    With respect to QQmlEngine, I was wondering, and asked in one of my posts above, whether it was an issue to create a second one, and if that might be part of my problem.

    Yes, that is definitely part of your problem. The diagram below summarizes your code:

    Connection Diagram

    (Red arrows show signal-slot connections; Blue lines show QML contexts)

    You have created 2 separate message processors and 2 separate QML engines.

    • Your first pMessageProcessor (in main.cpp) receives the MainWindow::canMessageOut() signal. However, you have not connected anything to this pMessageProcessor's signals.
    • Your second pMessageProcessor(in mainwindow.h) has its signals connected to the signal handlers ModulePage. However, it does not receiveMainWindow::canMessageOut() so it never emits its signals.

    From the diagram, can you see what needs to happen for your code to work as you want? Try to implement the change in your code. If you can't figure it out, describe what you want to do and I'll give you some pointers.

    The simple answer is 'all of the above'. A part of my job includes working with equipment that uses CAN bus to communicate, and I thought it would be interesting to learn some more about Qt while making a tool that could be useful for me when troubleshooting.

    When learning multiple new concepts, I recommend the "divide and conquer" approach. Focus on one thing at a time -- you will be able to learn much faster this way. Mixing multiple concepts into the same study makes it much harder to troubleshoot things.

    While I've had one or two formal classes in programming (enough to make me dangerous), I'm in no way a computer science major, and I apologize for the amateur mistakes I must be making!

    You don't need a computer science major to learn Qt, but you do need to be systematic and patient.

    Integrating QML GUIs with C++ seems like the best way to make interesting useful programs.

    You can absolutely make interesting useful programs using Qt Widgets too.

    Since the CAN example already has a solid GUI based on Qt Widgets, I highly recommend you first learn by adding new functionality to that example by implementing new widgets. Leave QML out of it for now.

    Add QML after you have mastered widgets, or implement QML in a separate, smaller, and simpler project which doesn't have such a complex web of connections.



  • Hi @JKSH ,

    THANK YOU!! Your diagram made what was happening very clear. I'll try to use something like that in the future when plotting connections.

    I made the following changes, and now it works as I expected it to:

    I deleted the contextProperty statements and moved the class declaration and connect statement out of main.cpp and placed them in MainWindow.cpp, as well as creating the QQmlApplicationEngines and setting the engine context properties in the same place - eliminating 'engine1', and that was basically all it took!

    When learning multiple new concepts, I recommend the "divide and conquer" approach. Focus on one thing at a time -- you will be able to learn much faster this way. Mixing multiple concepts into the same study makes it much harder to troubleshoot things.

    I appreciate this advice, and this is actually what I try do. When I tackle a new concept, I'll create a small application that does only the thing I'm trying to learn, but then I'll try to fit that functionality into a larger application that has more going on. This is actually sort of a culmination of trying different concepts, but I obviously bit off more that I could chew. This is the first time I've tried taking code that was complete and working (the CAN example) and adding my own functionality. I have made other small applications that combine QML and C++.

    Since the CAN example already has a solid GUI based on Qt Widgets, I highly recommend you first learn by adding new functionality to that example by implementing new widgets. Leave QML out of it for now.

    Add QML after you have mastered widgets, or implement QML in a separate, smaller, and simpler project which doesn't have such a complex web of connections.

    I find QML very easy to work with and Qt Widgets, not so much, (although I have created small GUI's strictly with Qt Widgets before). This tells me you're probably right about learning more about the Widgets framework.


  • Moderators

    @MScottM said in Signal not emitted or not received:

    I made the following changes, and now it works as I expected it to:

    Congrats! Happy coding.

    Your diagram made what was happening very clear. I'll try to use something like that in the future when plotting connections.

    A pen and paper are very powerful programming tools.

    I appreciate this advice, and this is actually what I try do. When I tackle a new concept, I'll create a small application that does only the thing I'm trying to learn, but then I'll try to fit that functionality into a larger application that has more going on.... I have made other small applications that combine QML and C++.

    OK, it sounds like you have a good systematic workflow.

    I find QML very easy to work with and Qt Widgets, not so much, (although I have created small GUI's strictly with Qt Widgets before). This tells me you're probably right about learning more about the Widgets framework.

    The ranking from easiest-to-hardest is roughly:

    1. Pure QML
    2. Pure C++
    3. Mixing QML and C++

    #3 depends on your ability to do #1 and #2, so you'll most likely benefit from strengthening your understanding of C++.


Log in to reply