跳至主要內容

Qt

LincZero大约 6 分钟

Qt

目录

.py 应用程序脚本

与C/C++调用Python程序的原理是一样的,QT也没有什么特殊的地方

参考:

简概

.py与.js区别

.py用作脚本的话和.js脚本类型,有略微不同

  • Qt工程上的区别:
    • .py:可以直接创建,不用加入到.qrc资源文件当中,会归类到 “Other files” 当中
    • .js:无法直接创建,但可以添加进.qrc资源文件中
  • 语言自身性质区别:python可以创建类,面向对象编程
  • Qt支持上的区别:python有PySide2 / PyQt5模块的支持,这能让Python像C++一样使用Qt框架

基本配置

QT中运行Python脚本

(图文版见参考链接)

工具->选项->环境->外部工具

  1. 添加->添加目录 (双击可任意更改名称这里更改为RunPy)
  2. 添加->添加工具(双击可任意更改名称这里更改为Python3)
  3. 点击Python3,配置执行档、参数等配置:
    • 执行档:(根据python安装路径设置,D:\Soft\Dev\All\Python_Anaconda\python.exe )
    • 参数:%
    • 工作目录:%

C++中调用Python脚本

项目文件下右键 -> 添加库

  1. 选择链接到库的类型 -> 外部库 -> 下一步
  2. 制定链接库和包含路径
    • Library type:WIndows
    • 库文件:(根据安装路径设置,D:\Soft\Dev\All\Python_Anaconda\libs\python37.lib)
    • 包含路径:(根据安装路径设置,D:\Soft\Dev\All\Python_Anaconda\libs)
    • 平台:取选Linux、Mac,只留Windows(默认全勾选)
    • 链接:静态(默认是动态)
    • Windows:取选:为debug版本添加 'd' 作为后缀 (教程里勾选但实际应该是取选。比如勾选的话他会找我的python37d.lib,但我没有啊。当然也可以后期在.pro里删掉 'd')

基本使用

测试代码1

#include <Python.h>
Py_Initialize();
PyRun_SimpleString("import sys");					// 前面这堆没懂什么作用
PyRun_SimpleString("sys.argv = ['python.py']");		// 前面这堆没懂什么作用
PyRun_SimpleString("sys.path.append('./')");		// 前面这堆没懂什么作用
PyObject* pModule = PyImport_ImportModule("dsdfs");
if (!pModule)
 {
     qDebug()<<"Cant open python file!\n";
 }
qDebug()<<"file of python ac been opened";
PyObject* pFunhello= PyObject_GetAttrString(pModule,"hhh");
if(!pFunhello){
    qDebug()<<"Get function hello failed";
}
//调用temperImg函数
PyObject_CallFunction(pFunhello,NULL);
//结束,释放python
Py_Finalize();

运行会报错,下一章解决

D:\Soft\Dev\All\Python_Anaconda\include\object.h:448: error: C2059: 语法错误:“;”
D:\Soft\Dev\All\Python_Anaconda\include\object.h:448: error: C2238: 意外的标记位于“;”之前

改良代码2

void runPy2(){
    /* 不加则运行时崩溃 */
    Py_SetPythonHome(L"D:\\Soft\\Dev\\All\\Python_Anaconda");
    /** Python系统初始化 */
    Py_Initialize();
    if(!Py_IsInitialized())
    {
        qDebug()<<"Failed to initialize py.";
        return;
    }
    /** Python文件 */
    PyObject* pModule = PyImport_ImportModule("pythonTest");
    if(!pModule)
    {
        qDebug()<<"Failed to import py script file.";
        return;
    }
    /** Python文件中的函数 */
    PyObject* pFunhello= PyObject_GetAttrString(pModule,"hello");
    if(!pFunhello){
        qDebug()<<"Failed to get py function.";
        return;
    }
    //执行函数
    PyObject_CallFunction(pFunhello,NULL);
    //结束,释放Python系统
    Py_Finalize();
}

获取返回值

参考:https://blog.csdn.net/qq_36662876/article/details/100929437

C++

void runPy(){
    Py_SetPythonHome(L"D:\\Soft\\Dev\\All\\Python_Anaconda");
    /** Python系统初始化 */
    Py_Initialize();
    if(!Py_IsInitialized())
    {
        qDebug()<<"Failed to initialize py.";
        return;
    }
    
    /** Python文件 */
    PyObject* pModule = PyImport_ImportModule("pythonTest");
    if(!pModule)
    {
        qDebug()<<"Failed to import py script file.";
        return;
    }
    
    /** Python文件中的函数 */
    PyObject* pFunhello= PyObject_GetAttrString(pModule,"hello");
    if(!pFunhello){
        qDebug()<<"Failed to get py function.";
        return;
    }
    
    /** 执行Python函数并获取返回值 By CallFunction */
    PyObject* pArg = Py_BuildValue("(s)","wwwooo");  // 括号是因为参数是元组,这里有两种方法可以用
    PyObject* pyValue = PyObject_CallObject(pFunhello, pArg);
    
    /** 将返回值转化为C++类型 */
    char *pyReturnStr, *IO_door;
    if(PyArg_ParseTuple(pyValue, "s|s", &pyReturnStr, &IO_door)){  // 只返回一个数时会显示乱码,所以加了没有含义的IO_door
        qDebug()<<"transfrom sucess";
        qDebug()<<"QT: "<<pyReturnStr;
    }
    // 返回数字同理
    // int i; // 指针?
    // if(PyArg_Parse(pyValue, "i", &i)){ qDebug()<<i; }
    
    /** 结束,释放Python系统 */
    Py_Finalize();
}

