准备在QT中调用自定义python脚本,然而在实践中遇到的坑不少,经过一番摸索最终也解决了,特此记录,以便于有共同需求的人。

1.创建工程

新建一个GUI工程,添加一个QPushButton,在槽函数中写下如下 代码:

#test.py  文件放在exe文件同目录下
# -*- coding: cp936 -*-
#定义hello函数,这个函数的功能是输出“hello world!”
def hello():
    print("hello python!")
#include <Python.h>
#include <QDebug>

void MainWindow::on_pushButton_clicked()
{
//初始化python模块
    Py_Initialize();
    if ( !Py_IsInitialized() )
    {
        return ;
    }
    //导入test.py模块
    PyObject* pModule = PyImport_ImportModule("test");
    if (!pModule) 
    {
        qDebug()<<"Cant open python file!\n";
        return ;
    }
    //获取test模块中的hello函数
    PyObject* pFunhello= PyObject_GetAttrString(pModule,"hello");

    if(!pFunhello)
    {
        qDebug()<<"Get function hello failed";
        return ;
    }
    //调用hello函数
    PyObject_CallFunction(pFunhello,NULL);
    //结束,释放python
    Py_Finalize();
}

2.编译工程

注:本文使用python 2.7.*版本

1)首先添加python库文件和头文件目录

Qt Creator中在项目上点右键–添加库:

Qprocess调用python获取输出结果 qt调用python函数_python


Qprocess调用python获取输出结果 qt调用python函数_qt_02


Qprocess调用python获取输出结果 qt调用python函数_python_03


点击完成。

如上设置即可编译通过。

3.运行

错误1:ImportError: No module named site
执行Py_Initialize即会在调试窗口输出这个,然后程序退出。
解决方法:在调用Py_Initialize之前,手动设置python搜索目录:Py_SetPythonHome(“C:/Python27”);
这里要设置成python的安装目录。
参考:

错误2:PyObject_GetAttrString 找不到hello函数
原因:python目录下有一个test的模块,且优先级比我们的模块优先级高。
解决办法:换一个名字
参考:

解决了这两个问题,再运行程序 即可在QT的应用输出窗口看到”hello python!”的输出了。

4.高级

问题1:py脚本放在其他目录怎么办?比如exe程序 在C:/test,脚本在C:/test/tmp?

解决办法:在PyImport_ImportModule上添加两句

PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\"/tmp/\")");
    PyObject* pModule = PyImport_ImportModule("qt_test");

问题2:像python中的函数传递参数或者获取返回值怎么 办?
解决办法:
比如:

#python 中有如下代码
def add(a,b)
    #print a+b
    return a+b
//QT 中调用方法
void MainWindow::on_pushButton_clicked()
{
    Py_SetPythonHome("C:/Python27");
    //初始化python模块
    Py_Initialize();
    if ( !Py_IsInitialized() )
    {
        return ;
    }
    //导入test.py模块
//    PyRun_SimpleString("import sys");
//    PyRun_SimpleString("sys.path.append(\"/tmp/\")");
    PyObject* pModule = PyImport_ImportModule("qt_test");
    if (!pModule)
    {
        qDebug()<<"Cant open python file!\n";
        return ;
    }
    //获取test模块中的add函数
    PyObject* pFunhello= PyObject_GetAttrString(pModule,"add");

    if(!pFunhello)
    {
        qDebug()<<"Get function add failed";
        return ;
    }
    PyObject* pArgs;
    pArgs=PyTuple_New(2);
    //放置传入的形参,类型说明:
    //s 字符串 , 均是C 风格的字符串
    //i 整型
    //f 浮点数
    //o 表示一个 python 对象
   PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 1));
   PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 2));
    //调用hello函数
    PyObject* pReturn=PyObject_CallObject(pFunhello,pArgs);

     int   res = PyInt_AsLong(pReturn);
     qDebug()<<res;
    //结束,释放python
    Py_Finalize();
}
从上述代码可以窥见Python内部运行的方式:
所有Python元素,module、function、tuple、string等等,实际上都是PyObject。C语言里操纵它们,一律使用PyObject *。
Python的类型与C语言类型可以相互转换。
Python类型XXX转换为C语言类型YYY要使用PyXXX_AsYYY函数;
C类型YYY转换为Python类型XXX要使用PyXXX_FromYYY函数。
也可以创建Python类型的变量,使用PyXXX_New可以创建类型为XXX的变量。

参考:
https://zhuanlan.zhihu.com/p/20150641
http://gashero.yeax.com/?p=38

以上算是简单入门。