Qt
大约 6 分钟
Qt
目录
.py 应用程序脚本
与C/C++调用Python程序的原理是一样的,QT也没有什么特殊的地方
参考:
- 【Python官网文档】扩展和嵌入 Python 解释器
- 【CSDN】QT——调用Python脚本
- c和c++调用Python,https://www.xzhongwei.com/post/127,好总结,重要参考
简概
.py与.js区别
.py用作脚本的话和.js脚本类型,有略微不同
- Qt工程上的区别:
- .py:可以直接创建,不用加入到.qrc资源文件当中,会归类到 “Other files” 当中
- .js:无法直接创建,但可以添加进.qrc资源文件中
- 语言自身性质区别:python可以创建类,面向对象编程
- Qt支持上的区别:python有
PySide2 / PyQt5
模块的支持,这能让Python像C++一样使用Qt框架
基本配置
QT中运行Python脚本
(图文版见参考链接)
工具->选项->环境->外部工具
- 添加->添加目录 (双击可任意更改名称这里更改为RunPy)
- 添加->添加工具(双击可任意更改名称这里更改为Python3)
- 点击Python3,配置执行档、参数等配置:
- 执行档:(根据python安装路径设置,D:\Soft\Dev\All\Python_Anaconda\python.exe )
- 参数:%
- 工作目录:%
C++中调用Python脚本
项目文件下右键 -> 添加库
- 选择链接到库的类型 -> 外部库 -> 下一步
- 制定链接库和包含路径
- 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脚本
首先检查
修改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 就行了