QT下调用py脚本的两种方法

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

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

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

感谢大佬的分享~~

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 <Python.h>
#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指针,否则将导致错误。

方法二:通过shell进行调用

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QtDebug>

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 /xxx/test.py \n");

//方式二:直接启动python,并要求他启动指定脚本。
    process1->start("/usr/bin/python3.7 /xxx/test.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函数输出信息,这些输出并不会即时显示。相反,所有输出会被缓存起来,直到循环结束或脚本执行完毕后才一并显示。

解决办法:

若希望实现实时获取控制台的每次输出,可以在Python脚本中将每次的输出实时保存到内存、剪贴板或指定的日志文件中。之后,通过Qt应用程序读取这些保存的输出信息,以此来捕获每一次的输出结果。另一种可行的方法是调整Python脚本的输出缓冲设置,使其能够即时刷新输出,确保每次调用print函数时都能立即反映在控制台上。例如,可以通过在脚本开头添加import sys; sys.stdout.flush()来手动刷新输出缓冲区。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值