1. 程式人生 > >Python中使用pyinstaller將pyqt所寫的程式打包為exe檔案

Python中使用pyinstaller將pyqt所寫的程式打包為exe檔案

Python中使用pyinstaller將pyqt所寫的程式打包為exe檔案

前言

最近需要寫一些小工具來輔助工作,其中一些想了想如果有一個簡單的介面的話應該使用起來更方便一些,由於python的方便性,大概試了一下python中的幾個常用的圖形庫,如wxPythonTkinter等,通過比較,感覺還是pyqt做出來的介面美觀性要強一些,而且可移植性較好。

在寫完程式的大概之後,即在IDE裡執行程式可以出現想要的介面了,現在的一個問題是,以後開啟這些程式的時候,若要每次都要先開啟IDE然後執行程式,這個過程未免太過繁瑣,所以想要將所寫的程式打包為exe檔案,這樣今後開啟的時候會方便許多,在其它機器上工作的時候移植也要方便。

本文就主要介紹如何將用pyqt所寫的程式打包為exe程式。

環境準備

1、 anaconda下2與3共存的方式與在3的環境中安裝包的方法

在本次嘗試中遇到了許多問題,其中絕大部分問題最後歸論起來還是pyqt環境安裝的有問題,所以在安裝pyqt的過程中一定要注意。

我的python的版本為2.7,是用anaconda2安裝的環境。但是pyqt5對於python2的支援並不好,我在多次嘗試後,始終沒有找到合適的安裝方法,因此最後還是在python3的環境中進行的操作。但是,如果只是想要在程式中實現介面的話,2.7是沒有任何問題的,這裡只是在打包exe過程中遇到了問題。

簡單說一下anaconda,anaconda是一種集成了大多數常用的庫的python環境,對於python的安裝來說是一種非常方便的方式,anaconda的2與3兩個版本便對應著python的2與3。在anaconda中2是可以與3共存的,安裝的方法也比較簡單,我是先安裝的2,在安裝3的時候需要主要要裝到2的envs這個資料夾中新建的資料夾,如C:\Users\xxx\Anaconda2\envs\python3

,再有就是安裝的時候在這個介面最好兩個選項都不要打勾:
anaconda安裝
其餘的基本一路預設就可以,安裝完成之後,python3便可以作為一個獨立的環境來進行使用了,在IDE中可以選擇…/envs/python3這個資料夾下的python3的直譯器,即呼叫了python3的環境。而在控制檯中,預設的初始情況下,直接輸入python,進入的是預設的python2.7的環境(因為之前的系統變數中為2.7的環境,而安裝anaconda3的時候並沒有修改系統變數),使用python3 的方法為輸入語句activate python3(這裡的python3即為上面envs裡面新建的資料夾的名稱),此時系統預設的python的環境即更改為了python3,此時的pip
也會將包裝到3的環境中。此時,若輸入python則會進入python環境並顯示目前的python版本為python3.6:
配置環境
而這裡的第二行的開頭可以看到括號裡的python3,這裡說明預設環境已經更改到了python3。而之後的說明若無特殊說明均預設為在已經進入了預設python3的環境。

2、 配置SIP

我們要利用PyQt5來寫介面,所需的一個依賴庫便是sip,sip是RiverBank(也就是PyQt的開發商)開發的用於PyQt的Python/C++混合程式設計解決方案。SIP是一種工具,可以將Python與C和C++的庫進行繫結,它包括程式碼生成器和python等模組,這使得Python等解釋性程式設計環境可以開發現有的C或者C++的庫。
在這裡,sip屬於python的一個依賴庫,可以直接使用命令進行安裝

pip install sip

###3、 配置PyQt5
接下來便就是主角PyQt5了,在python3中可以直接使用pip進行安裝:

pip install PyQt5

當然這裡第二步和第三步會出現許多錯誤,我在後面會提到。
###4、 配置pyinstaller
這裡網上許多資料裡都使用下載包然後安裝的方式,但是我也是簡單地採用了pip的方式進行的安裝,並沒有出現問題。

pip install pyinstaller

測試

這裡是測試的時候用的程式碼,可以顯示出一個簡單的介面:

