Как спать во встроенном Python в QT-приложении - PullRequest
1 голос
/ 28 мая 2011

Я встраиваю 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 Ответ

0 голосов
/ 06 июля 2011

Этот ответ является общим и может не работать с платформой 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 () должен разрешать запуск только одного события, следующего следующего из списка вызовов событий, иначе он не вернется, пока не будут обработаны все события.

...