本文是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編碼,能省去很多麻煩。