Signal/Slot newbie



  • Hi, I just made my first application in QT (with QT5, QT Creator and QT Quick) and I've got the exe running and everything, but being a newbie and not used to neither OOP nor QML I feel a bit insecure. The program has worked as expected the last 50 times but at some point earlier on, it gave some weird unexpected results. It would feel better if I felt sure I knew what I was doing, and/or had a way of testing it in more detail. My code:

    @//MyHandling.h:

    #ifndef MYFILE_
    #define MYFILE_

    #include <QObject>

    class MyHandling : public QObject {
    Q_OBJECT
    public slots:
    QString handleMyFile(bool Selection1, bool Selection2, QString inputFileName);
    signals:
    void valueChanged(void);
    };

    #endif

    //-----------
    //main.qml:

    import QtQuick 2.1
    import QtQuick.Controls 1.1
    import QtQuick.Layouts 1.1
    import QtQuick.Dialogs 1.0

    Rectangle {
    x: 0
    width: 500
    height: 370
    color: "#d7dee0"
    opacity: 1

    Item {
         id: item
        // width: 100; height: 100
    
         signal valueChanged()
     }
     
        Button {
        id: myButton
        x: 402
        y: 236
        width: 76
        height: 57
        text: qsTr("MyButton")
        z: 5
        onClicked: {
            textError.text = MyHdlObject.handleMyFile&#40;Selection1.checked, Selection2.checked,  inputFileName.text, outputFileName.text&#41;
            item.valueChanged() }
    }
    
     
     /* Some code */
    

    }

    //---------------
    //main.cpp:

    #include <QtGui/QGuiApplication>
    #include "qtquick2applicationviewer.h"

    #include "MyHandling.h"
    #include <QFile>
    #include <QQmlContext> //setContextProperty

    QString MyHandling::handleMyFile(bool Selection1, bool Selection2, QString inputFileName, QString outputFileName)
    {

    /* Some code */

    }

    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);

    QObject *item;
    QtQuick2ApplicationViewer viewer;
    viewer.rootContext()->setContextProperty("MyHdlObject", new MyHandling());
    viewer.setMainQmlFile&#40;QStringLiteral("qml/MyApp/main.qml"&#41;);
    viewer.showExpanded();
    item = (QObject *) viewer.rootObject();
    

    //Point A
    MyHandling sh1;
    QObject::connect(item, SIGNAL(valueChanged()),
    &sh1, SLOT(handleMyFile()));
    //Point B

    return app.exec();
    

    }
    @

    I have one very specific question: If i delete the text between "Point A" and "Point B" it still works just as well as with it. But I thought that part was vital for the signal/slot stuff. I deleted it as a test expecting it to fail then. Or does it perhaps just work less reliably with that part deleted? The only thing that happens is that I get a warning that "item" isn't used.

    Another question is: Is there a way you can recommend for testing the signal transfers between QML and C++, to make sure it works reliably? Obviously my idea to delete the whole signal/slot part expecting communication to die, is not a good test at all.

    And a general question is if my communication between C++ and QML seems to be doing what it should?

    I read several posts on similar subjects, especially those with example code, but for some reason none of those examples work (no matter if posted on qt-project, stackoverflow or Nokias site), I'm guessing it is due to changes in QT parts or something.


  • Moderators

    You are handling the file in QML, explicitly:
    @
    textError.text = MyHdlObject.handleMyFile(Selection1.checked, Selection2.checked, inputFileName.text, outputFileName.text)
    @

    That is why it works. It uses the object you create in your main C++ file:
    @
    viewer.rootContext()->setContextProperty("MyHdlObject", new MyHandling());
    @

    The other, created on a stack, is not used by the engine at all: you create it later and don't assign it to the root context.


  • Moderators

    Since you are a newbie, I'll also give you some advice:
    @
    QString handleMyFile(bool Selection1, bool Selection2, const QString &inputFileName);
    signals:
    void valueChanged() const;
    @

    Pass all Qt classes (especially containers, QString, QByteArray, etc.) as const references: this way it's faster and less memory-consuming (as Implicit Sharing kicks in).

    Always define singals as const: they always are const, and it allows some further optimisations when you declare them as such.



  • Thanks. Regarding stack etc I understand what you are saying, I suppose, but I wouldn't know what to change exactly. Haven't come across any description of stack usage when reading about QT/QML/C++ but I'm guessing you're talking about function call parameters since these AFAIK are on the stack and signals & slots are actually functions. But specific help on what to change would be helpful.

    I read various examples and tutorials etc. "This":http://woboq.com/blog/how-qt-signals-slots-work.html doesn't say much about the QML syntax. "This":http://www.developer.nokia.com/community/wiki/Reading_and_writing_files_in_QML (which has errors if I try to build & run it) doesn't even use ::connect. It uses e g Q_INVOKABLE (which I would have expected I might have use for) which the other example doesn't. Seems to be some options here.

    Thanks for the advice on speed impact. I have seen others use const for parameters before, didn't know why, I'm guessing it tells the compiler that they are pointers whose value won't change? I suppose that means I could/should add const also for the return value? I haven't seen anyone else using const for signals though.


  • Moderators

    I don't want to flood you by details. The interaction between C++, meta object system and QML is deep and complicated, especially for a newcomer. I suggest you to take it easy and try to develop some training projects step by step, to gradually get the idea about the whole system.

    [quote]Regarding stack etc I understand what you are saying, I suppose, but I wouldn’t know what to change exactly[/quote]

    Remove those lines (86-88) completely, you do not need them. What you do there is create a new object that is completely separate from the one you create in line 81. They don't know about each other, and neither does the QML engine. Don't focus on the "stack" word: the situation would have been exactly the same if you created it as pointer (with "new") there.

    [quote]I read various examples and tutorials etc. [...] doesn’t even use ::connect[/quote]

    Meta object system is really powerful, QML uses it everywhere. Here is the difference:

    • when you run, in your QML/JS code, this expression: MyHdlObject.handleMyFile(...) you are actually invoking a function (handleMyFile) from object you have added as a root context property (MyHdlObject, added in line 81 of C++ code). To do that, this method has to be marked as Q_INVOKABLE or be a slot (all slots are invokable through meta object system)
    • when you connect a signal to a slot (does not matter where: C++, JavaScript, QML) you do not invoke any function yourself. Meta object system will invoke the slot after your application emits the signal: and only then

    [quote]I haven’t seen anyone else using const for signals though.[/quote]

    I'm going through the documentation now and it seems that signals are ot being marked as const there. I believe this to be a bug. If you don't mark a signal as const, the compiler will not allow you to emit it in a const function. And in general, it is good practice to mark all functions that can be const as const: this keyword - as you correctly assume - tells the compiler "this stuff should not change the state of the current object". This way it achieves 2 goals: on one hand the compiler will throw an error if you accidentally try to change the state inside a const function, and on the other - it allows the compiler to optimize the code more aggressively (at least in theory).



  • Thanks for all the input. I suppose you are saying that at this stage I might as well delete the signal/slot part. Actually I don't mind doing that as long as it still works reliably. But if I understand you correctly, my code communictes very directly so there should be no problem of unreliability, the "only" drawback would be that I'm not doing it the way the Qt inventors intended, and it is not very pretty, but fine for a small one-man project.

    It seems to work reliably 99 times out of 100 but sometimes strange things happen. If you say I haven't caused this myself by bad coding then I would suspect the Qt environment, since I usually run it under Qt Creator (ctrl-R) and I've seen some quirks in Qt Creator both during debugging,linking and running which usually disappears after some things like restarting, cleaning, rebuildng etc. (BTW since a week I can't open QML files graphically in Qt Creator an it's not just my project but also e g the examples so I think I'll have to reinstall it again, so it doesn't seem to be bug free).

    I have two goals with this: One is to get it to work (it is not just for test, I intend to use this code for a fun shareware application), the other is to try Qt for the first time. I suppose that if I want to do more projects in Qt which use the Quick part, I should read up on the basics then.


  • Moderators

    [quote author="DavidGGG" date="1393168856"]But if I understand you correctly, my code communictes very directly so there should be no problem of unreliability, the "only" drawback would be that I'm not doing it the way the Qt inventors intended, and it is not very pretty, but fine for a small one-man project. [/quote]

    Both ways are valid, fully supported and "official", don't worry :)


Log in to reply
 

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