本文是PyQt4的入門教程。網上能搜到其它教程,但我覺得講得不是很清楚,希望這篇文章對入門者更加有協助。
先介紹一下PyQt4。Qt4圖形庫一經發布就好評不斷,它在Python下的綁定PyQt4更是讓我眼前一亮,不但漂亮,而且開發程式非常方便。
在我看來,PyQt4最大的改進之一是它不再拘泥與各種布局控制項了,也就是說,現在寫圖形介面程式,和VB一樣可以直接拖控制項到視窗上並隨便改變大小和位置了,不再像以前那樣要先放上布局控制項,再在布局控制項裡放其它控制項。
對PyQt4的介紹就限於此,我也不準備把它與其它Python圖形庫進行比較了,因為經驗表明這些東西的比較,特別是Qt與Gtk的比較總是會引起不必要的爭吵。
IDE我使用Eric4。Eric4本身是用PyQt4寫的,在使用Eric4時就能體會到用PyQt4能寫出多棒的圖形介面程式。Eric4的詳細介紹與安裝請見我的其它文章。
作業系統是Windows,在Linux下的操作完全一樣。
寒喧結束,進入正題。假設我們要用Python寫一個圖形介面程式,一個對話方塊,裡面兩個button一個label。點擊其中一個button能改變label的內容,點擊另一個button就退出。
1. 建立工程。
開啟Eric4,選擇菜單Project->New建立一個工程,名字我們取為HelloPyQt,填好各項並選擇工程所在檔案夾之後點OK,一個新的不含任何檔案的工程就建好了。
2. 建立對話方塊。
在左側的ProjectViewer中切換到Forms選項卡(左數第二個),右鍵點空白位置,選New Form,在彈出的對話方塊中選擇Form類型為Dialog,然後會問你儲存到哪。我設定為儲存為DlgHello.ui檔案。點OK之後就會建立這個檔案並自動開啟QtDesigner。
3. 設計介面。
先修改主對話方塊的屬性。選中對話方塊,在右側的屬性編輯器中就可以查看/修改對話方塊的屬性。將windowTitle改為"Hello, PyQt",將objectName改為"DlgHello”,前者是對話方塊標題,後者在以後產生代碼時有用,不建議使用預設值。
我們拖動一個Label(在DisplayWidgets分類中)到對話方塊中,將屬性text改為"Hello, PyQt",objectName改為lblHello。
再拖動兩個PushButton(在Buttons分類中)到對話方塊,分別將屬性text改為"你好"和"退出"。將屬性objectName分別改為btnHello和btnExit。
介面大概是這個樣子:
4. 處理事件。
在PyQt4下,事件處理方面的術語為“訊號”和“槽”,即signal和slot。事件對應訊號signal,而事件的處理函數則為slot槽。
PyQt4有一些預定義的slot,我們可以直接用,比如“退出”按鈕的slot,其實就是關閉對話方塊,這個slot已經在PyQt4中有定義了。對於這樣的slot,我們不用單獨寫代碼,在QtDesigner中就可以完成。而對於“你好”按鈕,我們需要自己寫代碼。對於這樣的slot,我們在QtDesigner中不做任何處理,甚至不做定義。
那麼在這個例子中,在QtDesigner裡我們只處理退出按鈕的單擊事件。
單擊“編輯訊號/槽”按鈕進入訊號/槽編輯模式。點中退出按鈕並拖動,會出現一個像是電路圖中的接地圖示一樣的東西,如下:
鬆開滑鼠,就會彈出“配置串連”對話方塊。勾上“顯示從QWidget繼承的訊號和槽”,左側選擇clicked(),右側選擇close(),點確定,就OK了。
如果要繼續調整對話方塊外觀,點擊“編輯視窗組件”按鈕返回視窗編輯模式。
5. 產生介面代碼
儲存之後關閉QtDesigner,會發現Eric4的ProjectViewer的Forms選項卡中已經多出DlgHello.ui了。右擊它選擇Compile Form,就能產生Ui_DlgHello.py檔案,並自動加入到工程中。在Sources選項卡中可以看到。
雙擊Ui_DlgHello.py可以看它的內容,其實是產生了一個Ui_DlgHello類。Ui_DlgHello.py是可以單獨啟動並執行,在Eric4中直接按F2可以運行,看看初步的效果。發現單擊退出按鈕果然能直接退出程式。
不建議手動修改Ui_DlgHello.py,因為每次改動介面並產生代碼後會將手動進行的修改給覆蓋掉。
6. 添加額外的代碼。
“你好”按鈕的單擊處理代碼還需要手寫。
在PyQt4中,介面代碼與事件代碼是分開的,這一點很贊,這樣每次改介面就不會影響到事件處理的代碼了。而wxPython這一點就做得不好。
事件處理要建立一個類並繼承DlgHello類,然後在這個新類裡寫事件處理函數。建立類的工作可以交給Eric4來完成。右鍵點DlgHello.ui,選擇Generate Dialog Code,在彈出的對話方塊中設定ClassName為DlgHello,同時,在這個對話方塊中可以選擇我們感興趣的事件,Eric4會一併建置事件處理函數的定義。如:
點確定之後,DlgHello.py就產生了。開啟這個檔案,“你好”按鈕的事件被定義為:
@pyqtSignature("")
def on_btnHello_clicked(self):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
raise NotImplementedError
注意這個@pyqtSignature("")自動處理了下面定義的槽slot(事件處理函數)與相對應的訊號signal(事件)之間的關聯,這裡是指,單擊btnHello按鈕,就會自動執行這個函數。slot的命名規則就是”on_對像名_訊號名”,如果想添加新的slot,按這個規則來添加函數就行,並且在函數定義語句之前加上@pyqtSignature(""),不用再重建一次DlgHello.py檔案。
其實另外一種關聯signal與slot之間的方法是在運行裡綁定,比如按鈕對象btnAbout的clicked訊號的槽是about_clicked函數,那麼在__init__函數中加入這樣一句話:
PyQt4.QtCore.QObject.connect(self.btnAbout, PyQt4.QtCore.SIGNAL("clicked()"), self.about_clicked)
那麼單擊按鈕btnAbout時就會執行about_clicked函數。
兩種方法各有長處。第一種方法簡單,第二種方法對於多個signal使用同一個slot時很有效。
將on_btnHello_clicked函數改為:
@pyqtSignature("")
def on_btnHello_clicked(self):
self.lblHello.setText("你好,PyQt4")
在檔案頭部加上:
import PyQt4, PyQt4.QtGui, sys
再在代碼最後加上(與Ui_DlgHello.py末的幾乎一樣):
if __name__ == "__main__":
app = PyQt4.QtGui.QApplication(sys.argv)
dlg = DlgHello()
dlg.show()
sys.exit(app.exec_())
這樣就OK了。
7. 最後的收尾工作。
按F2運行指令碼,發現點擊“你好”按鈕後lblHello label中的文字是亂碼。
解決辦法很簡單,把代碼中的("你好,PyQt4")改為(u"你好,PyQt4")就行了。PyQt4對中文的支援是很好的。代碼統一使用utf8編碼,能省去很多麻煩。