如何使用从外部脚本调用的回调发送信号?

时间:2019-03-05 19:48:16

标签: python c++ qt signals boost-python

简介

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

详细信息

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

  $employee=Employee::first()->getEmployeeName();

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 } 是一个callback成员函数(在calc.cpp中),我用来提取一些值,以指示python脚本中哪个阶段进行计算。从python脚本(MyModule.py)循环调用它:

static

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

  

非法调用非静态成员函数

     

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

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

有关

问题

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

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

  1. 我试图像这样简单地传递它: emit inprogress(progr);,但python似乎无法自动将其转换。
  2. 创建新的类对象:

    void class_name::callback(double t_prog, double t_final, class_name &cssd)

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

2 个答案:

答案 0 :(得分:1)

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

为此,我们可以使用一个类。为了使功能等同于仅使用简单的静态回调函数,让我们定义operator()(即使其成为函子),并将此运算符公开给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_;
};

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

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

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创建新实例,我们也不想复制它(尽管在这里并不重要,因为仅出于我们的状态)由参考组成)。

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

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

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

    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

答案 1 :(得分:-1)

也许问题在于您正在调用emit c_n.inprogress(progr);,其中信号progr的自变量的类型为double,而在connect(sender, SIGNAL( inprogress(int) ), ui->progressBar, SLOT( setValue(int) ) );中,信号取一个整数作为争论。在较旧的Qt版本(比Qt5版本旧)中,信号和插槽必须使用完全相同的类型,这意味着可能不会发生隐式转换。

https://forum.qt.io/topic/23302/connect-diferent-signals-and-slost-each-other/4