[solved] slots and signals, any good tutorial and some help ?



  • I read the Qt manual about signals and slots and I understood how this signals and slots system works - in theory. In practice, I still don't know how to actually use that system in code. For instance, I have a QSlider object that, when I drag the slider, I'd like it to notify the new slider value in a qDebug message.

    Can someone link me a good practical use tutorial? And if that's not too much "do my homework for me", could you give me an example code for outputting the new slider position in a qDebug message, please?

    Thank you in advance to anyone! :)


  • Moderators



  • Nice one, thanks!

    Now, how may I use it to output to qDebug() ? Should I create my own signal and slot for this?



  • Hello,

    in Your class header You should create Your own slot and then in implementation of this slot You can insert qDebug() for outputting.

    Here's a small example
    @
    class myClass : public QWidget // 1
    {
    Q_OBJECT // 2

    ///   .... some code
    

    // slots section:
    public slots: // 3
    void slotPrintSliderPostion( int iPos );
    }@

    Here are some comments for the numbers above:

    1. To use the signal/slots feature You need to derive from QObject class. QWidget derives from it either.
    2. "Exlpenation why this macro is important!":http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#Q_OBJECT
    3. Slots are defined in this kind of section

    To connecto You slot You can write something like this in Your constructor:
    @
    Q_ASSERT( connect ( pSlider, SIGNAL(sliderMoved(int), this, SLOT(slotPrintSliderPostion) );
    @
    "Q_ASSERT description":http://qt-project.org/doc/qt-5.0/qtcore/qtglobal.html#Q_ASSERT

    And finally example slotPrintSliderPostion implementtion:
    @
    void myClass:: slotPrintSliderPostion(int iPos)
    {
    qDebug() << "Position changed" << iPos;
    }@

    Hope this will help You :)

    Robert



  • Hey Robert, thank you very much!
    Problem is that the code you wrote is not working. Ok, there was a round bracket missing, no issues fixing that. But anyway, When I connect the signal with the slot in my class at runtime I get this:
    @QObject::connect: No such signal QWidget::sliderMoved(int) in ......\projects\Filter\filter.cpp:35@
    My class is derived from QWidget and inherits a QSlider object pointer:
    @class Filter : public QWidget{
    public:
    /*********** De/Contructor ***********/
    Filter(QWidget * parent=0, Qt::WindowFlags flags = 0, uint frequency=0, uint bandWidth=1000, char gain=0, char min=-6, char max= 6, bool lock=false, bool bypass=false);
    ~Filter();

    /*********** Getters ***********/
    // some getter functions here

    /*********** Setters ***********/
    // some setter functions here

    private:
    /* Filter properties */
    // some filter attributes here

    /* Filter control objects */
    QSlider * GainSlider; // The slider object I want to monitor the slider position change

    public slots:
    void slotPrintSliderPostion(int iPos);
    };@
    The GainSlider control which I'd like to monitor the slider change is created in the Filter class constructor.
    @Filter::Filter(QWidget * parent, Qt::WindowFlags flags, uint Frequency, uint Bandwidth, char Gain, char Min, char Max, bool Lock, bool Bypass){
    /* some less important code here */

    /* Creating the filter controls */
    GainSlider = new QSlider;
    GainSlider->setParent(this); // assigning the new QSlider to this QWidget
    GainSlider->setRange(Min, Max);
    GainSlider->setSliderPosition(Gain);

    connect(GainSlider, SIGNAL(sliderMoved(int)), SLOT(slotPrintSliderPostion(int)));
    /*
    the use of Q_ASSERT will result in a Visual C++ Runtime error
    Q_ASSERT(connect(GainSlider, SIGNAL(sliderMoved(int)), SLOT(slotPrintSliderPostion(int)))));
    */
    }@

    Can you tell me what's wrong here?
    Also, when I run using Q_ASSERT() at runtime I get a Visual C++ Runtime error saying "The application has requested the Runtime to terminate in an unusual way". Why is that?



  • Ok,

    I wrote that code without compiling it ;), so there might be some problems like missing semicolon after class last bracket ;). I'm running Windows at the moment, where I don't have any C++/Qt tool to compile the code...

    Problem: QObject::connect: No such signal QWidget::sliderMoved(int) in ......\projects\Filter\filter.cpp:35
    Solution: try to add Q_OBJECT macro to Your class
    @
    class Filter : public QWidget{
    Q_OBJECT //!!
    public:
    //....
    };
    @

    Problem: Q_ASSERT and Visual. I can't help You with this, because I code in Qt only on Linux.
    Possible solution 1: try regular assert from "C++ assert":http://www.cplusplus.com/reference/cassert/assert/
    Possible solution might also be here: "StackOverflow topic":http://stackoverflow.com/questions/13893122/q-assert-has-different-behavior-when-my-project-is-built-in-visual-studio-vs-qt

    BTW: Which Qt version do You use?
    Robert :)



  • I'm using Qt 5.1.1 with mingw32 and mingw64 (gcc 4.8 compiler).

    Adding Q_OBJECT to the class results in the "undefined reference to `vtable for Filter'" error. I think it's not necessary since QWidget is already a Q_OBJECT and calling this macro again breaks things.
    Calling C++'s assert doesn't change things, it would only allow me to use a [Retry][Terminate][Ignore] dialog which won't crash the application so I can keep using it.

    I'll try a few different options like monitoring the Filter class instead of the QSlider object, I hope to get a working signal-slot communication, and then I may look further in this issue.


  • Lifetime Qt Champion

    When adding/removing the Q_OBJECT macro, qmake must be run again in order to generate respectively remove moc generated code for your class.

    Q_OBJECT must be added as soon as you want to add signals and slots in your classes.



  • Nevermind! I found the issue!

    For those like me who have manually added Qt versions and compilers (in my case mingw32 and mingw64) you should remember that qmake doesn't always run automatically. For this reason adding Q_OBJECT to any class will result in the error "undefined reference to `vtable for YourClassHere’". But if you don't add such macro to the class you won't get the signals and slots on your class.
    The solution is to manually run qmake by doing right-click on the project name in QtCreator's Projects pane and then select "Run qmake". This will generate all the necessary code needed for the signals and slot system (vtable is one of them).

    I now successfully connected my slider(s) to qDebug using the exact code I had two posts ago ( http://qt-project.org/forums/viewreply/150095/ ) by only adding Q_OBJECT to the class and manually running qmake.

    Thank you for your assistance Robert, and thank you for your help too JKSH :)


  • Moderators

    [quote author="T3STY" date="1384122716"]Nevermind! I found the issue![/quote]Glad to hear :) Happy coding! Thank you for sharing your solution and explanations.

    [quote author="poorBob" date="1384103644"]
    @
    Q_ASSERT( connect ( pSlider, SIGNAL(sliderMoved(int), this, SLOT(slotPrintSliderPostion) );
    @
    [/quote]You don't want to put connect(), or any other function with side effects, inside Q_ASSERT(). Everything inside Q_ASSERT() will disappear in a Release build, meaning that your connection will not be made.



  • Oh, I missed that point on Q_ASSERT()... I'll be careful using it then. I must say though that it's very useful when you're not sure the code will behave correctly, so I am using it to keep the application working even if any fault happens.

    BTW, another thing related to Q_OBJECT: header and source must be separated in split files (.h and .cpp), and the Q_OBJECT macro must be called in the class definition in the header file. Including the source in the same file as the headers causes a compilation error. I'm not really sure why is that, but it's good to know there is a workaround.


  • Lifetime Qt Champion

    You can use a variable for that.

    @bool success = connet(pSlider, SIGNAL(sliderMoved(int)), SLOT(slotPrintSliderPosition()));
    Q_ASSERT(success);@

    What do you mean by including the source in the same file as the header ?



  • I mean doing like this:
    @class myclass : public QWidget{
    Q_WIDGET
    myclass();
    ~myclass();
    }

    /* when you define any class function together with the class prototype
    a lot of compilation error related to vtable or so will popup from nowhere
    even if the code syntax and semantics is right */
    myclass::myclass(){
    // do some stuff here
    }@

    An example of this can be found here:
    http://stackoverflow.com/questions/9272047/undefined-reference-to-vtable-for-digitalclock-undefined-reference-to-digit?lq=1
    and here:
    http://stackoverflow.com/questions/6367735/qt-error-undefined-reference-to-vtable-for-thread?rq=1
    In this last link, the 2 answer explains that the meta-object compiler will only run on header files, not on source files (like .cpp), and that's what causes the issue.

    Simply put, separating a class in .h and .cpp files will avoid this issue.


Log in to reply
 

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