3

How to properly connect to QObject's destroyed signal from Qt Script?

When I connect to it like to your average signal, it does not work. I did test that I removed the object and that other QObjects did get the signal, but the script function I connected to it is not invoked.

Below is the sample I'm using for testing. The most important part is the line:

_engine.evaluate("obj.destroyed.connect(function() { debug(\"obj destroyed\") })");

I'd expect it to invoke that function when obj is destroyed. The code below ensures that object is deleted when even loop already started and it also tests that the object did send destroyed signal to another QObject. What I want to fix is for the script to invoke the script function with debug("obj destroyed") after destroyed signal is emitted.

ScriptTester.h:

#ifndef SCRIPTTESTER_H
#define SCRIPTTESTER_H

#include <QtScript>
#include <QtCore>

class ScriptTester: public QObject {
    Q_OBJECT

public:
    explicit ScriptTester(QObject *parent = 0);

private slots:
    void signalTest();
    void boo();

private:
    QScriptEngine _engine;
};

#endif // SCRIPTTESTER_H

ScriptTester.cpp:

#include "ScriptTester.h"

static QScriptValue scriptDebug(QScriptContext *context, QScriptEngine *engine) {
    Q_UNUSED(engine);
    if (context->argumentCount() >= 1) {
        QString msg = context->argument(0).toString();
        for (int i = 1; i < context->argumentCount(); ++i) {
            msg = msg.arg(context->argument(i).toString());
        }
        qDebug() << msg;
    }
    return QScriptValue();
}

ScriptTester::ScriptTester(QObject *parent) :
    QObject(parent)
{
    QTimer::singleShot(0, Qt::CoarseTimer, this, SLOT(signalTest()));
    _engine.globalObject().setProperty("debug", _engine.newFunction(scriptDebug, 1));
}

void ScriptTester::signalTest() {
    QObject *obj = new QObject(this);
    _engine.globalObject().setProperty("obj", _engine.newQObject(obj));
    _engine.evaluate("obj.destroyed.connect(function() { debug(\"obj destroyed\") })");
    if (_engine.hasUncaughtException()) {
        qDebug() << "Exception:" << _engine.uncaughtException().toString();
    }
    connect(obj, SIGNAL(destroyed()), this, SLOT(boo()));

    QTimer *timer = new QTimer;
    _engine.globalObject().setProperty("timer", _engine.newQObject(timer));
    _engine.evaluate("timer.timeout.connect(function() { debug(\"timer timeout\"); obj.deleteLater(); })");
    if (_engine.hasUncaughtException()) {
        qDebug() << "Exception:" << _engine.uncaughtException().toString();
    }

    timer->setSingleShot(true);
    timer->start(100);
}

void ScriptTester::boo() {
    qDebug() << "was destroyed!";
}

Note that I don't want a hack like passing destroyed first to C++ code and then manually or by a signal informing script of that. I'm searching for an implementation that's done fully in the script.

Xilexio
  • 1,178
  • 19
  • 40

0 Answers0