Как спать во встроенном Python в QT-приложении
Я встраиваю Python в 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, "l", &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, METH_VARARGS, "."},
{"sleep", mysleep, METH_VARARGS, "Sleep."},
{NULL, NULL, 0, NULL}
};
static PyModuleDef EmbModule = {
PyModuleDef_HEAD_INIT, "obu", NULL, -1, EmbMethods,
NULL, NULL, NULL, 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();
}
1 ответ
Этот ответ является общим и может не работать с платформой 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
Однако в среде графического интерфейса вы также хотите продолжать проверять и запускать любые события, которые могут произойти, эта функция этого не делает.
поэтому вам нужна новая функция, которая выглядит так:
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) {
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, если существует способ реализовать функцию handleEvents() с QT, это решение должно решить вашу проблему.
Примечание: это заставляет компьютер ждать не менее n секунд, в случае обработки события оно должно быть завершено, прежде чем цикл сможет снова проверить время.
Кроме того, handleEvents() должен разрешать запуск только одного события, следующего следующего из списка вызовов событий, иначе он не вернется, пока не будут обработаны все события.