准备在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中在项目上点右键–添加库:
点击完成。
如上设置即可编译通过。
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
以上算是简单入门。