Using QProcess in QtScript
Hello everyone,
I'm trying to use QProcess from QtScript.
I've tried a lot of things, but it seems the only way I can make it build is by using Q_SCRIPT_DECLARE_QMETAOBJECT(QProcess, QObject*), and then do:
Code:
QScriptValue proc = engine.scriptValueFromQMetaObject<QProcess>();
engine.globalObject().setProperty("Process", proc);
But then I do in the script:
Code:
var n = new Process();
n.start("someapp");
And it results in TypeError: Result of expression 'n.start' [undefined] is not a function.
What am I doing wrong?
Thanks in advance
Re: Using QProcess in QtScript
Easy, Process is a QObject
You need to tell the script engine that Process is actually a QProcess.
What you have is correct but not complete. Also use qScriptRegisterMetaType()
Re: Using QProcess in QtScript
Can you be more specific?
It seems I need to specify a toScriptValue and fromScriptValue functions, but I'm not really sure how to do it.
Thanks!
Re: Using QProcess in QtScript
Something in the lines of:
Code:
{
Q_OBJECT
...
};
Q_DECLARE_METATYPE(MyObject*)
QScriptValue myObjectToScriptValue(QScriptEngine *engine, MyObject* const &in)
{ return engine->newQObject(in); }
void myObjectFromScriptValue(const QScriptValue &object, MyObject* &out)
{ out = qobject_cast<MyObject*>(object.toQObject()); }
...
qScriptRegisterMetaType(&engine, myObjectToScriptValue, myObjectFromScriptValue);
Edit: changed the code as mentioned on the Qt documentation website
Re: Using QProcess in QtScript
I had to change a bit the functions since QProcess can't be copied.
But now I'm having this issue:
Code:
/usr
/include
/qt4
/QtCore
/qmetatype.
h: In
static member function ‘
static int QMetaTypeId2<T>
::qt_metatype_id() [with T
= QProcess]’
: /usr
/include
/qt4
/QtCore
/qmetatype.
h:230: instantiated from ‘
int qMetaTypeId
(T
*) [with T
= QProcess]’
/usr
/include
/qt4
/QtCore
/qmetatype.
h:243: instantiated from ‘
int qRegisterMetaType
(T
*) [with T
= QProcess]’
/usr
/include
/qt4
/QtScript
/qscriptengine.
h:402: instantiated from ‘
int qScriptRegisterMetaType
(QScriptEngine
*, QScriptValue
(*)(QScriptEngine
*,
const T
&),
void (*)(const QScriptValue
&, T
&),
const QScriptValue
&, T
*) [with T
= QProcess]’
mainwindow.cpp:69: instantiated from here
/usr/include/qt4/QtCore/qmetatype.h:169: error: ‘qt_metatype_id’ is not a member of ‘QMetaTypeId<QProcess>’
Any ideas?
Thanks again
Re: Using QProcess in QtScript
Yes, do not forget Q_DECLARE_METATYPE
Re: Using QProcess in QtScript
Right... I thought that was implicit since it's already a QObject...
But now:
Code:
/usr
/include
/qt4
/QtCore
/qprocess.
h: In function ‘
void* qMetaTypeConstructHelper
(const T
*) [with T
= QProcess]’
: /usr
/include
/qt4
/QtCore
/qmetatype.
h:196: instantiated from ‘
int qRegisterMetaType
(const char*, T
*) [with T
= QProcess]’
mainwindow.cpp:4: instantiated from here
/usr
/include
/qt4
/QtCore
/qprocess.
h:224: error
: ‘
QProcess::QProcess(const QProcess
&)’ is
private /usr/include/qt4/QtCore/qmetatype.h:142: error: within this context
:) this isn't as easy as it sounded... at least to me...
Re: Using QProcess in QtScript
:-)
This isn't easy :-)
Wrap your QProcess in a QSharedPointer.
This whole QScript mess is very complex. On one hand you have to have copy constructors, but on the other hand, they are not allowed.
You can solve this by using a QSharedPointer
Re: Using QProcess in QtScript
I'm going to come out as the stupidest guy in here :D but... how can I wrap it with an object that isn't a QObject?
Re: Using QProcess in QtScript
Note: I didn't compile this, so there might be a syntax error.
Example:
Code:
QScriptValue qScriptValueFromProcess(QScriptEngine *engine, const QSharedPointer<QProcess> &object)
{
return engine->newQObject(object.data());
}
void qScriptValueToProcess(const QScriptValue & value, QSharedPointer<QProcess> & object)
{
}
Q_DECLARE_METATYPE(QSharedPointer<QProcess>)
QScriptValue processValue = m_engine->scriptValueFromQMetaObject<QProcess>();
m_engine->globalObject().setProperty("Process", processValue);
qScriptRegisterMetaType(m_engine, qScriptValueFromProcess, qScriptValueToProcess);
m_engine is a member variable containing a pointer to a script engine.
Re: Using QProcess in QtScript
Great, so now it built, but it's the same problem as before, I can declare a variable, assign new Process(), but when I call variable.start("ls") it's the same error...
Any ideas?
Re: Using QProcess in QtScript
Ohh now I remember.
The functions you want to use need to be defined as a property or a slot :-(
Try the kill() or terminate() functions, they will work.
You can write a wrapper, which is just a QProcess subclass defining the functions as slots.
Sigh... now I remember why it took me a week to get the Qt Creator cpp parser to work in scripts.
Re: Using QProcess in QtScript
GREAT!!! You're right...
At least I have some kind of idea on how to do this... because I'll need to wrap a lot more objects probably :)
Thanks a lot tbscope...
Re: Using QProcess in QtScript
I just tried it, and this works:
Note, I created a widget with a plain text edit and a button.
Header
Code:
{
Q_OBJECT
public:
~MyProcess() {}
public slots:
void startMyProcess(const QString& proc);
};
{
Q_OBJECT
public:
explicit Widget
(QWidget *parent
= 0);
~Widget();
public slots:
void runScript();
private:
Ui::Widget *ui;
QScriptEngine *m_engine;
};
Implementation:
Code:
QScriptValue qScriptValueFromProcess(QScriptEngine *engine, const QSharedPointer<MyProcess> &object)
{
return engine->newQObject(object.data());
}
void qScriptValueToProcess(const QScriptValue &, QSharedPointer<MyProcess> &)
{
}
Q_SCRIPT_DECLARE_QMETAOBJECT
(MyProcess,
QObject*)Q_DECLARE_METATYPE(QSharedPointer<MyProcess>)
void MyProcess
::startMyProcess(const QString &proc
) {
start(proc);
}
ui(new Ui::Widget),
m_engine(new QScriptEngine)
{
ui->setupUi(this);
QScriptValue processValue = m_engine->scriptValueFromQMetaObject<MyProcess>();
m_engine->globalObject().setProperty("Process", processValue);
qScriptRegisterMetaType(m_engine, qScriptValueFromProcess, qScriptValueToProcess);
connect(ui->buttonRun, SIGNAL(clicked()), this, SLOT(runScript()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::runScript()
{
QScriptValue resultValue = m_engine->evaluate(ui->textScript->toPlainText(), "test");
if(resultValue.isError())
qDebug() << "Error: " << resultValue.toString();
}
Re: Using QProcess in QtScript
When I try something just like you did I get "QProcess: Destroyed while process is still running"... but with static functions it works... I'm running this on Linux, may be that's the problem, I don't know... I've created a test slot that just prints a string, and it works, so this isn't a problem of calling a non-static member function...
For now I can do with the static ones, we'll see how it goes with other classes...
Thanks again for everything!
Re: Using QProcess in QtScript
You might want to keep a private pointer to an existing QProcess in the wrapper.
I did something similar here:
http://gitorious.org/qt-creator-stat...68de862ba7527b
And done a bit different:
http://doc.qt.nokia.com/4.7/script-customclass.html
Re: Using QProcess in QtScript
Thanks for the links...
Now, I've got to handle (for now) one type of scripts. What they need to do is a couple of file operations (create some empty dir, check some file for existence, etc... nothing fancy), and then start a new process with certain arguments. So, that's kind of worked out with all that's already discussed, but there's another issue: it'll be good to have each script to set up its own UI elements in a more general dialog from the application.
I've only worked with non-scripts plugins in qt... and they handle themselves quite differently, obviously. If I were using this kind of plugins, I'd probably just do something like the setupUi function from the qt designer generated files, and have a slot I can call from the main app to start the process that the plugin represents (all the other stuff would be handled from the script itself and the generated UI). So when the app starts, I load every plugin, execute setupUi(some_container), and later on trigger the execute slot; after that the plugin will handle all the UI signals that correspond to it.
How can I port this idea to a plugin implemented with qtscript?