在Qt(C++)中与Python混合编程
一、PythonQt库
在Qt(C++)中与Python混合编程,可以使用PythonQt库。
网站首页:http://pythonqt.sourceforge.net
下载页面:https://sourceforge.net/projects/pythonqt/files/
只提供了源码下载,需自行编译。
版本要求:
其网站building页面上的要求:Qt 4.8.1以上,Python2.6以上
实际测试中得出的版本要求:Qt5.4以上,可以编译得到动态链接库(.so文件);Python2.7.12,编译范例程序成功。
(备注:我的测试环境是操作系统 Ubuntu 16.04 64bit,PythonQt版本:3.2)
二、编译与安装
编译文档:http://pythonqt.sourceforge.net/Building.html
这里以Linux(Ubuntu系)为例,介绍一下编译安装方法。
1. 安装Qt
去Qt网站下载安装包,或者通过apt安装。安装完毕后,在命令行中执行qmake -v
,查看输出信息,确认Qt已安装好。
注意:如果使用apt或者synaptic安装Qt,那么需要手动安装Qt的一些模块,例如multimedia等。以Qt5为例,其模块一般以libqt5为开头,可以用apt或synaptic搜索关键字安装。如果缺少模块,则编译PythonQt时会报错提示(报错是 Unknown module(s))。如果出现类似错误,则需要安装相关模块,再重新编译。
大部分Qt模块的软件包名称都是以libqt5开头的,例如libqt5gui5、libqt5multimedia5、libqt5qml5等,有些可能以-dev结尾。但是有一些模块的名称则不一样,这里列出来,以免遗漏:
- qtdeclarative5-dev:与qml和quick模块有关
- qtmultimedia5-dev:与multimedia模块有关
2. 安装Python
用apt安装Python和Python-dev。Linux一般预装Python。
sudo apt install python python-dev
3. 编译
将下载的源码解压。进入解压目录,之后执行编译指令。假设解压目录为PythonQt
cd PythonQt
qmake
make all
编译可能需要花费几分钟,请耐心等待。
编译完成后,编译得到的库文件以及范例程序都在PythonQt/lib
下。此时运行范例程序可能失败,需要先安装刚编译好的库。
4. 安装
所谓安装,是指让系统能够找到编译好的库文件。实现的方式有多种,这里介绍通过链接的方式安装。
首先确认系统中的库文件默认目录是什么。
cd /etc/ld.so.conf.d/
ls
可能列出一些配置文件,文件名是对应的目录,比如x86_64-linux-gnu.conf。用文本编辑器打开,就可以看到对应的完整目录。我的系统中默认库目录有
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
这里,我选择/usr/lib/x86_64-linux-gnu这个目录安装。
# 进入PythonQt的目录
cd PythonQt
# 复制文件(文件名中的数字与版本有关,不一定和我一样)
sudo cp lib/libPythonQt-Qt5-Python2.7.so.3.2.0 /usr/lib/x86_64-linux-gnu
sudo cp lib/libPythonQt_QtAll-Qt5-Python2.7.so.3.2.0 /usr/lib/x86_64-linux-gnu
# 进入安装目录
cd /usr/lib/x86_64-linux-gnu/
# 创建链接
sudo ln -sf libPythonQt-Qt5-Python2.7.so.3.2.0 libPythonQt-Qt5-Python2.7.so
sudo ln -sf libPythonQt-Qt5-Python2.7.so.3.2.0 libPythonQt-Qt5-Python2.7.so.3
sudo ln -sf libPythonQt-Qt5-Python2.7.so.3.2.0 libPythonQt-Qt5-Python2.7.so.3.2
sudo ln -sf libPythonQt_QtAll-Qt5-Python2.7.so.3.2.0 libPythonQt_QtAll-Qt5-Python2.7.so
sudo ln -sf libPythonQt_QtAll-Qt5-Python2.7.so.3.2.0 libPythonQt_QtAll-Qt5-Python2.7.so.3
sudo ln -sf libPythonQt_QtAll-Qt5-Python2.7.so.3.2.0 libPythonQt_QtAll-Qt5-Python2.7.so.3.2
# 更新
sudo ldconfig
安装完成。运行PythonQt/lib
下的范例程序(双击或命令行执行),如果可以运行,说明正常。
三、在Qt项目中使用PythonQt
可以看范例源码和官方文档学习。这里以Linux(Ubuntu系)环境为例,简单介绍一下使用方法。
1. 新建项目
使用QtCreator新建项目。
2. 准备库文件
需要将一些配置文件和PythonQt库的头文件复制到项目文件夹下(可以新建一个子文件夹)。假设项目目录为[PRJ],PythonQt目录为[PYQ]。
cd [PRJ]
mkdir PythonQt
cp [PYQ]/src/PythonQt*.h PythonQt/
cp [PYQ]/build/*.prf ./
cp [PYQ]/lib/libPythonQt-Qt5-Python*.so* ./
其中.h是头文件,.prf是配置文件,.so是链接库。
头文件可以直接使用。配置文件需要修改,主要是修改相关目录。
说明:配置文件的注释方式是每行前加注释符号#
。
以下是一种修改方式:
common.prf
将以下三行删除或注释掉:
CONFIG(debug, debug|release) {
TARGET = $${TARGET}_d
}
将所有的$$PWD/../
改为$$PWD/
。
PythonQt.prf
删除或注释掉以下内容:
INCLUDEPATH += $$PWD/../src
# check if debug or release
CONFIG(debug, debug|release) {
DEBUG_EXT = _d
} else {
DEBUG_EXT =
}
修改
unix::LIBS += -L$$PWD/../lib -lPythonQt-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT}
改为
unix::LIBS += -L$$PWD -lPythonQt-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT}
3. 修改.pro文件
在项目.pro文件中加入以下内容:
include ( common.prf )
include ( PythonQt.prf )
INCLUDEPATH += PythonQt
4. 在代码中调用PythonQt
这个可以参考PythonQt的范例,然后慢慢摸索。
首先,引用头文件
#include "PythonQt.h"
在使用PythonQt时,首先要对PythonQt的单例对象进行操作。包括初始化,获取对象等。
// init PythonQt and Python
PythonQt::init();
之后,获取__main__模块。
PythonQtObjectPtr mainModule;
// get the __main__ python module
mainModule = PythonQt::self()->getMainModule();
为了能看到python程序中的打印信息,需要连接PythonQt单例对象信号,与你自己写的槽。
// connect output signals
connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), this, SLOT(stdOut(const QString&)));
connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), this, SLOT(stdErr(const QString&)));
第一个信号是向std::out
的输出,第二个信号是std::err
的输出。
之后就可以操作mainModule的方法来调用python代码了。当然,如果python代码里不需要输出,也可以不连接上述信号。
四、执行Python语句或脚本
按照上一节的说明初始化后,就可以执行Python语句或调用Python脚本了。
1. evalScript——执行少量语句
如果要调用的python代码只有单一一行语句或者少量几语句,可以使用evalScript
函数。该函数的参数是要执行的指令,返回执行结果。
QVariant result1 = mainModule.evalScript("19*2+4", Py_eval_input);
QVariant result2 = mainModule.evalScript("len([1, 2, 3])", Py_eval_input);
其中"19*2+4"
是python语句,第二个参数表示执行的是独立的python表达式。返回类型是QVariant
,可以根据实际执行的语句,转换成具体的数据类型。比如这里可以用QVariant::toInt()
转换成int
,得到的结果分别是42和3。不熟悉的朋友请参考QVariant
文档。
evalScript
可以用于定义函数,方便以后调用。例如:
mainModule.evalScript("def add(a, b):\n return a+b");
这样就定义了一个Python中的函数,名为add
,接受两个参数a
和b
,返回两个数的和。
后面第三部分介绍如何调用Python函数。
2. evalFile——执行脚本
如果需要使用Python实现较为复杂的功能,写在一个Python文件中比较方便。假设文件名为func.py。
Python文件的开头需要加入如下语句:
from PythonQt import *
在Qt项目中新建资源文件(.qrc文件),在资源文件中添加func.py,以便调用。调用方式为:
mainModule.evalFile(":/func.py");
调用时的文件路径与添加到资源文件时的前缀有关。注意evalFile
没有返回类型,所以不能用于获得返回值,可以通过第四节所说的打印信息看到执行过程(如果Python程序中有输出语句的话)。如果是Qt GUI项目,也可以把执行结果显示在界面上,这一点在后面第四部分介绍。
执行过evalFile
后,脚本中定义的函数可以在以后直接调用。所以可以把需要返回值的功能写在函数中,后续调用。调用方式见第三部分。
3. call——调用函数
前面介绍了,使用evalScript
和evalFile
都能定义Python函数。定义的函数会保存,之后可以在代码的任意位置调用。要调用这些函数,可使用call
。例如第一点介绍中定义了一个Python中的函数,名为add
,接受两个参数a
和b
,返回两个数的和。调用该函数的方法如下:
int a = 2;
int b = 3;
QVariant c = mainModule.call("add", QVariantList() << a << b);
call
的第一个参数是要调用的函数名称,用字符串表示;第二个参数是要调用的Python函数的参数,用一个QVariantList
存放所有参数。这里,我们把a和b两个数传入。返回类型是QVariant
,需要转换成具体类型。这里的c
转换成整数后是5。
4. addObject——与Qt交互
如果Python程序需要与Qt中的对象交互,可以将继承自QObject
的类型实例传入Python中。addObject
就起到这个作用。
假设Qt GUI项目的mainwindow中有一个label,下面演示怎么通过Python改变label的文字。
首先将label传入Python(label的类型是QLabel,继承自QObject),并且赋予其一个在python中调用的变量名:
mainModule.addObject("label", ui->label);
这条语句将ui->label
传入,并且在Python中可以用label
这个变量名调用。
Python程序如下:
def changeLabelText(text):
label.text = text
通过evalScript
或者evalFile
调用上述程序后,再用call
调用。
mainModule.evalFile(":/func.py");
mainModule.call("changeLabelText", QVariantList() << QString("Hello"));
mainModule.call("changeLabelText", QVariantList() << QString("World"));
第一次调用将标签文字改为Hello,第二次调用改为World。
在Python中操作QObject对象时,要注意,使用的方法、函数、属性等要用Python语法进行。例如在Qt(C++)中改变标签文字的方法是
label->setText("Hello");
而在Python中,应该使用
label.text = 'Hello'
5. Python模块路径问题
既然使用Python,可能是要使用Python中成熟的库,例如用于科学计算的NumPy。如果在Python程序中写入:
import numpy as np
可能在使用PythonQt执行的时候报错,说找不到numpy模块。(当然是已安装的情况下,在Python或命令行中都运行正常。)这很可能是路径问题。
首先找到numpy的安装路径,例如/usr/lib/python2.7/dist-packages
。然后在需要调用的Python文件中加入如下语句:
import sys
sys.path.append('/usr/lib/python2.7/dist-packages') # To use Numpy
import numpy as np
这样就可以正常导入NumPy模块了。
小结
以上介绍了PythonQt库的安装和使用方法。
更加复杂的功能,请参考PythonQt源码中的范例,以及网站上的文档。
开发者文档:http://pythonqt.sourceforge.net/Developer.html
源码中也有很多有用信息,关于一些API函数的调用,可以参考头文件中的注释。例如,关于上面介绍的evalScript
等函数,可以参考PythonQtObjectPtr.h文件(可用QtCreator内的切换功能快速定位)。
在Qt(C++)中与Python混合编程的更多相关文章
- 很好的c++和Python混合编程文章
c++中嵌入python入门1 本人是用vc2003+python2.5学习的,其它的也应该差不了多少 0. 坏境设置把Python的include/libs目录分别加到vc的include/lib ...
- 在QT C++中调用 Python并将软件打包发布(裸机可运行)
为了提高工作效率,需要一个可以自动生成多份相关联的word文档免去繁琐复制粘贴工作的软件.最后选定使用QT C++做界面和主要逻辑程序设计,对word的操作使用python写好对应的函数,然后在QT中 ...
- C语言调用Python 混合编程
导语 Python有很多库,Qt用来编写界面,自然产生C++调用Python的需求.一路摸索,充满艰辛 添加头文件搜索路径,导入静态库 我的python头文件搜索路径:C:\Python27amd64 ...
- C++/Python 混合编程 Clion IDE 搭建
1.Clion IDE 环境 2.TdmGcc C++ 编译器 3.WinPython Python 科学计算环境 4.MySQL SQL 数据库 5.Git GitHub 版本控制 插件
- C++和Python混合编程
为何人工智能(AI)首选Python?读完这篇文章你就知道了:https://blog.csdn.net/qq_41769259/article/details/79419322 C++调用Pytho ...
- Win10 + CLion + 树莓派 + QT 远程开发调用Python
原则:能在一个机器上开发的就不在两台机器上!! 首先需要配置远程QT开发环境 配置Cmake cmake_minimum_required(VERSION 3.14) project(qt_test) ...
- VS/Qt C++和Matlab混合编程
最近两天在搞C++和Matlab混合编程,这个中间过程真是让人心酸啊,最后还是搞定成功!现在把这个过程记录一下. 首先自己的电脑本来就安装着matlab2013b,按着网上的说法首先需要输入!mcc, ...
- 批处理与python代码混合编程的实现方法
批处理可以很方便地和其它各种语言混合编程,除了好玩,还有相当的实用价值, 比如windows版的ruby gem包管理器就是运用了批处理和ruby的混合编写, bathome出品的命令工具包管理器bc ...
- Python和C++的混合编程(使用Boost编写Python的扩展包)
想要享受更轻松愉悦的编程,脚本语言是首选.想要更敏捷高效,c++则高山仰止.所以我一直试图在各种通用或者专用的脚本语言中将c++的优势融入其中.原来贡献过一篇<c++和js的混合编程>也是 ...
随机推荐
- mongodb的优缺点
在这里收集下我自己对Mongodb的一些优缺点方面的认识,或者是通过其它比较可靠的网文上引用或者摘录的作为依据,这个是一个渐进的过程,也是随着我对Mongodb认识的加深而不断扩展的. (1)Mong ...
- 解决运行wamp提示“MSVCR110.dll”丢失的问题!
我在Windows系统上安装wampserver2.5 64位,安装到最后,总是提示丢失msvcr110.dll 解决办法: 到这个网站下载一个Visual C++ Redistributable f ...
- Android常见问题及解决方案收集
1.手机安裝Apk时提示“无法打开文件” 出现这个问题,是因为下载的服务端对APK的MIME类型设置错误导致,一般会设置为application/vnd.android,其实这是错误的,应该设置为ap ...
- 用Lucene4.5对中文文本建立索引
这里需要完成一个能对txt文本建立索引,并能完成检索查询.完成这个功能,使用的是Lucene4.5,同时使用其自带的中文分析器. 准备工作是在一个文件夹里面建一些txt文件,这是我的文件结构: 首先要 ...
- SSM商城项目(一)
1. 学习计划 1.电商行业的背景. 2.宜立方商城介绍 3.宜立方商城的系统架构 a) 功能介绍 b) 架构讲解 4.工程搭建-后台工程 a) 使用maven搭建工程 b) 使用maven的tomc ...
- vim字符串替换及小技巧
vi/vim 中可以使用 :s 命令来替换字符串.以前只会使用一种格式来全文替换,今天发现该命令有很多种写法(vi 真是强大啊,还有很多需要学习),记录几种在此,方便以后查询. :s/vivian/s ...
- EF CodeFirst学习笔记002--更新数据库表
BlogEntities这个类从DbContext继承,负责数据库的更新. Database.SetInitializer(new DropCreateDatabaseIfModelChanges&l ...
- python 遍历enumerate
在python中enumerate的用法多用于在for循环中得到计数,本文即以实例形式向大家展现python中enumerate的用法.具体如下: enumerate参数为可遍历的变量,如 字符串,列 ...
- Mac IntelliJ IDEA 2017(java开发集成环境)附注册码和破解教程 v2017.3.5破解版
原文:http://www.orsoon.com/Mac/155938.html 原文中含有软件下载地址 软件介绍 IntelliJ IDEA 2017 Mac激活版是Mac平台上的一款java开发集 ...
- as3.0用了视频组件,导致视频打开后就全屏,加一下代码就行
myFlv.fullScreenTakeOver = false; fullScreenTakeOver : Boolean 舞台进入全屏模式时,FLVPlayback 组件位于所有内容的顶部并占据整 ...