Qt下异步使用C++调用Python文件

您所在的位置:网站首页 qt调用python脚本崩溃 Qt下异步使用C++调用Python文件

Qt下异步使用C++调用Python文件

#Qt下异步使用C++调用Python文件| 来源: 网络整理| 查看: 265

Qt项目中使用到了C++异步调用Python,这里记录一下。

环境

C++ 14,Python 2.7 ,Qt5.4.2用CMake构建,Win10 64位

CMakeLists.txt:Python部分

# Python环境配置 find_package(Python2.7 COMPONENTS Interpreter Development REQUIRED) include_directories(${PYTHON_INCLUDE_DIR}) C++ 体系复杂,且构建依赖环境,一定要注意各个环节版本是否一致。特别是系统64/32位,两种环境不能互通。 代码

C++头文件

class MyWindow : public QMainWindow { Q_OBJECT public: explicit MyWindow(QWidget *parent = 0); //销毁资源 virtual ~MyWindow(); //异步调用方法需设置为static static QString callPython(QString selectedValue); public slots: void onValueChanged(); void onComboChanged(int idx); private: //任务监听 QFutureWatcher *myWatcher; QComboBox *myCombo; QString myValue; } QFutureWatcher\:为任务监听,QString为异步任务返回值,全局初始化是为了方便获取执行结果及销毁资源,不全局申明可在onValueChanged方法中用下面的代码获取任务监听 QFutureWatcher\ *myWatcher = dynamic_cast(this->sender());

C++ CXX文件:

#include MyWindow::MyWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MyWindow), m_Model(NULL) { ui->setupUi(this); myCombo = new QComboBox(this); //...初始化combobox //绑定comboBoxchange事件 connect(myCombo, SIGNAL(currentIndexChanged(int)), SLOT(onComboChanged(int))); myWatcher = new QFutureWatcher(this); //监听任务结束事件 connect(myWatcher, SIGNAL(finished()), this, SLOT(onValueChanged())); ... } MyWindow::~MyWindow() { //销毁资源 myWatcher->cancel(); myWatcher->waitForFinished(); delete myWatcher; } void MyWindow::onComboChanged(int idx) { QString selectedValue = myCombo->currentData().value(); QFuture myFuture = QtConcurrent::run(MyWindow::callPython, selectedValue); cacWatcher->setFuture(myFuture); } QString MyWindow::callPython(QString selectedValue){ QString result = ""; if(Py_IsInitialized() == 0){ Py_Initialize(); } QString filename = "py文件路径"; QFileInfo filepath = QFileInfo(filename); QString path = filepath.absolutePath(); PyObject *sys = PyImport_ImportModule("sys"); PyObject *syspath = PyObject_GetAttrString(sys, "path"); PyList_Insert(syspath, 0, PyString_FromFormat(path.toStdString().c_str())); filename = filepath.fileName().split(".")[0]; PyObject *pName = PyString_FromString(filename.toStdString().c_str()); PyObject *pModule = PyImport_Import(pName); if (pModule != NULL) { PyObject *pDict = PyModule_GetDict(pModule); PyObject *pFunc = PyDict_GetItem(pDict, PyString_FromString("函数名称")); if (pFunc != NULL) { PyObject *pyParams = PyTuple_New(2); PyTuple_SetItem(pyParams, 0, Py_BuildValue("s", selectedValue.toStdString().c_str())); PyObject *pythonResult = PyObject_CallObject(pFunc, pyParams); result = QString(PyString_AsString(pythonResult).c_str()); } else { msgBox.setText("can't find function"); msgBox.exec(); } } else { msgBox.setText("can't find dir"); msgBox.exec(); } } catch (std::exception &err) { msgBox.setText(err.what()); msgBox.exec(); } return result; } void MyWindow::onValueChanged() { this->myValue = myWatcher->result(); // ...业务代码 } QFutureWatcher:为任务监听 QFuture:为异步任务,这里使用QtConcurrent来创建异步任务,也有其它模式,具体请参见官方文档。 Py_Initialize为初始化python环境,但在2.7时重复初始环境会导致系统崩溃,可使用Py_IsInitialized()判断是否已初始化过环境。 Py_DECREF:看说明是释放资源,但是调用函数第二次运行时也会崩溃,所以实际代码中没有使用。 Py_Finalize():同上述原因实际没有使用。 PyObject_CallObject:第二个参数为Python函数参数,可有多个,使用PyTuple包裹。

Python源码:

import os def call_python(param): helloStr = "Hello in Python "+param; return helloStr; 代码运行过程中每第二次调用python程序就会崩溃,一度以为是QFutureWatcher的异步监听没有释放资源导致,修改为同步任务调试才发现是由于Py_Initialize二次初始化及Py_DECREF释放资源导致。去掉相关资源释放后反而正常了。还是要以实际效果为准 参考资料

https://zhuanlan.zhihu.com/p/149887203

https://blog.csdn.net/iamqianrenzhan/article/details/86516440



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3