开发者

How to sleep in an embedded Python in a QT-application

开发者 https://www.devze.com 2023-03-09 07:30 出处:网络
I am embedding Python into a GUI QT-Application. I assigned a signal to one of my buttons i开发者_StackOverflow中文版n my UI-file, and when it is clicked I run the script.

I am embedding Python into a GUI QT-Application. I assigned a signal to one of my buttons i开发者_StackOverflow中文版n my UI-file, and when it is clicked I run the script.

This works when using the approach from

http://docs.python.org/py3k/extending/embedding.html

I also added some functions to an embedded module as demonstrated in section 5.4 on that page. I want to be able to add some delays in the python script. How can I do this without using sleep, since sleep will halt the entire application? I guess you would do it with a QTimer, that wakes up the python script after some time, but I cannot figure out, how this is done.

I believe I am pretty close to a solution, so that I don't want to add threads if possible or even another framework like PythonQT or Boost.

Here the relevant snippet:

    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();
}


This answer is general, and may not be workable with the QT framework. (I don't use QT myself)

The reason sleep doesn't work is it basically looks like the following code in 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); }

Note its a good idea for you function to return how long the program actually sleep for rather than the input value. As you may need to know this period in your code.

This function would be called by python

However with a GUI environment, you also want to keep checking and running any events that may occur this function doesn't do that.

so you need a new function that look like so:

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); }

you should check the QT documentation if there exists a way to implement the handleEvents() function with QT, this solution should fix your problem.

Note: this cause the computer to wait a least n seconds, in an event is being handled it must be completed before the loop can check the time again.

Also handleEvents() should allow only one event to be run the next one of the event call list to be run, otherwise it won't return until all events have been handled.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号