import sys
from PyQt5 import QtCore, QtWidgets

app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
widget.resize(320, 240)
widget.setWindowTitle("Hello, PyQT!")
widget.show()
sys.exit(app.exec())

將程式碼寫完後將其儲存為hello_PyQt.py檔案。

之後開啟控制檯,輸入activate python3將預設的python環境設定為python3,然後輸入cd 路徑進入剛剛的.py檔案所在的路徑:

步驟1

然後輸入pyinstaller -F -w hello_PyQt.py將程式碼打包為exe檔案(可以在網上查詢各種不同引數含義,這裡的-F與-w分別為儲存為一個檔案與執行exe檔案時不顯示控制檯):
步驟2
最後可以看見此時便儲存成功了,在剛剛的路徑中的多出來幾個資料夾與檔案,在build資料夾中可以檢視pyinstaller執行時的一些資訊,而在另一個dist資料夾中便有著hello_PyQt.exe檔案了,即為我們需要的exe檔案。此時執行該檔案:
結果
可以看到出現了我們程式碼中所實現的視窗,此時便執行成功。

過程中遇到的問題

1、 在配置sip時報錯

在配置sip時報錯:
···
Could not find a version that satisfies the requirement sip (from versions: )
No matching distribution found for sip
···
報錯1
報錯原因為:此時並沒有輸入activate python3命令進入預設python3環境,而sip對於python2.7支援並不好,因此無法直接pip進行安裝。

2、 在打包過程中報錯

在使用Pyinstaller進行打包的過程中,報錯:
···
Exception: Cannot find PyQt5 plugin directories
···
原因與上一條相同,沒有將預設Python環境更改為python3。

3、 在執行exe時報錯

這裡是整個環節中比較棘手的一環了,我遇到的主要問題是有兩點:
第一次是使用python2.7到了這一步,執行exe一直不成功,嘗試了很多種方法,但是都沒有完美解決的,之後用3.6來重新測試。
第二點是在用python3.6的時候遇到的,當時為了測試並沒有加-w引數,在執行exe檔案時會一閃而過一個控制檯資訊,內容為

ModuleNotFoundError: no modules named 'PyQt5.sip'

這裡的原因是,上面所配置的QtPy5SIP的版本是需要對應的,如果沒有對應的話,這一步就會出現這樣的問題。

因此,我們可以根據我們已經安裝的SIP的版本去確定我們所需要的PyQt5的版本。

首先,先將已有的PyQt5的包進行刪除,執行命令(記得進入Python3的預設環境):

pip uninstall pyqt5

然後檢視已經安裝過的sip的版本,方法為進入python環境後,先import sip,然後輸入sip.SIP_VERSION_STR命令,即可檢視:
檢視sip版本

可以看到我的sip的版本為’4.19.8‘,之後需要做的便是根據已經安裝的sip的版本來確定我們需要安裝的PyQt5的版本,這裡,要注意的是,兩個版本號在字面上並不是一一對應的,我還沒有找到一個明確的版本之間的對應關係。目前採用的方法為去檢視兩個包的歷史釋出日期,然後選擇與目前sip包釋出日期相近的PyQt5的版本,比如我現在的sip的版本為’4.19.8‘可以查到其對應的頁面為:sip 釋出歷史,釋出日期為2018年2月27日,然後再檢視PyQt5 釋出歷史,可以看到有同一天釋出的PyQt5,其版本為‘5.10.1’,因此,我們此時需要安裝的便就是這個版本,此時,執行命令:

pip install PyQt5==5.10.1

成功之後便安裝好了該版本的包,此時執行就不會出現問題了。

4、在執行exe檔案時彈窗報錯FATAL ERROR

在執行exe檔案的時候,彈出一個FATAL ERROR視窗,錯誤資訊為:

fail to execute script hello_PyQ

首先確定是否是在python2的環境中打包的(執行pyinstaller時),若是的話,應重新在python3 的環境打包。若已經為在python3的環境中打包的,則按照第三個錯誤中的方法來檢查一下,檢視包之間的對應關係,我這裡最後就是這麼解決的。