在Qt(C++)中与Python混合编程
⼀、PythonQt库
在Qt(C++)中与Python混合编程,可以使⽤PythonQt库。
⽹站⾸页:
下载页⾯:
只提供了源码下载,需⾃⾏编译。
版本要求:
其⽹站building页⾯上的要求:Qt 4.8.1以上,Python2.6以上
实际测试中得出的版本要求:Qt5.4以上,可以编译得到动态链接库(.so⽂件);Python2.7.12,编译范例程序成功。
(备注:我的测试环境是操作系统 Ubuntu 16.04 64bit,PythonQt版本:3.2)
⼆、编译与安装
编译⽂档:
这⾥以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模块有关
ubuntu怎么安装python
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/f.d/
ls
可能列出⼀些配置⽂件,⽂件名是对应的⽬录,⽐如f。⽤⽂本编辑器打开,就可以看到对应的完整⽬录。我的系统中默认库⽬录有
/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):
< = 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中,应该使⽤
< = '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源码中的范例,以及⽹站上的⽂档。
开发者⽂档:
源码中也有很多有⽤信息,关于⼀些API函数的调⽤,可以参考头⽂件中的注释。例如,关于上⾯介绍的evalScript等函数,可以参考PythonQtObjectPtr.h⽂件(可⽤QtCreator内的切换功能快速定位)。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。