在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)html
編譯文檔:http://pythonqt.sourceforge.net/Building.html
這裏以Linux(Ubuntu系)爲例,介紹一下編譯安裝方法。python
去Qt網站下載安裝包,或者經過apt安裝。安裝完畢後,在命令行中執行qmake -v
,查看輸出信息,確認Qt已安裝好。
注意:若是使用apt或者synaptic安裝Qt,那麼須要手動安裝Qt的一些模塊,例如multimedia等。以Qt5爲例,其模塊通常以libqt5爲開頭,能夠用apt或synaptic搜索關鍵字安裝。若是缺乏模塊,則編譯PythonQt時會報錯提示(報錯是 Unknown module(s))。若是出現相似錯誤,則須要安裝相關模塊,再從新編譯。
大部分Qt模塊的軟件包名稱都是以libqt5開頭的,例如libqt5gui五、libqt5multimedia五、libqt5qml5等,有些可能以-dev結尾。可是有一些模塊的名稱則不同,這裏列出來,以避免遺漏:linux
用apt安裝Python和Python-dev。Linux通常預裝Python。
sudo apt install python python-dev
shell
將下載的源碼解壓。進入解壓目錄,以後執行編譯指令。假設解壓目錄爲PythonQt編程
cd PythonQt qmake make all
編譯可能須要花費幾分鐘,請耐心等待。
編譯完成後,編譯獲得的庫文件以及範例程序都在PythonQt/lib
下。此時運行範例程序可能失敗,須要先安裝剛編譯好的庫。app
所謂安裝,是指讓系統可以找到編譯好的庫文件。實現的方式有多種,這裏介紹經過連接的方式安裝。
首先確認系統中的庫文件默認目錄是什麼。python2.7
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
下的範例程序(雙擊或命令行執行),若是能夠運行,說明正常。函數
能夠看範例源碼和官方文檔學習。這裏以Linux(Ubuntu系)環境爲例,簡單介紹一下使用方法。學習
使用QtCreator新建項目。
須要將一些配置文件和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}
在項目.pro文件中加入如下內容:
include ( common.prf ) include ( PythonQt.prf ) INCLUDEPATH += 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代碼只有單一一行語句或者少許幾語句,可使用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函數。
若是須要使用Python實現較爲複雜的功能,寫在一個Python文件中比較方便。假設文件名爲func.py。
Python文件的開頭須要加入以下語句:
from PythonQt import *
在Qt項目中新建資源文件(.qrc文件),在資源文件中添加func.py,以便調用。調用方式爲:
mainModule.evalFile(":/func.py");
調用時的文件路徑與添加到資源文件時的前綴有關。注意evalFile
沒有返回類型,因此不能用於得到返回值,能夠經過第四節所說的打印信息看到執行過程(若是Python程序中有輸出語句的話)。若是是Qt GUI項目,也能夠把執行結果顯示在界面上,這一點在後面第四部分介紹。
執行過evalFile
後,腳本中定義的函數能夠在之後直接調用。因此能夠把須要返回值的功能寫在函數中,後續調用。調用方式見第三部分。
前面介紹了,使用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。
若是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'
既然使用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內的切換功能快速定位)。