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

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();
        // ...业务代码
    }
AI 代码解读
  • 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;
AI 代码解读
代码运行过程中每第二次调用python程序就会崩溃,一度以为是QFutureWatcher的异步监听没有释放资源导致,修改为同步任务调试才发现是由于Py_Initialize二次初始化及Py_DECREF释放资源导致。去掉相关资源释放后反而正常了。还是要以实际效果为准

参考资料

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

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

目录
打赏
0
0
0
0
891
分享
相关文章
[oeasy]python094_使用python控制音符列表_midi_文件制作
本文介绍了如何使用Python控制音符列表制作MIDI文件。首先回顾了列表下标索引(正数和负数)的用法,接着通过`mido`库实现MIDI文件生成。以《两只老虎》为例,详细解析了代码逻辑:定义音高映射、构建旋律列表、创建MIDI文件框架,并将音符插入音轨。还探讨了音符时值与八度扩展的实现方法。最终生成的MIDI文件可通过不同平台播放或编辑。总结中提到,此技术可用于随机生成符合调性的旋律,同时引发对列表其他实际应用的思考。
36 5
Python文件打包:一站式指南
本文深入探讨Python文件打包的各种方法,从基础的zip和tar工具到高级的setuptools、PyInstaller、cx_Freeze等,涵盖Docker镜像、虚拟环境及自包含可执行文件的打包方式。通过示例代码与详细解析,帮助开发者根据项目需求选择合适的打包方案,提升代码分发与部署效率。内容全面,适合各水平读者学习参考。
205 7
在C++的QT框架中实现SQLite数据库的连接与操作
以上就是在C++的QT框架中实现SQLite数据库的连接与操作的基本步骤。这些步骤包括创建数据库连接、执行SQL命令、处理查询结果和关闭数据库连接。在实际使用中,你可能需要根据具体的需求来修改这些代码。
207 14
|
3月前
|
使用Python实现multipart/form-data文件接收的http服务器
至此,使用Python实现一个可以接收 'multipart/form-data' 文件的HTTP服务器的步骤就讲解完毕了。希望通过我的讲解,你可以更好地理解其中的逻辑,另外,你也可以尝试在实际项目中运用这方面的知识。
198 69
探秘文件共享服务之哈希表助力 Python 算法实现
在数字化时代,文件共享服务不可或缺。哈希表(散列表)通过键值对存储数据,利用哈希函数将键映射到特定位置,极大提升文件上传、下载和搜索效率。例如,在大型文件共享平台中,文件名等信息作为键,物理地址作为值存入哈希表,用户检索时快速定位文件,减少遍历时间。此外,哈希表还用于文件一致性校验,确保传输文件未被篡改。以Python代码示例展示基于哈希表的文件索引实现,模拟文件共享服务的文件索引构建与检索功能。哈希表及其分布式变体如一致性哈希算法,保障文件均匀分布和负载均衡,持续优化文件共享服务性能。
解锁文件共享软件背后基于 Python 的二叉搜索树算法密码
文件共享软件在数字化时代扮演着连接全球用户、促进知识与数据交流的重要角色。二叉搜索树作为一种高效的数据结构,通过有序存储和快速检索文件,极大提升了文件共享平台的性能。它依据文件名或时间戳等关键属性排序,支持高效插入、删除和查找操作,显著优化用户体验。本文还展示了用Python实现的简单二叉搜索树代码,帮助理解其工作原理,并展望了该算法在分布式计算和机器学习领域的未来应用前景。
Python中的Paramiko与FTP文件夹及文件检测技巧
通过使用 Paramiko 和 FTP 库,开发者可以方便地检测远程服务器上的文件和文件夹是否存在。Paramiko 提供了通过 SSH 协议进行远程文件管理的能力,而 `ftplib` 则提供了通过 FTP 协议进行文件传输和管理的功能。通过理解和应用这些工具,您可以更加高效地管理和监控远程服务器上的文件系统。
151 20
Chainlit:一个开源的异步Python框架,快速构建生产级对话式 AI 应用
Chainlit 是一个开源的异步 Python 框架,帮助开发者在几分钟内构建可扩展的对话式 AI 或代理应用,支持多种工具和服务集成。
515 9
如何在Python中高效地读写大型文件?
大家好,我是V哥。上一篇介绍了Python文件读写操作,今天聊聊如何高效处理大型文件。主要方法包括:逐行读取、分块读取、内存映射(mmap)、pandas分块处理CSV、numpy处理二进制文件、itertools迭代处理及linecache逐行读取。这些方法能有效节省内存,提升效率。关注威哥爱编程,学习更多Python技巧。
156 8
如何使用 Python 进行文件读写操作?
大家好,我是V哥。本文介绍Python中文件读写操作的方法,包括文件读取、写入、追加、二进制模式、JSON、CSV和Pandas模块的使用,以及对象序列化与反序列化。通过这些方法,你可以根据不同的文件类型和需求,灵活选择合适的方式进行操作。希望对正在学习Python的小伙伴们有所帮助。欢迎关注威哥爱编程,全栈路上我们并肩前行。
154 4

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问