如何使用从外部脚本调用的回调发送信号? [英] How to send signal using callback called from external script?

查看:102
本文介绍了如何使用从外部脚本调用的回调发送信号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介

我正在尝试根据嵌入式python脚本中的计算状态更新QT GUI元素.我能够从python中提取所需的值,但是无法设置对c ++对象的引用以使其正常工作.

I'm trying to update QT GUI element basing on the state of calculations in embedded python script. I'm able to extract required values from python, but can't set a reference to c++ object to make it work.

详细信息

假设以这种方式(在calc.cpp中)调用python代码:

Let's assume python code is called (in calc.cpp) this way:

void class_name::transfer(varA, varB, varC)
{
    Py_Initialize();
    emit inprogress(70); //HERE IT WORKS
    object module = import("__main__");
    object name_space = module.attr("__dict__");
    exec_file("MyModule.py", name_space, name_space);

    object MyFunc = name_space["MyFunc"];
    object result = MyFunc(varA, varB, varC, callback);

    double ret = extract<double>(result);
    Py_Finalize();
}

void class_name::callback(double t_prog, double t_final)
{
    progr = (double)t_prog / t_final * 100;
    cout << progr; //To check if value is updating (It is)
    emit inprogress(progr); //HERE IT FAIL
}

callbackstatic成员函数(在calc.cpp中),我用来提取一些值,指示python脚本内部的计算是在哪个阶段.它是从python脚本(MyModule.py)循环调用的:

callback is a static member function (in calc.cpp) I use to extract some values, indicating on which stage is calculation inside python script. It is called in loop from python script (MyModule.py):

while r.successful() and k < num_steps:
    r.integrate(r.t + delta_t)
    callback(r.t, t_final)

但是编译失败并出现以下错误:

However the compilation fails with following error:

非法调用非静态成员函数

illegal call to nonstatic member function

非静态成员引用必须相对于特定对象

nonstatic member reference must be relative to specific object

emit inprogress(progr);

问题

我认为我应该将对对象的引用从我的c ++传递给python,然后通过回调传递回c ++ .但是我找不到一种方法来做到这一点.正确的方法是什么?

I think I should pass a reference to the object from my c++ to python, and back to c++ with callback. But I can't find a way how to do this. What's the correct way to do this?

经过测试的想法(仍然无法运行)

  1. 我试图像这样简单地传递它: void class_name::callback(double t_prog, double t_final, class_name &cssd),但是python似乎无法自动将其转换.
  2. 创建新的类对象:

  1. I was trying to pass it simple like: void class_name::callback(double t_prog, double t_final, class_name &cssd) but python seems to can't convert it automatically.
  2. Creating of new class object:

class_name cs;
emit cs.inprogress(progr);

编译没有错误,但信号从未到达插槽-它创建新对象而不是引用现有对象.

Compile without error, but signal never reach the slot - it creates new object instead of refer to existing.

推荐答案

我们需要在回调中添加一些其他状态,即对要调用其成员函数的类的实例的引用.

We need to add some additional state to the callback, namely a reference to the instance of the class whose member function we want to invoke.

为此,我们可以使用一个类.为了使功能等同于仅使用简单的静态回调函数,让我们定义operator()(即使其成为函子),并将此运算符公开给Python.

To do this, we can use a class. To make the functionality equivalent to just using a simple static callback function, let's define operator() (i.e. make it a functor), and also expose this operator to Python.

假设我们有以下应用程序类:

Let's suppose we have the following application class:

class app
{
public:
    explicit app(std::string name) : name_(std::move(name)) {}

    int run();

    void callback(double t_prog, double t_final);

private:
    std::string name_;
};

run()中,我们执行Python脚本,并希望它调用当前实例的成员函数callback.

In run() we execute our Python script, and we want it to call the member function callback of the current instance.

让我们定义以下回调处理程序类:

Let's define the following callback handler class:

class callback_handler
{
public:
    explicit callback_handler(app& a) : app_(a) {}

    void operator()(double t_prog, double t_final)
    {
        app_.callback(t_prog, t_final);
    }

private:
    app& app_;
};

我们需要将该类公开给Python,但又不想从Python创建新的实例,我们也不想复制它(尽管在这里这并不重要,因为仅出于我们的状态)由参考组成.)

We need to expose this class to Python, but don't want to be able to create new instances from Python, nor do we really want it to be copied (although it doesn't really matter here, since our state only consists of references).

BOOST_PYTHON_MODULE(cbtest)
{
    bp::class_<callback_handler, boost::noncopyable>("callback_handler", bp::no_init)
        .def("__call__", &callback_handler::operator())
        ;
};

在我们的应用程序开始时,我们需要确保在使用模块之前先对其进行初始化-在初始化Python解释器后立即调用initcbtest();.

At the start of our application, we need to make sure to initialize our module before we use it -- call initcbtest(); right after initializing the Python interpreter.

现在,我们可以按以下方式使用回调处理程序(Python代码保持不变,因为该对象是可调用的):

Now we can use our callback handler in the following manner (The Python code stays the same, since the object is callable):

    callback_handler cbh(*this);
    bp::object result = MyFunc(1, 10, 2, boost::ref(cbh));
    std::cout << "result = " << bp::extract<double>(result) << "\n";


示例代码

#include <boost/noncopyable.hpp>
#include <boost/python.hpp>

#include <iostream>
// ============================================================================
namespace bp = boost::python;
// ============================================================================
class app
{
public:
    explicit app(std::string name) : name_(std::move(name)) {}

    int run();

    void callback(double t_prog, double t_final);

private:
    std::string name_;
};
// ============================================================================
class callback_handler
{
public:
    explicit callback_handler(app& a) : app_(a) {}

    void operator()(double t_prog, double t_final)
    {
        app_.callback(t_prog, t_final);
    }

private:
    app& app_;
};
// ----------------------------------------------------------------------------
BOOST_PYTHON_MODULE(cbtest)
{
    bp::class_<callback_handler, boost::noncopyable>("callback_handler", bp::no_init)
        .def("__call__", &callback_handler::operator())
        ;
};
// ============================================================================
void app::callback(double t_prog, double t_final)
{
    std::cout << "CB(" << name_ << ") " << t_prog << " " << t_final << "\n";
}
// ----------------------------------------------------------------------------
int app::run()
{
    Py_Initialize();
    initcbtest();

    try {
        bp::object module = bp::import("__main__");
        bp::object name_space = module.attr("__dict__");
        bp::exec_file("MyModule.py", name_space, name_space);

        bp::object MyFunc = name_space["MyFunc"];

        callback_handler cbh(*this);
        bp::object result = MyFunc(1, 10, 2, boost::ref(cbh));
        std::cout << "result = " << bp::extract<double>(result) << "\n";
    } catch (bp::error_already_set&) {
        PyErr_Print();
    }

    Py_Finalize();

    return 0;
}
// ============================================================================
int main()
{
    app a("TestApp");

    return a.run();
}
// ============================================================================


Python脚本

文件MyModule.py:

def MyFunc(a, b, c, callback):
    result = 0
    for i in range(a, b, c):
        result += i
        callback(i, b)
    return result


控制台输出

CB(TestApp) 0 10
CB(TestApp) 2 10
CB(TestApp) 4 10
CB(TestApp) 6 10
CB(TestApp) 8 10
result = 20

这篇关于如何使用从外部脚本调用的回调发送信号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