I've made my application scriptable by creating a derived QThread class, where I add multiples QObject class in order to access their functions via the command line.
void commandLine::addObject(QObject *obj, QString name)
{
QScriptValue sv = m_scriptEngine.newQObject(obj);
m_scriptEngine.globalObject().setProperty(name, sv);
qObjectMap.insert(std::pair<QString, QObject *>(name, obj));
}
After the run() call, the class enter in an infinite loop, using m_scriptEngine to evaluate every command line entered.
In my (simplified) main I do :
simuCLI cli;
simuCore core;
cli.addObject(&core, "core");
simuUI ui;
connect(&ui, SIGNAL(start()), &core, SLOT(start()));
But when I call start() from my GUI and from my script, results are differents
My application architecture is like the following :
Core -> StateMachine -> Machine -> Communication
Start from UI works great.
Start from command line execute the code, but don't launch the QStateMachine and it emit signals, but never receive them.
Communication
sends commands to Machine
by emiting signals received in Machine
. It works if I've call core::start() from my UI
If I call core::start() using my command lines signal is emited but never received.
void WL::WL()
{
std::cout << "wl cst" << std::endl;
mLectMotStateMachine.setInitialState(sNoCard);
mLectMotStateMachine.start();
}
void WL::enterNoCard()
{
std::cout << "no card" << std::endl;
}
Ouput :
start() from UI :
wl cst
no card
start() from command line :
wl cst
As you can see, the state machine never enter in it first state, like it never launch.
So my questions are :
1 - In wich thread is executing start() if I call it from command line ?
2 - How can I debug signals ? (best answer I've found)
3 - Is there a way to see every Signals connection at a time 't' on execution
4 - How can I know in which thread I am on execution ?
5 - Have you any ideas of why my code isn't working only when I use the command line ?
Your problem is that it is an error to directly call thread-unsafe methods in the objects that reside in other threads. I presume that the simuCore
object is a QThread
and creates a bunch of other objects in its thread. Those objects cannot be accessed from other threads directly unless you make their methods thread safe (you demonstrably don't).
The answers are:
You can check it. Within the start()
method, add:
qDebug() << QThread::currentThread();
You'll see that it's the same thread as qApp->thread()
, also known as the main thread or the gui thread.
I don't know what you mean by debugging signals. The signal-slot mechanism obviously works, so what is there to debug?
Why would you need that? You're the one who is making (and breaking) the connections, so you can certainly add debug output at the point where you make and break those connections. No magic to it.
QThread::currentThread()
.
Because you're:
Calling thread-unsafe methods from threads other than the thread where the object resides.
Deriving from QThread
when you shouldn't.
You should, instead, simply move the script engine object to a plain dedicated QThread
(no subclassing), and use thread-safe method invocation to evaluate the command lines. Signal-slot connections are thread-safe, as well as QMetaObject::invokeMethod
.
For example:
#include <QCoreApplication>
#include <QScriptEngine>
#include <QThread>
class ScriptEngine : public QScriptEngine {
Q_OBJECT
Q_SIGNAL void evaluateSignal(const QString &);
public:
Q_SLOT void evaluate(const QString & str) { QScriptEngine::evaluate(str); }
/// A thread-safe evaluate()
Q_SLOT void safeEvaluate(const QString & str) { emit evaluateSignal(str); }
explicit ScriptEngine(QObject * parent = 0) : QScriptEngine(parent) {
connect(this, &ScriptEngine::evaluateSignal, this, &ScriptEngine::evaluate);
}
};
class Thread : public QThread {
// A thread that's safe to destruct, like it ought to be
using QThread::run; // final
public:
~Thread() { quit(); wait(); }
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
ScriptEngine engine;
Thread worker;
engine.globalObject().setProperty("qApp", engine.newQObject(qApp));
engine.moveToThread(&worker);
worker.start();
QMetaObject::invokeMethod(&engine, "evaluate", Q_ARG(QString, "print('Hi!')"));
engine.safeEvaluate("print('And hello!')");
engine.safeEvaluate("qApp.quit()");
return app.exec();
}
#include "main.moc"