QT 下调用python自定义模块

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

1.创建工程

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

#test.py  文件放在exe文件同目录下
# -*- coding: cp936 -*-
#定义hello函数,这个函数的功能是输出“hello world!”
def hello():
    print("hello python!")
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
#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();
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

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的安装目录。
参考:http://blog.csdn.net/you_lan_hai/article/details/8592697

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

解决了这两个问题,再运行程序 即可在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");
    
    
  • 1
  • 2
  • 3

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

#python 中有如下代码
def add(a,b)
    #print a+b
    return a+b

    
    
  • 1
  • 2
  • 3
  • 4
  • 5
//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();
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
从上述代码可以窥见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的变量。
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

以上算是简单入门。

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

1.创建工程

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

#test.py  文件放在exe文件同目录下
# -*- coding: cp936 -*-
#定义hello函数,这个函数的功能是输出“hello world!”
def hello():
    print("hello python!")
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
#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();
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

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的安装目录。
参考:http://blog.csdn.net/you_lan_hai/article/details/8592697

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

解决了这两个问题,再运行程序 即可在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");
  
  
  • 1
  • 2
  • 3

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

#python 中有如下代码
def add(a,b)
    #print a+b
    return a+b

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
//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();
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
从上述代码可以窥见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的变量。
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

以上算是简单入门。

猜你喜欢

转载自blog.csdn.net/j497205974/article/details/80601266
今日推荐