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

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

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<QString> *myWatcher;
    QComboBox *myCombo;
    QString myValue;
}
  • QFutureWatcher\<QString\>:为任务监听,QString为异步任务返回值,全局初始化是为了方便获取执行结果及销毁资源,不全局申明可在onValueChanged方法中用下面的代码获取任务监听
QFutureWatcher\<QString\> *myWatcher = dynamic_cast<QFutureWatcher\<QString\> *\>(this->sender());

C++ CXX文件:

#include <Python.h>

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<QString>(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<QString>();
        QFuture<QString> 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

目录
相关文章
|
16天前
|
Python
【python】python跨文件使用全局变量
【python】python跨文件使用全局变量
|
17天前
|
计算机视觉 数据格式
使用opencv在Qt控件上播放mp4文件
使用opencv在Qt控件上播放mp4文件
24 2
|
18天前
|
算法 数据处理 Python
Python并发编程:解密异步IO与多线程
本文将深入探讨Python中的并发编程技术,重点介绍异步IO和多线程两种常见的并发模型。通过对比它们的特点、适用场景和实现方式,帮助读者更好地理解并发编程的核心概念,并掌握在不同场景下选择合适的并发模型的方法。
|
21天前
|
存储 C++
基于C++的简易文件压缩与解压缩工具设计与实现
基于C++的简易文件压缩与解压缩工具设计与实现
14 3
|
23天前
|
安全 算法 程序员
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
31 0
|
25天前
|
监控 数据处理 索引
使用Python批量实现文件夹下所有Excel文件的第二张表合并
使用Python和pandas批量合并文件夹中所有Excel文件的第二张表,通过os库遍历文件,pandas的read_excel读取表,concat函数合并数据。主要步骤包括:1) 遍历获取Excel文件,2) 读取第二张表,3) 合并所有表格,最后将结果保存为新的Excel文件。注意文件路径、表格结构一致性及异常处理。可扩展为动态指定合并表、优化性能、日志记录等功能。适合数据处理初学者提升自动化处理技能。
21 1
|
27天前
|
Unix 编译器 Linux
【计算机基础 ELF文件】深入探索ELF文件:C++编程中的关键组成部分
【计算机基础 ELF文件】深入探索ELF文件:C++编程中的关键组成部分
47 0
|
11天前
|
人工智能 机器人 C++
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
|
28天前
|
编译器 测试技术 C++
【Python 基础教程 01 全面介绍】 Python编程基础全攻略:一文掌握Python语法精髓,从C/C++ 角度学习Python的差异
【Python 基础教程 01 全面介绍】 Python编程基础全攻略:一文掌握Python语法精髓,从C/C++ 角度学习Python的差异
157 0
|
24天前
|
Linux C++ iOS开发
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(二)
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南
237 2

热门文章

最新文章

推荐镜像

更多