欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

QT下调用py脚本

时间:2023-04-24

如何实现在c++QT中调用py脚本呢?方法如下:

方法一:通过官方python.h进行调用

该方法参考了Ubuntu18.04下 Qt调用conda下的python_猫生鱼的博客-CSDN博客

感谢大佬的分享~~

1.在.pro文件中加入

##加入python库(根据实际位置调整路径)

LIBS += -L/usr/local/python3.7/lib -lpython3.7m -lcrypt -lpthread -ldl  -lutil -lm -lpython3

DEPENDPATH += /usr/local/python3.7/include/python3.7m

INCLUDEPATH += /usr/local/python3.7/include/python3.7m  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall

INCLUDEPATH += /usr/local/python3.7/lib/python3.7/site-packages/numpy/core/include

2.在需要调用py脚本的文件中加入

#undef slots

#include

#define slots Q_SLOTS

tip:为什么添加#undef slots #define slots Q_SLOTS?原因是python中的slots与qt中的slots 定义冲突

3、在需要调用py脚本的.cpp文件中加入以下代码(可以在函数中加入)

   //以下为使用python.h调用py的代码

    Py_Initialize();// 解释器初始化

    if(!Py_IsInitialized()){

        PyErr_Print();

        qDebug() << "Can't Initialize python!n" ;

        return ;

    }

    PyRun_SimpleString("import sys");//令python能找到已经安装的库,不加此句会出现无法import的问题

    PyRun_SimpleString("sys.argv = ['python.py']");

    PyRun_SimpleString("sys.path.append('./')");//把工作目录改为py文件所在目录,这里为当前目录

//导入.py文件模块,这里的project为文件名

PyObject* pModule = Pyimport_importModule("project");

if(!pModule){

    PyErr_Print();

    qDebug() << "Can't open python file!n" ;

    return;

}

//导入模块中的方法字典

PyObject* pDict = PyModule_GetDict(pModule);

if(!pDict){

    PyErr_Print();

    qDebug() << "Get Dict failed!n" ;

   return;

}

//导入已导入模块中的方法或类,这里的main为方法(函数)名

PyObject* pFuc = PyDict_GetItemString(pDict, "main");

if(!pFuc){

    PyErr_Print();

    qDebug() << "Get function failed!n" ;

    return;

}

//启用导入的方法或类

PyObject_CallFunction(pFuc,NULL);

//内存释放

Py_CLEAR(pModule);

Py_CLEAR(pDict);

Py_CLEAR(pFuc);

//释放Python解释器所占用的资源

Py_Finalize();

知识点补充:Python嵌入C/C++释放资源

Python使用引用计数机制对内存进行管理,实现自动垃圾回收。在C/C++中使用Python对象时,应正确地处理引用计数,否则容易导致内存泄漏。在Python/C API中提供了Py_CLEAR()、Py_DECREF()等宏来对引用计数进行操作。

当使用Python/C API中的函数创建列表、元组、字典等后,就在内存中生成了这些对象的引用计数。在对其完成操作后应该使用Py_CLEAR()、Py_DECREF()等宏来销毁这些对象。其原型分别如下所示。

void Py_CLEAR( PyObject *o)

void Py_DECREF( PyObject *o)

其参数含义如下。

*o:要进行操作的对象。

对于Py_CLEAR()其参数可以为NULL指针,此时,Py_CLEAR()不进行任何操作。而对于Py_DECREF()其参数不能为NULL指针,否则将导致错误。

方法二:通过多线程调用

#include "mainwindow.h"

#include "ui_mainwindow.h"

#include

#include

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

     process1 = new QProcess(this);

//方式一:首先调用控制台,再通过控制台启动程序。(控制台:mac/linux下调用bash,windows下是cmd.exe)

     process1->start("bash");//调用控制台程序

     process1->waitForStarted();//等待程序确实启动再往下走

     process1->write("/usr/bin/python3.7 ./handpose.py n");

//方式二:直接启动python,并要求他启动指定脚本。

process1->start("/usr/bin/python3.7 /AR/ar/handpose.py");//直接启动python,并要求他启动指定脚本。

//信号槽连接,获取到程序输出就调用OnReadData函数

     connect(process1,SIGNAL(readyReadStandardOutput()),this,SLOT(onReadData()));

}

void MainWindow::onReadData(){

//打印输出

    QString strResult = QString::fromLocal8Bit(process1->readAllStandardOutput().data());

    qDebug() << strResult;

}

MainWindow::~MainWindow()

{

//杀死调用的进程

    process1->kill();

    process1->close();

    delete process1;

    delete ui;

}

输出问题:

值得指出的是,这里输出的内容,是当前py脚本运行结束后才会触发。比如脚本中有个循环10次每秒输出print,这里就不会触发10次分别打出print,而是会等10次运行结束后,统一打出文本。

解决办法,如果要想收到控制台的每次输出,可以再py脚本中将输出保存到内存中,或是剪切板,或者是指定的log文件,然后再通过qt读取,获取每次输出。

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。