问题描述
|
我将Python嵌入到GUI QT应用程序中。我向UI文件中的一个按钮分配了一个信号,然后单击该脚本后运行该脚本。
当使用来自
http://docs.python.org/py3k/extending/embedding.html
我还向嵌入式模块添加了一些功能,如该页第5.4节所示。我希望能够在python脚本中添加一些延迟。由于睡眠会暂停整个应用程序,我该如何不使用睡眠来做到这一点?我猜你会用QTimer来做,它会在一段时间后唤醒python脚本,但是我不知道怎么做。
我相信我已经很接近解决方案了,因此,我尽可能不添加线程,甚至不想添加其他框架,例如PythonQT或Boost。
以下是相关代码段:
static PyObject* openDoor(PyObject *self,PyObject *args)
{
int value1 = 0;
if (!PyArg_ParseTuple(args,\"l\",&value1))
return Py_BuildValue(\"i\",-1);
opendoor(value1)
return PyLong_FromLong(value1);
}
static PyObject* mysleep(PyObject *self,PyObject *args)
{
int value1 = 0;
if (!PyArg_ParseTuple(args,&value1))
return Py_BuildValue(\"i\",-1);
// this does not work !!!
// QTimer slideShowtimer = new QTimer(this);
// connect(slideShowtimer,SIGNAL(timeout()),this,SLOT(slideShowHelper()));
// slideShowtimer->start(5000);
return PyLong_FromLong(value1);
}
static PyMethodDef EmbMethods[] = {
{\"openDoor\",openDoor,METH_VaraRGS,\".\"},{\"closeDoor\",closeDoor,{\"sleep\",mysleep,\"Sleep.\"},{NULL,NULL,NULL}
};
static PyModuleDef EmbModule = {
PyModuleDef_HEAD_INIT,\"obu\",-1,EmbMethods,NULL
};
static PyObject*
PyInit_emb(void)
{
return PyModule_Create(&EmbModule);
}
// taken from python docs
void MainWindow::on_ScriptButton_clicked()
{
PyObject *pName,*pModule,*pFunc;
PyObject *pArgs,*pValue;
int i;
PyImport_AppendInittab(\"emb\",&PyInit_emb);
Py_Initialize();
pName = PyUnicode_FromString(\"multiply\");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule,\"run\");
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(1);
for (i = 0; i < 1; ++i) {
pValue = PyLong_FromVoidPtr(this);
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr,\"Cannot convert argument\\n\");
}
PyTuple_SetItem(pArgs,i,pValue);
}
pValue = PyObject_CallObject(pFunc,pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf(\"Result of call: %ld\\n\",PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,\"Call Failed\\n\");
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr,\"Cannot find function \\n\");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
;
}
else {
PyErr_Print();
fprintf(stderr,\"002 Failed to load \\n\");
}
Py_Finalize();
}
解决方法
这个答案是一般性的,可能不适用于QT框架。 (我自己不使用QT)
睡眠不起作用的原因是它基本上看起来像C ++中的以下代码
static PyObject* mysleep(PyObject *self,PyObject *args)
{
int secs = 0;
if (!PyArg_ParseTuple(args,\"l\",&secs))
return Py_BuildValue(\"i\",-1);
long start = gettimestamp(); // This function should return a unix timestamp
long now = start;
while (now < start + secs) {
now = gettimestamp(); }
return PyLong_FromLong(now-start); }
请注意,这对于您的函数来说是个好主意,它返回程序实际休眠的时间,而不是输入值。如您可能需要在代码中知道这段时间。
该函数将由python调用
但是,在GUI环境中,您还希望继续检查并运行此功能无法执行的任何事件。
因此,您需要一个新的功能,如下所示:
static PyObject* mysleep(PyObject *self,-1);
long start = gettimestamp(); // This function should return a unix timestamp
long now = start;
while (now < start + secs) {
handleEvents(); // This function makes the framework check,and run events in they have occurred it will be framework spefic
now = gettimestamp(); }
return PyLong_FromLong(now-start); }
您应该检查QT文档,是否存在使用QT实现handleEvents()函数的方法,此解决方案应该可以解决您的问题。
注意:这会导致计算机等待至少n秒,如果正在处理事件,则必须先完成计算机,然后循环才能再次检查时间。
同样,handleEvents()应该只允许运行一个事件,而下一个事件调用列表必须运行,否则它将在处理完所有事件后才返回。