简体   繁体   English

如何在 QT 应用程序中的嵌入式 Python 中休眠

[英]How to sleep in an embedded Python in a QT-application

I am embedding Python into a GUI QT-Application.我将 Python 嵌入到 GUI QT 应用程序中。 I assigned a signal to one of my buttons in my UI-file, and when it is clicked I run the script.我为我的 UI 文件中的一个按钮分配了一个信号,当它被单击时,我运行脚本。

This works when using the approach from这在使用来自的方法时有效

http://docs.python.org/py3k/extending/embedding.html 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.我还向嵌入式模块添加了一些功能,如该页面第 5.4 节所示。 I want to be able to add some delays in the python script.我希望能够在 python 脚本中添加一些延迟。 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.我想你会用 QTimer 来做,它会在一段时间后唤醒 python 脚本,但我不知道这是如何完成的。

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.我相信我非常接近解决方案,因此我不想添加线程(如果可能),甚至不想添加其他框架,如 PythonQT 或 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.这个答案很笼统,可能不适用于 QT 框架。 (I don't use QT myself) (我自己不使用 QT)

The reason sleep doesn't work is it basically looks like the following code in C++睡眠不起作用的原因是它基本上看起来像 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.请注意,它是一个好主意 function 返回程序实际休眠的时间而不是输入值。 As you may need to know this period in your code.您可能需要在代码中知道这段时间。

This function would be called by python此 function 将由 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.但是,对于 GUI 环境,您还希望继续检查和运行可能发生的任何事件,此 function 不会这样做。

so you need a new function that look like so:所以你需要一个新的 function 看起来像这样:

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.如果存在使用 QT 实现 handleEvents() function 的方法,您应该查看 QT 文档,此解决方案应该可以解决您的问题。

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.注意:这会导致计算机等待至少 n 秒,如果正在处理一个事件,则必须在循环可以再次检查时间之前完成它。

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.此外,handleEvents() 应该只允许运行一个事件,下一个要运行的事件调用列表,否则在处理完所有事件之前它不会返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM