Qt World Summit: Submit your Presentation

[SOLVED]QVariant in signal argument and QSignalSpy

  • Hi folks,

    I have the following code:
    @emit sigEntryDataChanged(c_NameField, QVariant::fromValue(m_strName));//m_strName contains "New string"
    QSignalSpy Spy(&Entry;, SIGNAL(sigEntryDataChanged(QString, QVariant)));
    QVERIFY(Arguments[0].toString() == EntryData::c_NameField);//It is ok. The verification is passed
    QVERIFY(Arguments[1].toString() == strName);// That verification is not passed because Arguments[1].toString() yields the empty string!

    strName is the correctly set and passed to the signal emission. I have a several part of code which I try to test but all of them fails!
    It seems like some problem with signals and QVariants in signal arguments.

    Could anyone explain what the problem I've encountered?

  • Please post a complete example. From the above it looks as if you setup the signal spy after you have emitted the signal.

  • it is excerpt from the project. Signal is emitted after the QSignalSpy Spy(&Entry;, SIGNAL(sigEntryDataChanged(QString, QVariant)));

    And you can see it in the two last line in my scratch: first signal argument is received right while the second(which is QVariant) is broken. Have you ever used signals with QVariant arguments? I don't want to build a complete example to reproduce it because it will take quite a time to do it. So I just hope to find someone who have faced such a behavior already.

  • I've used QVariants with signals quite extensively. I've never had any issues with anything being broken from the Qt side of things.

    Have you double checked that there is actually a valid QVariant being emitted (i.e., QVariant::fromValue(m_strName) is all good)?

  • m_strName is good. But how can I check if the QVariant::fromValue(m_strName) is good?
    I think that it should be good as long as the argument is good.
    mlong, have you used QSignalSpy with signals which arguments are QVariants?
    It returns QList of QVariants so maybe it wraps QVAriant into QVariant somehow so I need to unwrap it before? I'll double check my code one more time, though.

  • As ZapB suggested, can you post a more complete example?

  • @QSignalSpy Spy(&Entry;, SIGNAL(sigEntryDataChanged(QString, QVariant)));@

    Does this code compile with the ';' in @&Entry;@

  • The extra semicolon is a problem with the code formatting on this site. It was discussed "here":http://developer.qt.nokia.com/forums/viewthread/7889.

  • I've made the test project:
    @#ifndef TEST_H
    #define TEST_H

    #include <QObject>
    #include <QString>
    #include <QVariant>

    class TestClass: public QObject
    void emitSignal()
    QString strFirst("First");
    QString strSecond("Second");
    emit sigTest(strFirst, QVariant::fromValue(strSecond));

    void sigTest(const QString&, const QVariant&);

    #endif // TEST_H

    @#include <QtCore/QCoreApplication>
    #include <QtTest/QSignalSpy>
    #include <QtDebug>
    #include "test.h"

    int main(int argc, char *argv[])
    QCoreApplication a(argc, argv);
    TestClass Test;
    QSignalSpy Spy(&Test;, SIGNAL(sigTest(QString, QVariant)));
    QList<QVariant> Arguments = Spy.takeFirst();
    qDebug() << "First Argument: " << Arguments[0].toString() << ", Second arg: " << Arguments[1].toString();
    return a.exec();

    And it prints: First Argument: "First" , Second arg: ""

    Project: http://www.sendspace.com/file/56i1ey

  • OK sorted it. At first I added a simple receiver class like this to test the argument passing between signals and slots:

    class Receiver : public QObject
    Receiver( QObject* parent = 0 )
    : QObject( parent )

    public slots:
    void testSlot( const QString& str, const QVariant& v )
    qDebug() << Q_FUNC_INFO;
    qDebug() << "arg1 =" << str;
    qDebug() << "arg2 =" << v.toString();

    When connected to your Test object it indeed printed out:

    void Receiver::testSlot(const QString&, const QVariant&)
    arg1 = "First"
    arg2 = "Second"

    as expected. This made me think it was a bug in QSignalSpy not being able to handle QVariant argument types correctly.

    However, digging deeper and debugging into the source code of QSignalSpy I noticed this function getting called when the signal is emitted:

    void appendArgs(void **a)
    QList<QVariant> list;
    for (int i = 0; i < args.count(); ++i) {
    QMetaType::Type type = static_castQMetaType::Type(args.at(i));
    list << QVariant(type, a[i + 1]);

    Notice that each argument is indeed wrapped in a QVariant. So your argument is getting added to the list correctly just that it is now a QString wrapped in a QVariant wrapped in a QVariant.

    So to adjust your app to properly print out the argument contents I did this:

    QList<QVariant> arguments = spy.takeFirst();
    qDebug() << "First Argument: " << arguments.at( 0 ).toString();
    QVariant v = arguments.at( 1 ).value<QVariant>();
    qDebug() << ", Second arg: " << v.toString();

    Notice the extra value<QVariant>() call since QVariant does not have a toVariant() function ;-)

    Hope this explains it.

  • ZapB, great job, thanks! You have confirmed my thoughts about wrapping, but I have not ever thought about value<QVariant>()

  • No problem, you're welcome.

  • I also got bitten by this particular nastiness, your post helped me solve it. Many thanks!

Log in to reply