安裝兩個模塊
PyQt5 pip install PyQt5
PyQt-tool pip install PyQt5-tools -i https://pypi.douban.com/simple --trusted-host=pypi.douban.com
什么是pyqt?
簡而言之,qt是一個開發窗體程序的模塊,原本是是C++的庫,PyQt是Python的移植版本,所以我們安裝了pyqt之后,就可以在python上面進行窗體的開發了。python有自帶的窗體模塊Tkinter,但是不夠好用,為什么不夠好用呢?因為畫窗體什么的都要自己寫代碼...用了qt以后,我們就可以通過qt designer進行開發了,什么是qt disigner呢?
就是個啦,你可以在這里設計你的窗口,畫編輯框,畫按鈕,想畫什么畫什么,總之,不用寫代碼看天書的東西都是好東西!
什么是eric?
我們有了qt,可以直接畫窗體了,但是悲劇的是我們畫好了窗體,生成的是一個.ui文件,python不認識啊,這個時候eric的作用就體現出來了,它可以把ui文件轉換成py文件,簡直強大~~~這里就不多介紹,直接來說說窗體開發,我是怎么入手的。
擁有一個屬於自己的窗體程序
跳過那些坑,我們直接來說說如何快速擁有一個窗體程序。按照我上面提供的連接安裝好開發需要的工具,我們可以在eric的安裝目錄找到一個叫做eric.pyw的東西,啟動它,就打開了eric。可以看到如下左圖的界面,點擊project可以新建一個工程,這里不詳述,還是推薦一個鏈接:使用eric創建一個PyQt項目http://www.pythoner.com/89.html
按照剛剛提供的鏈接,我們創建了一個新工程,甚至在新的工程中添加了窗口,還給窗口畫了很多組件,這里來介紹幾個我用到的,下圖中展示了我畫好的兩個界面:登錄和主窗口:
我這個簡易版的ftp只用到了這5個組件。。。天,這樣說會不會得不了A。。。嘻嘻,不管怎么樣,反正就用到了這幾個:lable是標簽,lineEdit是編輯框,pushButton是按鈕,listWidget是列表框,TextBrowser是文本框。畫好了這些東西之后,我們關閉並保存qt文件,就會在eric中看到兩個ui文件,右鍵選擇生成文件,就生成了.py文件了,這個網上有大量資料,隨便一搜就搜到了哈~
正文
好啦,看到這里才算進入正題,現在才是我要介紹的主要內容~~~我們現在已經有了一個ui界面和python文件,但是這個時候我們運行.py文件什么也不會發生,它會報錯。。。錯誤的具體內容不太記得了,只記得是說沒有QApplication,那么QApplication是從哪里來的呢?看下面的圖:
詳細的解釋看右邊→_→:
# Form implementation generated from reading ui file 'E:\ericWorkSpace\12-21\FTPhomework\views\login.ui' # # Created by: PyQt4 UI code generator 4.11.4 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: def _fromUtf8(s): return s try: _encoding = QtGui.QApplication.UnicodeUTF8 def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig) class Ui_login(object): def setupUi(self, login): login.setObjectName(_fromUtf8("login")) login.resize(400, 300) login.setSizeGripEnabled(True) self.login_pushButton = QtGui.QPushButton(login) self.login_pushButton.setGeometry(QtCore.QRect(160, 210, 75, 23)) self.login_pushButton.setObjectName(_fromUtf8("login_pushButton")) self.register_pushButton = QtGui.QPushButton(login) self.register_pushButton.setGeometry(QtCore.QRect(250, 210, 75, 23)) self.register_pushButton.setObjectName(_fromUtf8("register_pushButton")) self.usr_lineEdit = QtGui.QLineEdit(login) self.usr_lineEdit.setGeometry(QtCore.QRect(160, 126, 161, 21)) self.usr_lineEdit.setObjectName(_fromUtf8("usr_lineEdit")) self.pwd_lineEdit = QtGui.QLineEdit(login) self.pwd_lineEdit.setGeometry(QtCore.QRect(160, 166, 161, 21)) self.pwd_lineEdit.setObjectName(_fromUtf8("pwd_lineEdit")) self.usr_label = QtGui.QLabel(login) self.usr_label.setGeometry(QtCore.QRect(91, 130, 54, 12)) self.usr_label.setObjectName(_fromUtf8("usr_label")) self.pwd_label = QtGui.QLabel(login) self.pwd_label.setGeometry(QtCore.QRect(91, 172, 54, 12)) self.pwd_label.setObjectName(_fromUtf8("pwd_label")) self.ip_label = QtGui.QLabel(login) self.ip_label.setGeometry(QtCore.QRect(80, 44, 91, 20)) self.ip_label.setObjectName(_fromUtf8("ip_label")) self.ip_lineEdit = QtGui.QLineEdit(login) self.ip_lineEdit.setGeometry(QtCore.QRect(160, 44, 161, 21)) self.ip_lineEdit.setObjectName(_fromUtf8("ip_lineEdit")) self.port_lineEdit = QtGui.QLineEdit(login) self.port_lineEdit.setGeometry(QtCore.QRect(160, 86, 161, 21)) self.port_lineEdit.setObjectName(_fromUtf8("port_lineEdit")) self.port_label = QtGui.QLabel(login) self.port_label.setGeometry(QtCore.QRect(80, 86, 91, 20)) self.port_label.setObjectName(_fromUtf8("port_label")) self.retranslateUi(login) QtCore.QMetaObject.connectSlotsByName(login) def retranslateUi(self, login): login.setWindowTitle(_translate("login", "Dialog", None)) self.login_pushButton.setText(_translate("login", "登錄", None)) self.register_pushButton.setText(_translate("login", "注冊", None)) self.usr_label.setText(_translate("login", "用戶名", None)) self.pwd_label.setText(_translate("login", "密 碼", None)) self.ip_label.setText(_translate("login", "服務器地址", None)) self.port_label.setText(_translate("login", "服務器端口", None)) #這里開始是我們自己寫的 import sys from PyQt4 import QtGui def LoginController(argv): app = QtGui.QApplication(argv) dlg = Ui_login() dlg.show() sys.exit(app.exec_()) if __name__ == 'main': LoginController(sys.argv) login ui Code
為控件綁定事件
執行上面的代碼我們就可以有一個自己的登錄窗體了,這只是一個花瓶擺件,中看不中用,我們點一點那些按鈕和編輯框,沒有一個搭理我們。。。腫么辦腫么辦,這里我也糾結了好久,最后發現qt和eric的強大不僅僅是給我們提供了畫窗體的功能,還提供了信號和槽的功能(不理解的就背下來,這里其實我也不太懂。。。),先來看怎么做。。。網上說了一大堆什么在qt里添加信號和槽,親測無效。。。所以這里還是按照我的方法來:
首先右鍵UI文件(當然,你剛剛已經使用Compile form生成過一個文件了),這里再使用Generate...這個生成一個對話文件,我們姑且這么翻譯,這個時候會彈出右邊的對話框,我們填好上面的那些信息,勾選你要給哪些組件添加事件,點擊ok,就又生成了一個新文件。
我們可以看到現在目錄變成了上面的模樣,不要問我他們為什么不在一個文件夾下,因為你一開始選擇的路徑就是不同的。現在我來說說他們的關系,ui文件和py文件沒什么關系。。。但是我們第一次生成的窗口的描述文件和第二次生成的對話文件之間是有聯系的!有聯系的!聯系的!重要的事情說三遍。。。實際操作中我們可以看到,第二次生成的文件中事件方法所在的類是繼承了窗口描述文件中的類的。。。所以我們在這一次的實例化中,只需要初始化派生類的對象就可以了。。。這里不理解的去看類繼承的知識。。。
所以這個時候我們想要讓這個login窗口顯示只需要在派生類下執行那些代碼就好了,很容易理解吧?代碼也貼上
""" Module implementing Login. """ import sys from PyQt4.QtCore import pyqtSignature,QString from PyQt4.QtGui import QDialog from views.Ui_login import Ui_login from PyQt4 import QtGui import ClientClass import mainWindowEvent class Login(QDialog, Ui_login): global TEST """ Class documentation goes here. """ def __init__(self,parent=None): QDialog.__init__(self, parent) self.setupUi(self) @pyqtSignature("") def on_login_pushButton_clicked(self): pass @pyqtSignature("") def on_register_pushButton_clicked(self): """ Slot documentation goes here. """ # TODO: not implemented yet raise NotImplementedError import sys from PyQt4 import QtGui def LoginController2(argv): app = QtGui.QApplication(argv) dlg = Login() dlg.show() sys.exit(app.exec_()) if __name__ == 'main': LoginController(sys.argv) login ui dailog Code
現在這兩個事件就和我們窗口中的按鈕們綁定在一起了,隨便你在里面寫什么,只要一點按鈕,就會觸發這個事件,執行這個方法里面的內容。。。
窗口的切換
好了,假裝我們已經實現了登錄的功能,在登錄方法中進行了一系列操作,那么問題來了, 當我們登錄成功之后,如何切換窗口呢?加入在本窗口中實例化ftp窗口的話,那么登錄窗口關閉之后,ftp的窗口也會跟着關閉了,是不是很鬧心,在這里糾結一天。。。不賣關子了,直接上代碼:
就是這樣,accept是關鍵。。。到現在為止,我們已經實現了窗口的切換。我的心在滴血,為什么沒有人寫教程。。。
窗口切換中的數據交換問題
剛剛我們已經實現了數據的交換,開篇我就說過,我要實現的是一個ftp程序,那么在輸入了各種ip、端口、用戶名和密碼登錄之后,這個連接已經建立起來了,在這個窗體中建立起來的對象要怎么傳遞給ftp這個新窗體呢?我嘗試了很多種方法,比如將這個外部類實例化的對象變成這個類的一個字段,等等,均未果,但是在這里不得不說,全局變量很好用,很好用,很好用,但是直接定義一個變量是不好用的,因為直接定義一個變量,那么在它再次賦值的時候。
直接上代碼。
就是這樣!定義一個全局變量,分分鍾解決問題。