Py

def hello(text="not vals"):
    print(text)
    xx='none'
    print("hello world!")
    return "python function return",xx

坑非常多,建议逐步测试

逐步测试详见Python笔记中的编译DLL一章

更多的坑见:【CSDN】QT——调用Python脚本open in new window

首先检查

修改py文件时要修改两处

更新py文件时要注意,exe目录和源项目中的py文件都要更新,别忘了前者

推荐每一步 if 一下,看哪步出错了

void runPy(){
    Py_SetPythonHome(L"D:\\Soft\\Dev\\All\\Python_Anaconda");
    
    /** Python系统初始化 */
    Py_Initialize();
    if(!Py_IsInitialized())
    {
        qDebug()<<"Failed to initialize py.";
        return;
    }
    
    /** Python文件 */
    PyObject* pModule = PyImport_ImportModule("pythonTest");
    if(!pModule)
    {
        qDebug()<<"Failed to import py script file.";
        return;
    }
    
    /** Python文件中的函数 */
    PyObject* pFunhello= PyObject_GetAttrString(pModule,"hello");
    if(!pFunhello){
        qDebug()<<"Failed to get py function.";
        return;
    }
    
    /** 执行Python函数并获取返回值 By CallFunction */
    PyObject* pArg = Py_BuildValue("(s)","wwwooo");  // 括号是因为参数是元组,这里有两种方法可以用
    PyObject* pyValue = PyObject_CallObject(pFunhello, pArg);
    if(!pyValue){
        qDebug()<<"Failed to get py return.";
        return;
    }
    
    /** 将返回值转化为C++类型 */
    char *pyReturnStr, *IO_door;
    if(!PyArg_ParseTuple(pyValue, "s|s", &pyReturnStr, &IO_door)){  // 只返回一个数时会显示乱码,所以加了没有含义的IO_door
		qDebug()<<"Failed to transfrom python return.";
    }
    qDebug()<<"QT: "<<pyReturnStr;
    
    /** 结束,释放Python系统 */
    Py_Finalize();
}

py_Initialize 就出错

C2059: 语法错误:“;”、C2238: 意外的标记位于“;”之前

打开报错的python源文件,并加两行条件编译注释解决

typedef struct{
    const char* name;
    int basicsize;
    int itemsize;
    unsigned int flags;
    #undef slots
    PyType_Slot *slots; /* terminated by slot==0. */	# 这里定义的slots和QT中的关键字冲突。加上下两行注释即可解决
    #define slots Q_SLOTS
} PyType_Spec;

LNK1104: 无法打开文件“python37_d.lib”

include文件夹下找到pyconfig.h文件,将python37_d.lib更改为python37.lib

C1083: 无法打开文件“pyconfig.h”; No such file or directory

这个Anaconda自带的那个目录是有这个文件的,但是你自己下载的Python源码是没有的,好像要另外配置

推荐直接用Anaconda路径的那个

断点在 py_Initialize 初始化时崩溃

两个方法

/* 不加则运行时崩溃:
 * initfsencoding: unable to load the file system codec
 * 参考:https://www.cnblogs.com/2008nmj/p/8027430.html
 * 两个方法:
 * 一个就是补全python的环境变量。但不知道为什么我的环境变量设置没用,还是报错
 * 另一个就是手动设置初始化函数的搜寻路径(也就是加载路径)
 */
Py_SetPythonHome(L"D:\\Soft\\Dev\\All\\Python_Anaconda"); // 方法二
/** Python系统初始化 */
Py_Initialize();

调用Py文件时出错

PyImport_ImportModule 导入py文件时找不到

要将py文件和exe文件放置于同一目录下

与Python文件

SystemError: new style getargs format but argument is not a tuple、不崩溃,若打印则崩溃

原代码

const char *command;
if(PyArg_Parse(pyValue, "s", &command)){  		// 报错:TypeError: argument must be str, not None
    qDebug()<<"transfrom sucess";
}

const char *command;
if(PyArg_ParseTuple(pyValue, "s", &command)){	// 报错:SystemError: new style getargs format but argument is not a tuple
    qDebug()<<"transfrom sucess";
}

char *pyReturnStr, *IO_door;
if(PyArg_ParseTuple(pyValue, "s", &pyReturnStr)){ // 报错:SystemError: new style getargs format but argument is not a tuple
    qDebug()<<"transfrom sucess";
    qDebug()<<"QT: "<<pyReturnStr;
}

修改

// Python多传一个无意义参数
char *pyReturnStr, *IO_door;
if(PyArg_ParseTuple(pyValue, "s|s", &pyReturnStr, &IO_door)){
    qDebug()<<"transfrom sucess";
    qDebug()<<"QT: "<<pyReturnStr;
}

// 或将方法改成PyArg_Parse
char *pyReturnStr;
if(PyArg_Parse(pyValue, "s", &pyReturnStr)){
    qDebug()<<"transfrom sucess";
    qDebug()<<"QT: "<<pyReturnStr;
}

TypeError: argument must be str, not None、输出的都是乱码、不崩溃

原代码

// C++
const char *command;
if(PyArg_Parse(pyValue, "s", &command)){
    qDebug()<<"transfrom sucess";
}

// python
return "python function return","none"
    

TypeError: an integer is required ( got type NoneType )

翻译:需要一个整数

后来发现是我exe目录里的py文件没更新

SystemError: old style getargs format uses new features、不崩溃

PyArg_Parse 改 PyArg_ParseTuple 就行了