信息技術(shù)八年級(jí)上冊(cè)網(wǎng)站建設(shè)鄭州seo實(shí)戰(zhàn)培訓(xùn)
PySide2/PySide6、PyQt5/PyQt6:都是基于Qt 的Python庫,可以形象地這樣說,PySide2 是Qt的 親兒子(Qt官方開發(fā)的) , PyQt5 是Qt還沒有親兒子之前的收的 義子 (Riverbank Computing這個(gè)公司開發(fā)的,有商業(yè)版權(quán)限制)。
兩個(gè)庫的使用 對(duì)程序員來說,差別很小:它們的調(diào)用接口幾乎一模一樣。如果你的程序是PyQt5開發(fā)的,通常只要略作修改,比如把導(dǎo)入的名字從 PyQt5 換成 PySide2 就行了。反之亦然。
對(duì)應(yīng):PySide2-PyQt5
、PySide6-PyQt6
安裝pyside2:(推薦使用)
pip install pyside2 -i https://pypi.douban.com/simple/`
安裝pyside6:
pip install pyside6
安裝pyqt5:
pip install pyqt5-tools
安裝pyqt6:
pip install pyqt6-tools
問題:運(yùn)行pyside2代碼時(shí)發(fā)生初始化問題
解決:
方法1 :在代碼頭中加入環(huán)境變量
import sys, os
import PySide2
from PySide2.QtWidgets import *
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
print(plugin_path)
方法2:
把 PySide2 或者 PyQt5 安裝在解釋器目錄下的 \plugins\platforms 目錄添加到環(huán)境變量Path中。
比如,我的環(huán)境就是把這個(gè)路徑加到 環(huán)境變量 Path 中
D:\Anaconda\envs\virtual_pytorch\Library\plugins\platforms
1 基礎(chǔ)—(控件、動(dòng)作、封裝)
1.1 控件 (QtWidgets)
QApplication
提供了整個(gè)圖形界面程序的底層管理功能,比如:初始化、程序入口參數(shù)的處理,用戶事件(對(duì)界面的點(diǎn)擊、輸入、拖拽)分發(fā)給各個(gè)對(duì)應(yīng)的控件等等。所以,我們必須在任何界面控件對(duì)象創(chuàng)建前,先創(chuàng)建它。
app = QApplication([])
QMainWindow
、QPlainTextEdit
、QPushButton
是3個(gè)控件類,分別對(duì)應(yīng)界面的主窗口、文本框、按鈕。他們都是控件基類對(duì)象QWidget的子類。要在界面上 創(chuàng)建一個(gè)控件 ,就需要在程序代碼中 創(chuàng)建 這個(gè) 控件對(duì)應(yīng)類 的一個(gè) 實(shí)例對(duì)象。
window = QMainWindow()
window.resize(500, 400)
window.move(300, 310)
window.setWindowTitle('窗口名')textEdit = QPlainTextEdit(window)
textEdit.setPlaceholderText("文本框名")
textEdit.move(10,25)
textEdit.resize(300,350)button = QPushButton('按鈕名', window)
button.move(380,80)window.show() # 顯示窗口app.exec_() # 進(jìn)入QApplication的事件處理循環(huán),接收用戶的輸入事件
在 Qt 系統(tǒng)中,控件(widget)是 層層嵌套
的,除了最頂層的控件,其他的控件都有父控件。QPlainTextEdit、QPushButton 實(shí)例化時(shí),都有一個(gè)參數(shù)window
,就是指定它的父控件對(duì)象 是 window 對(duì)應(yīng)的QMainWindow 主窗口。而 實(shí)例化 QMainWindow 主窗口時(shí),卻沒有指定 父控件, 因?yàn)樗褪亲钌蠈拥目丶恕?/p>
控件對(duì)象的 move 方法
決定了這個(gè)控件顯示的位置
。
控件對(duì)象的 resize 方法
決定了這個(gè)控件顯示的大小
。
放在主窗口的控件,要能全部顯示在界面上, 必須使用window.show()
最后 ,通過app.exec_()
,進(jìn)入QApplication的事件處理循環(huán),接收用戶的輸入事件,并且分配給相應(yīng)的對(duì)象去處理。
常用控件介紹:https://www.byhy.net/tut/py/gui/qt_05_1/
1.2 動(dòng)作 (signal 和 slot)
在 Qt 系統(tǒng)中, 當(dāng)界面上一個(gè)控件被操作
時(shí),比如 被點(diǎn)擊、被輸入文本、被鼠標(biāo)拖拽等, 就會(huì)發(fā)出 信號(hào)signal
。就是表明一個(gè)事件發(fā)生
了(比如被點(diǎn)擊、被輸入文本)。
我們可以預(yù)先在代碼中指定處理這個(gè) signal 的函數(shù),這個(gè)處理 signal 的函數(shù)
叫做 槽slot
。
比如上節(jié)例子中,我們可以像下面這樣定義一個(gè)slot函數(shù):
def handleCalc():QMessageBox.about(window, '關(guān)于', '點(diǎn)擊按鈕1次')
QMessageBox
是的信息提示框?qū)ο?#xff0c;他的about方法可以單獨(dú)彈出一個(gè)提示框。
然后, 指定 如果 發(fā)生了button 按鈕被點(diǎn)擊 的事情,需要讓 handleCalc 來處理,像這樣
button.clicked.connect(handleCalc)
用QT的術(shù)語來解釋上面這行代碼,就是:把 button
被點(diǎn)擊(clicked)
產(chǎn)生的信號(hào)signal
, 連接(connect)
到了 handleCalc
這樣的一個(gè)處理函數(shù)slot
上。
大白話就是:讓 handleCalc 來 處理 button 被 點(diǎn)擊的操作。
1.3 封裝
上面的代碼把控件對(duì)應(yīng)的變量名全部作為全局變量。
如果要設(shè)計(jì)稍微復(fù)雜一些的程序,就會(huì)出現(xiàn)太多的控件對(duì)應(yīng)的變量名。
而且這樣也不利于 代碼的模塊化。
所以,我們通常應(yīng)該把窗口和其包含的控件(self)
以及處理函數(shù)
,對(duì)應(yīng)的代碼 全部封裝到類中
:
import sys, os
import PySide2
from PySide2.QtWidgets import *
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
print(plugin_path)class Stats():def __init__(self):self.window = QMainWindow()self.window.resize(500, 400)self.window.move(300, 300)self.window.setWindowTitle('窗口名')self.textEdit = QPlainTextEdit(self.window)self.textEdit.setPlaceholderText("文本框默認(rèn)內(nèi)容")self.textEdit.move(10, 25)self.textEdit.resize(300, 350)self.button = QPushButton('按鈕名', self.window)self.button.move(380, 80)self.button.clicked.connect(self.handleCalc)def handleCalc(self):QMessageBox.about(self.window, '關(guān)于', '點(diǎn)擊按鈕1次')app = QApplication([])
stats = Stats()
stats.window.show()
app.exec_()
2 界面布局
2.1 Qt Designer
我們可以用QT界面生成器
Qt Designer ,拖拖拽拽
就可以直觀的創(chuàng)建出程序大體的界面。
怎么運(yùn)行這個(gè)工具呢?
Windows下,運(yùn)行 Python安裝目錄下 Scripts\pyside2-designer.exe
這個(gè)可執(zhí)行文件
如果你安裝的是pyqt5, 運(yùn)行 Python安裝目錄下 Scripts\pyqt5designer.exe 這個(gè)可執(zhí)行文件。
主界面區(qū)域介紹:
工具箱 區(qū)域
:提供GUI界面開發(fā)使用的各種基本控件,如單選框、文本框等??梢酝蟿?dòng)到新創(chuàng)建的主程序界面。
主界面 區(qū)域
:用戶放置各種從工具箱拖過來的各種控件。模板選項(xiàng)中最常用的就是Widget(通用窗口)和MainWindow(主窗口)。二者區(qū)別主要是Widget窗口不包含菜單欄、工具欄等??梢苑謩e創(chuàng)建對(duì)比看看。
對(duì)象查看器 區(qū)域
:查看主窗口放置的對(duì)象列表。
屬性編輯器 區(qū)域
: 提供對(duì)窗口、控件、布局的屬性編輯功能。比如修改控件的顯示文本、對(duì)象名、大小等。
信號(hào)/槽編輯器 區(qū)域
:編輯控件的信號(hào)和槽函數(shù),也可以添加自定義的信號(hào)和槽函數(shù)。
Widget Box控件工具箱介紹:
窗體(Window)
:
Mian Window(包含菜單欄的窗體)Widget(不包含菜單欄的窗體)
顯示控件(Display Widget)
:
Lable:文本標(biāo)簽,顯示文本,可以用來標(biāo)記控件。PySide2 中QLabel類可以顯示文字和圖片,選擇了QLabel加Timer播放。QLabel顯示的格式必須是Qimage,但是用cv2讀取的幀格式是numpy array,必須把它轉(zhuǎn)換成為Qimage。Text Browser:顯示文本控件。用于后臺(tái)命令執(zhí)行結(jié)果顯示。
輸入控件(Input Widget)
:提供與用戶輸入交互
Line Edit:單行文本框,輸入單行字符串??丶?duì)象常用函數(shù)為Text() 返回文本框內(nèi)容,用于獲取輸入。setText() 用于設(shè)置文本框顯示。Text Edit:多行文本框,輸入多行字符串??丶?對(duì)象常用函數(shù)同Line Edit控件。Combo Box:下拉框列表。用于輸入指定枚舉值。
控件按鈕(Buttons)
:供用戶選擇與執(zhí)行
Push Button:命令按鈕。常見的確認(rèn)、取消、關(guān)閉等按鈕就是這個(gè)控件。clicked信號(hào)一定要記住。clicked信號(hào)就是指鼠標(biāo)左鍵按下然后釋放時(shí)會(huì)發(fā)送信號(hào),從而觸發(fā)相應(yīng)操作。Radio Button:單選框按鈕。Check Box:多選框按鈕。
布局(Layout)
:不同布局方式可以嵌套;比如A是水平布局,B是垂直布局 ,可以選中AB再做一種布局方式;參考講解Layout
布局有三種方法:
1、先在左側(cè)空間欄Layouts中的某種布局方式拖動(dòng)到主窗口;再將組件拖入布局窗中;
2、先將組件拖入主窗中并選中;再點(diǎn)擊工具欄中的某種布局方式,如下圖。
3、先將組件拖入主窗中并選中;鼠標(biāo)右鍵>布局,選擇其中一種布局方式。
所有組件的布局完成之后,如下圖紅色框位置,頂層還未布局;選中頂層,然后對(duì)其進(jìn)行布局??梢赃M(jìn)行水平、垂直、網(wǎng)格的任意一種(效果一樣)。至此已經(jīng)完成了所有布局,按CTRL+R預(yù)覽的時(shí)候拉大窗口,所有組件會(huì)隨著窗口的變化而變化。
間隔(Spacers)
:實(shí)現(xiàn)部件布局排列美觀,如自動(dòng)靠左對(duì)齊或者靠右對(duì)齊的方式來顯示等。Spacers部件除了名字之外只有三個(gè)屬性,分別是orientation、sizeType和sizeHint。
屬性編輯器介紹:
有從父類Widget繼承而來的屬性,也有自己控件獨(dú)特的屬性,比較方便。
常用的屬性介紹:
名稱 | 含義 |
---|---|
objectName | 控件對(duì)象名稱 |
geometry | 相應(yīng)左上角為原點(diǎn)的坐標(biāo)與寬和高(x,y),x,y |
sizePolicy | 控件大小的策略 |
minimumSize | 最小的寬和高 |
maximumSize | 最大的寬和高 |
font | 字體 |
cursor | 光標(biāo) |
…… | …… |
導(dǎo)出設(shè)計(jì):
通過 Qt Designer 設(shè)計(jì)的界面,最終是生成XML格式
的ui界面定義文件
。
2.2 動(dòng)態(tài)加載UI文件(推薦)
有了界面定義文件,我們的Python程序就可以從文件中加載UI定義,并且動(dòng)態(tài) 創(chuàng)建一個(gè)相應(yīng)的窗口對(duì)象。
如下:
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import *
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
print(plugin_path)class Stats:def __init__(self):# 從文件中加載UI定義self.ui = QUiLoader().load('你的UI文件名.ui')# 從 UI 定義中動(dòng)態(tài) 創(chuàng)建一個(gè)相應(yīng)的窗口對(duì)象# 注意:里面的控件對(duì)象也成為窗口對(duì)象self.ui的屬性了# 比如 self.ui.button , self.ui.textEditself.ui.button.clicked.connect(self.handleCalc)def handleCalc(self):QMessageBox.about(self.window, '關(guān)于', '點(diǎn)擊按鈕1次')app = QApplication([])
stats = Stats()
stats.ui.show()
app.exec_()
2.3 轉(zhuǎn)化UI文件為Python代碼(不推薦)
先把UI文件直接轉(zhuǎn)化為包含界面定義的Python代碼文件,然后在你的程序中使用定義界面的類,執(zhí)行如下的命令 把UI文件直接轉(zhuǎn)化為包含界面定義的Python代碼文件。
pyside2-uic main.ui > ui_main.py
然后在你的代碼文件中這樣使用定義界面的類
from PySide2.QtWidgets import QApplication,QMainWindow
from ui_main import Ui_MainWindow# 注意 這里選擇的父類 要和你UI文件窗體一樣的類型
# 主窗口是 QMainWindow, 表單是 QWidget, 對(duì)話框是 QDialog
class MainWindow(QMainWindow):def __init__(self):super().__init__()# 使用ui文件導(dǎo)入定義界面類self.ui = Ui_MainWindow()# 初始化界面self.ui.setupUi(self)# 使用界面定義的控件,也是從ui里面訪問self.ui.webview.load('http://www.baidu.com')app = QApplication([])
mainw = MainWindow()
mainw.show()
app.exec_()
通常采用動(dòng)態(tài)加載比較方便,因?yàn)楦膭?dòng)界面后,不需要轉(zhuǎn)化,直接運(yùn)行,特別方便。
3 顯示樣式
要讓產(chǎn)品更好看一些,通常就是指定界面元素的 顯示樣式 。比如指定顏色、字體、間距。Qt有種定義界面顯示樣式的方法,稱之為 Qt Style Sheet ,簡稱 QSS。
如果在設(shè)計(jì)師界面上 最上層的 MainWindow
對(duì)象 styleSheet
屬性指定如下的內(nèi)容
QPushButton { color: red ;font-size:15px;
}
就會(huì)發(fā)現(xiàn),所有的按鈕上的文字都變成了紅色的,并且字體變大了。注意這個(gè)指定界面元素 顯示樣式的 語法,由 selector
和 declaration
組成。
- 花括號(hào)前面的 部分,比如示例中的 QPushButton 稱之為 selector。
- 花括號(hào)后面的 部分,稱之為 Properties樣式屬性。
選擇器selector:花括號(hào)前面的 部分稱之為 selector,用來 告訴Qt 哪些特征的元素
是你要設(shè)定顯示效果的。
樣式屬性declaration:在Qt Designer
中設(shè)置樣式。
背景
:可以指定某些元素的背景色,像這樣
QTextEdit { background-color: yellow }
顏色可以使用紅綠藍(lán)數(shù)字,像這樣
QTextEdit { background-color: #e7d8d8 }
也可以像這樣指定背景圖片
QTextEdit {background-image: url(gg03.png);
}
邊框
:可以像這樣指定邊框
border:1px solid #1d649c;
其中,1px 是邊框?qū)挾?#xff0c;solid 是邊框線為實(shí)線, 也可以是 dashed(虛線) 和 dotted(點(diǎn))
比如
*[myclass=bar2btn]:hover{border:1px solid #1d649c;
}
邊框可以指定為無邊框
border:none
字體、大小、顏色
:可以這樣指定元素的 文字字體、大小、顏色
*{ font-family:微軟雅黑;font-size:15px;color: #1d649c;
}
寬度、高度
:可以這樣指定元素的 寬度、高度
QPushButton { width:50px;height:20px;
}
margin、padding
:
可以這樣指定元素的 元素的 margin,分別指定了元素的上右下左margin。
QTextEdit {margin:10px 11px 12px 13px
}
也可以使用 margin-top, margin-right, margin-bottom, margin-left 單獨(dú)指定 元素的上右下左margin。
QTextEdit {margin:10px 50px;padding:10px 50px;
}
4 后臺(tái)線程 與 信號(hào)
4.1 界面阻塞問題
我們 點(diǎn)擊按鈕
執(zhí)行槽函數(shù),如果服務(wù)端接收處理的比較慢,就會(huì)導(dǎo)致槽函數(shù)要比較長的時(shí)間才能返回。假設(shè)10秒鐘后,才接收到響應(yīng)消息,這時(shí)候,界面就會(huì) 僵死
10秒鐘。
這是因?yàn)?#xff0c;我們現(xiàn)在的代碼都是在主線程中執(zhí)行
的。其中最末尾的代碼:
app.exec_()
其實(shí)會(huì)讓主線程進(jìn)入一個(gè)死循環(huán)
,循環(huán)不斷的處理 用戶操作的事件。
當(dāng)我們點(diǎn)擊按鈕后,Qt的 核心代碼就會(huì)接受到這個(gè) 點(diǎn)擊事件,并且調(diào)用相應(yīng)的 slot函數(shù)去處理。
因?yàn)槲覀兇a做了這樣的設(shè)置
# 信號(hào)處理
self.ui.buttonSend.clicked.connect(self.槽函數(shù))
如果這個(gè)槽函數(shù)
很快能接收到 服務(wù)端的響應(yīng),那么 槽函數(shù) 就可以很快的返回。
返回后, 整個(gè)程序又進(jìn)入到 app.exec_() 里面接收各種 事件,并且調(diào)用相應(yīng)的函數(shù)去處理。界面就不會(huì)僵死,因?yàn)樗械牟僮鹘缑娴氖录?#xff0c;都能得到及時(shí)的處理。
但是,如果這個(gè) 槽函數(shù) 要很長時(shí)間才能返回,這段時(shí)間內(nèi),整個(gè)程序就停在 槽函數(shù)內(nèi)的某段代碼處
,自然就沒有機(jī)會(huì)去處理其他的用戶操作界面的事件了,當(dāng)然程序就僵死了。
4.2 子線程處理
典型的一種解決方法就是使用多線程
去處理。
為了防止槽函數(shù)
卡在 發(fā)送請(qǐng)求 或 處理數(shù)據(jù)的操作
上,我們可以使用Python多線程,將發(fā)送請(qǐng)求 或 處理數(shù)據(jù)的操作
封裝成一個(gè)函數(shù),在槽函數(shù)中創(chuàng)建新線程
,然后調(diào)用封裝好的函數(shù)。
這樣,通過創(chuàng)建新的線程去執(zhí)行[發(fā)送請(qǐng)求 或 處理數(shù)據(jù)]的方法,服務(wù)器響應(yīng)再慢,也只會(huì)在新線程中阻塞
,主線程啟動(dòng)新線程后,主線程就繼續(xù)執(zhí)行后面的代碼
,返回繼續(xù)運(yùn)行Qt的事件循環(huán)處理 ,可以響應(yīng)用戶的操作
,就不會(huì)僵死了。
from threading import Threaddef 槽函數(shù)(self):正常操作;# 創(chuàng)建新的線程去執(zhí)行發(fā)送方法,# 服務(wù)器慢,只會(huì)在新線程中阻塞# 不影響主線程thread = Thread(target = self.新線程請(qǐng)求或處理函數(shù),args= (參數(shù)列表))thread.start()# 新線程入口函數(shù)def 新線程請(qǐng)求或處理函數(shù)(self,參數(shù)列表):原來槽函數(shù)中 發(fā)送請(qǐng)求 或 處理數(shù)據(jù)的操作;
4.3 子線程發(fā)信號(hào)更新界面
Qt建議: 只在主線程中操作界面 。
在另外一個(gè)線程直接操作界面,可能會(huì)導(dǎo)致意想不到的問題,比如:輸出顯示不全,甚至程序崩潰。
但是,我們確實(shí)經(jīng)常需要在子線程中 更新界面。比如子線程是個(gè)爬蟲,爬取到數(shù)據(jù)顯示在界面上。
怎么辦呢?
這時(shí),推薦的方法是使用信號(hào)
。
前面我們?cè)?jīng)看到過 各種 Qt 控件可以發(fā)出信號(hào),比如 被點(diǎn)擊、被輸入等。
我們也可以自定義信號(hào)
,只要這個(gè)類繼承QObject類
,就能發(fā)出自己定義的各種Qt信號(hào),具體做法如下:
-
自定義一個(gè)
Qt 的 QObject類
,里面封裝一些自定義的 Signal信號(hào)
,一種信號(hào)定義為 該類的 一個(gè)靜態(tài)屬性
,值為Signal 實(shí)例對(duì)象即可??梢远x 多個(gè) Signal靜態(tài)屬性,對(duì)應(yīng)這種類型的對(duì)象可以發(fā)出的 多種 信號(hào)。
(如下MySignals類有text_print 信號(hào) 和 update_table 信號(hào))
注意:Signal實(shí)例對(duì)象的信號(hào)參數(shù)類型
,就是 發(fā)出信號(hào)對(duì)象時(shí),傳遞的參數(shù)數(shù)據(jù)類型。因?yàn)镼t底層是C++開發(fā)的,必須指定類型。(如下的QTextBrowser 和 str類型) -
定義
主線程
執(zhí)行的函數(shù)處理Signal信號(hào)
(通過connect方法) -
在
新線程需要操作界面的時(shí)候
,就通過自定義對(duì)象
發(fā)出 信號(hào)
通過該信號(hào)對(duì)象
的emit方法
發(fā)出信號(hào), emit方法的參數(shù) 傳遞必要的數(shù)據(jù)。參數(shù)類型 遵循 定義Signal時(shí),指定的類型。 -
主線程
信號(hào)處理函數(shù),被觸發(fā)執(zhí)行,獲取Signal里面的參數(shù),執(zhí)行必要的更新界面操作
from PySide2.QtWidgets import QApplication, QTextBrowser
from PySide2.QtUiTools import QUiLoader
from threading import Threadfrom PySide2.QtCore import Signal,QObject# 自定義信號(hào)源對(duì)象類型,一定要繼承自 QObject
class MySignals(QObject):# 定義一種text_print信號(hào),兩個(gè)參數(shù) 類型分別是: QTextBrowser 和 字符串# 調(diào)用 emit方法 發(fā)信號(hào)時(shí),傳入?yún)?shù) 必須是這里指定的 參數(shù)類型text_print = Signal(QTextBrowser,str)# 還可以定義其他種類的update_table信號(hào)update_table = Signal(str)# 實(shí)例化
global_ms = MySignals() # GUI類
class Stats:def __init__(self):self.ui = QUiLoader().load('main.ui')# 自定義信號(hào)MySignals類的處理函數(shù)global_ms.text_print.connect(self.printToGui)# 自定義信號(hào)處理函數(shù)def printToGui(self,fb,text):fb.append(str(text))fb.ensureCursorVisible()# 產(chǎn)生text_print信號(hào)時(shí)的界面操作函數(shù)def task1(self):def threadFunc():# 通過Signal 的 emit 觸發(fā)執(zhí)行 主線程里面的處理函數(shù)# emit參數(shù)和定義Signal的數(shù)量、類型必須一致global_ms.text_print.emit(self.ui.infoBox1, '輸出內(nèi)容')thread = Thread(target = threadFunc )thread.start()
5 智云平臺(tái)實(shí)戰(zhàn)
智云平臺(tái)是一個(gè)集成活體檢測、人臉識(shí)別、關(guān)鍵點(diǎn)檢測、人像分割、疲勞檢測、視線追蹤、微表情識(shí)別、危險(xiǎn)駕駛動(dòng)作識(shí)別、火災(zāi)檢測、越獄檢測、打架檢測的開放算法平臺(tái)。
待更…
程序圖標(biāo)
添加主窗口圖標(biāo)
我們程序運(yùn)行的窗口,需要顯示自己的窗口圖標(biāo)
,這樣才更像一個(gè)正式的產(chǎn)品。
通過如下代碼,我們可以把一個(gè)png圖片
文件作為 程序窗口圖標(biāo)。
from PySide2.QtGui import QIconapp = QApplication([])
# 加載 icon
app.setWindowIcon(QIcon('logo.png'))
注意:這些圖標(biāo)png文件,在使用PyInstaller創(chuàng)建可執(zhí)行程序時(shí),也要拷貝到程序所在目錄。否則可執(zhí)行程序運(yùn)行后不會(huì)顯示圖標(biāo)。
應(yīng)用程序圖標(biāo)
應(yīng)用程序圖標(biāo)是放在可執(zhí)行程序里面的資源??梢栽赑yInstaller創(chuàng)建可執(zhí)行程序時(shí),通過參數(shù) --icon=“l(fā)ogo.ico” 指定。
pyinstaller main_ui.py --noconsole --hidden-import PySide2.QtXml --icon="logo.ico"
注意參數(shù)一定是存在的ico文件
,不能是png等圖片文件。
如果你只有png文件,可以通過在線的png轉(zhuǎn)ico文件網(wǎng)站,生成ico,比如下面的網(wǎng)站:IOC生成
發(fā)布程序
我們前面開發(fā)的QT界面程序,在Windows 上只需要執(zhí)行pyinstaller
的命令,即可制作獨(dú)立exe程序。
pyinstaller main_ui.py --noconsole --hidden-import PySide2.QtXml
這樣就會(huì)在當(dāng)前目錄下產(chǎn)生一個(gè)名為 dist
的目錄,dist目錄
里面就有一個(gè)名為 main_ui的目錄
,我們的可執(zhí)行程序 main_ui.exe
就在里面。
main_ui.py
dis____|main_ui____|main_ui.exe
其中:
-
main_ui.py
是包含QApplication()
的GUI程序,可以自己命名。 -
noconsole
指定不要命令行窗口,否則我們的程序運(yùn)行的時(shí)候,還會(huì)多一個(gè)黑窗口。 但是我建議大家可以先去掉這個(gè)參數(shù),等確定運(yùn)行成功后,再加上參數(shù)重新制作exe。因?yàn)檫@個(gè)黑窗口可以顯示出程序的報(bào)錯(cuò),這樣我們?nèi)菀渍业絾栴}的線索。 -
hidden-import PySide2.QtXml
參數(shù)是因?yàn)檫@個(gè) QtXml庫是動(dòng)態(tài)導(dǎo)入,PyInstaller沒法分析出來,需要我們告訴它。
最后,如果使用的是動(dòng)態(tài)加載UI文件,別忘了,把程序所需要的ui文件拷貝到main_ui.exe同級(jí)目錄中。
因?yàn)镻yInstaller只能分析出需要哪些代碼文件。 而你的程序動(dòng)態(tài)打開的資源文件,比如 圖片、excel、ui這些,它是不會(huì)幫你打包的。