《快速掌握PyQt5》第二十二章 Pyinstaller打包
第二十二章 Pyinstaller打包
寫完的程式如果要發給別人使用,但對方並沒有安裝python環境,也沒有安裝PyQt5庫時怎麼辦呢?最好的解決辦法就是將程式打包成可執行檔案,這樣就算在一臺沒有安裝python環境和PyQt5庫的電腦上也可以使用,非常方便。
22.1 下載Pyinstaller
windows上下載:
pip install pyinstaller
Linux上下載:
pip3 install pyinstaller
Mac上下載:
pip3 install pyinstaller
下載完後我們開啟終端,輸入pyinstaller,若顯示如下,則表示安裝成功:
22.2 瞭解Pyinstaller命令引數
這裡我們只需要瞭解幾個常用命令即可,詳細用法請參考Pyinstaller手冊:
引數 | 用處 |
-F | 將程式打包成一個檔案 |
-w | 去除黑框 |
-i | 新增程式圖示 |
22.3 打包示例
我們就將第五章的登入框小程式拿過來打包作為示例好了,該程式的程式碼如下:
import sys from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QLabel, QLineEdit, QPushButton, \ QGridLayout, QVBoxLayout, QHBoxLayout, QMessageBox USER_PWD = { 'la_vie': 'password' } class Demo(QWidget): def __init__(self): super(Demo, self).__init__() self.resize(300, 100) self.user_label = QLabel('Username:', self) self.pwd_label = QLabel('Password:', self) self.user_line = QLineEdit(self) self.pwd_line = QLineEdit(self) self.login_button = QPushButton('Log in', self) self.signin_button = QPushButton('Sign in', self) self.grid_layout = QGridLayout() self.h_layout = QHBoxLayout() self.v_layout = QVBoxLayout() self.lineedit_init() self.pushbutton_init() self.layout_init() self.signin_page = SigninPage() # 例項化SigninPage() def layout_init(self): self.grid_layout.addWidget(self.user_label, 0, 0, 1, 1) self.grid_layout.addWidget(self.user_line, 0, 1, 1, 1) self.grid_layout.addWidget(self.pwd_label, 1, 0, 1, 1) self.grid_layout.addWidget(self.pwd_line, 1, 1, 1, 1) self.h_layout.addWidget(self.login_button) self.h_layout.addWidget(self.signin_button) self.v_layout.addLayout(self.grid_layout) self.v_layout.addLayout(self.h_layout) self.setLayout(self.v_layout) def lineedit_init(self): self.user_line.setPlaceholderText('Please enter your username') self.pwd_line.setPlaceholderText('Please enter your password') self.pwd_line.setEchoMode(QLineEdit.Password) self.user_line.textChanged.connect(self.check_input_func) self.pwd_line.textChanged.connect(self.check_input_func) def pushbutton_init(self): self.login_button.setEnabled(False) self.login_button.clicked.connect(self.check_login_func) self.signin_button.clicked.connect(self.show_signin_page_func) def check_login_func(self): if USER_PWD.get(self.user_line.text()) == self.pwd_line.text(): QMessageBox.information(self, 'Information', 'Log in Successfully!') else: QMessageBox.critical(self, 'Wrong', 'Wrong Username or Password!') self.user_line.clear() self.pwd_line.clear() def show_signin_page_func(self): self.signin_page.exec_() def check_input_func(self): if self.user_line.text() and self.pwd_line.text(): self.login_button.setEnabled(True) else: self.login_button.setEnabled(False) class SigninPage(QDialog): def __init__(self): super(SigninPage, self).__init__() self.signin_user_label = QLabel('Username:') self.signin_pwd_label = QLabel('Password:') self.signin_pwd2_label = QLabel('Password:') self.signin_user_line = QLineEdit() self.signin_pwd_line = QLineEdit() self.signin_pwd2_line = QLineEdit() self.signin_button = QPushButton('Sign in') self.user_h_layout = QHBoxLayout() self.pwd_h_layout = QHBoxLayout() self.pwd2_h_layout = QHBoxLayout() self.all_v_layout = QVBoxLayout() self.lineedit_init() self.pushbutton_init() self.layout_init() def layout_init(self): self.user_h_layout.addWidget(self.signin_user_label) self.user_h_layout.addWidget(self.signin_user_line) self.pwd_h_layout.addWidget(self.signin_pwd_label) self.pwd_h_layout.addWidget(self.signin_pwd_line) self.pwd2_h_layout.addWidget(self.signin_pwd2_label) self.pwd2_h_layout.addWidget(self.signin_pwd2_line) self.all_v_layout.addLayout(self.user_h_layout) self.all_v_layout.addLayout(self.pwd_h_layout) self.all_v_layout.addLayout(self.pwd2_h_layout) self.all_v_layout.addWidget(self.signin_button) self.setLayout(self.all_v_layout) def lineedit_init(self): self.signin_pwd_line.setEchoMode(QLineEdit.Password) self.signin_pwd2_line.setEchoMode(QLineEdit.Password) self.signin_user_line.textChanged.connect(self.check_input_func) self.signin_pwd_line.textChanged.connect(self.check_input_func) self.signin_pwd2_line.textChanged.connect(self.check_input_func) def pushbutton_init(self): self.signin_button.setEnabled(False) self.signin_button.clicked.connect(self.check_signin_func) def check_input_func(self): if self.signin_user_line.text() and self.signin_pwd_line.text() and self.signin_pwd2_line.text(): self.signin_button.setEnabled(True) else: self.signin_button.setEnabled(False) def check_signin_func(self): if self.signin_pwd_line.text() != self.signin_pwd2_line.text(): QMessageBox.critical(self, 'Wrong', 'Two Passwords Typed Are Not Same!') elif self.signin_user_line.text() not in USER_PWD: USER_PWD[self.signin_user_line.text()] = self.signin_pwd_line.text() QMessageBox.information(self, 'Information', 'Register Successfully') self.close() else: QMessageBox.critical(self, 'Wrong', 'This Username Has Been Registered!') self.signin_user_line.clear() self.signin_pwd_line.clear() self.signin_pwd2_line.clear() if __name__ == '__main__': app = QApplication(sys.argv) demo = Demo() demo.show() sys.exit(app.exec_())
我們將這個py檔案命名為test.py,並將檔案放到桌面上,之後開啟命令列視窗,cd到桌面目錄,輸入pyinstaller -F -w test.py
點選回車,開始打包:
結束後我們會發現在桌面上多了兩個資料夾和一個spec檔案:
而我們想要的可執行程式就在dist資料夾中,雙擊開啟就是我們的程式了:
現在你完全可以就將這個test可執行檔案放到其他電腦上去執行。
上面打包的可執行檔案使用的是預設的圖示,我們接下來打包時新增-i引數來給程式加個圖示(請注意該用法只對Windows系統有效):
將該圖示命名為login.ico並放在桌面,跟test.py同路徑。同樣開啟命令列視窗,cd到桌面,輸入pyinstaller -F -w -i login.ico test.py 按回車開始打包:
然後在dist資料夾中就可以找到我們打包好的可執行檔案:
22.4 小結
1. 打包時可能會出現各種各樣的問題,但大部分問題其實只要仔細閱讀報錯內容就可以解決,不要慌;
2. 筆者彙總了一些用Pyinstaller打包時出現的問題,詳情請見:Pyinstaller打包問題之解決方案彙總。
----------------------------------------------------------------------
喜歡的小夥伴可以加入這個Python QQ交流群一起學習:820934083