小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

基于 Python 與Qt 的快速GUI 編程

 River_LaLaLa 2016-08-21


來(lái)源:codecodes 

鏈接:http://www.jianshu.com/p/f087984f6263


An Expression Evaluator in 30 Lines(30行代碼的表達(dá)式計(jì)算器)


這個(gè)應(yīng)用程序是采用30行代碼(不包括空白行與注釋代碼)編寫的一個(gè)完整的“對(duì)話框樣式”應(yīng)用程序。“對(duì)話框樣式”表示這個(gè)應(yīng)用程序沒(méi)有菜單欄,通常也沒(méi)有工具欄或者狀態(tài)欄,常見(jiàn)的情況是有一些按鈕控件,但沒(méi)有中心窗口控件(central widget)。相應(yīng)地,“主窗口樣式”應(yīng)用程序通常有菜單欄、工具欄、狀態(tài)欄,在一些情況下也有按鈕;并且它們擁有中心窗口控件(能容納其他控件)。我們將在第6章學(xué)習(xí)“主窗口樣式”應(yīng)用程序。



這個(gè)應(yīng)用程序使用了兩個(gè)控件:QTextBrowser控件,是一個(gè)具有只讀屬性的多行文本框,它可以顯示純文本與HTML文本;QLineEdit控件,是一個(gè)只能顯示純文本的單行文本框。PyQt中控件使用的所有文本都采用Unicode編碼,如果有必要,它們可以被轉(zhuǎn)換成其他編碼。

計(jì)算器應(yīng)用程序(如圖4.3所示)的調(diào)用方式和其他常規(guī)的GUI應(yīng)用程序一樣,通過(guò)鼠標(biāo)點(diǎn)擊(或者雙擊,取決于操作系統(tǒng)平臺(tái)與設(shè)置)它的程序圖標(biāo)。(當(dāng)然它也可以通過(guò)控制臺(tái)啟動(dòng)運(yùn)行)。一旦應(yīng)用程序運(yùn)行,用戶可以在行編輯框中簡(jiǎn)單地輸入數(shù)學(xué)表達(dá)式,當(dāng)用戶按下回車(Enter)鍵,表達(dá)式與它的結(jié)果會(huì)以追加模式顯示在QTextBrowser控件中。任何由于無(wú)效的表達(dá)式或者無(wú)效的數(shù)學(xué)運(yùn)算(例如被零除)引起的異常將會(huì)轉(zhuǎn)變成錯(cuò)誤消息,并追加在QTextBrowser中顯示。


如同上一節(jié)一樣,我們將分塊去瀏覽整個(gè)代碼。這個(gè)例子所遵循的模式是我們?cè)谝院笏械腉UI應(yīng)用程序開(kāi)發(fā)中使用的模式:“窗體”采用一個(gè)類來(lái)表示,響應(yīng)用戶交互的行為由“方法”來(lái)處理,“主程序”部分盡可能的保持簡(jiǎn)潔。


from __future__ import division

import sys

from math import *

from PyQt4.QtCore import *

from PyQt4.QtGui import *


因?yàn)槲覀冊(cè)谧鰯?shù)學(xué)計(jì)算,并不想遇到任何的諸如除法截?cái)嗟纫馔馇闆r,因此我們采用浮點(diǎn)數(shù)除法。通常我們導(dǎo)入非PyQt模塊時(shí)采用import moduleName語(yǔ)句,但因?yàn)槲覀兿胧褂盟械膍ath包里的函數(shù)與常量,因此我們簡(jiǎn)單地把math包里所有的內(nèi)容都導(dǎo)入到當(dāng)前命名空間。與上一節(jié)例子中一樣,我們導(dǎo)入sys模塊來(lái)獲取sys.argv參數(shù)列表,同時(shí)我們從QtCore與QtGui模塊中導(dǎo)入所有內(nèi)容。


class Form(QDialog):

    def __init__(self,parent=None):

        super(Form,self).__init__(parent)

        self.browser = QTextBrowser()

        self.lineedit = QLineEdit('Type an express and press Enter')

        self.lineedit.selectAll()

        layout = QVBoxLayout()

        layout.addWidget(self.browser)

        layout.addWidget(self.lineedit)

        self.setLayout(layout)

        self.lineedit.setFocus()

        self.connect(self.lineedit,SIGNAL('returnPressed()'),self.updateUi)

        self.setWindowTitle('Calculate')


正如我們所見(jiàn),任何一個(gè)控件都可以作為頂級(jí)窗體。但大多數(shù)情況下,我們通過(guò)子類QDialog或者QMainWindow創(chuàng)建頂級(jí)窗體,有時(shí)候我們也采用QWidget。QDialog和QMainWindow,以及所有的PyQt控件,都是從QWidget派生出來(lái)的,它們都屬于Python中的新式類。通過(guò)繼承QDialog類我們可以得到一個(gè)空白的窗口,即一個(gè)灰色的矩形窗口,它只具有一些簡(jiǎn)單的行為或者方法。例如,如果用戶點(diǎn)擊關(guān)閉的X按鈕,對(duì)話框會(huì)關(guān)閉。默認(rèn)情況下,當(dāng)控件被關(guān)閉時(shí),它僅僅只是隱藏了,當(dāng)然,我們也可以改變這一行為,這將在以后的章節(jié)中介紹。


我們傳遞給Form類的初始化方法__init__()默認(rèn)的參數(shù)parent為None值,并采用super()方法進(jìn)行初始化。如果一個(gè)窗體控件沒(méi)有父類,那么這個(gè)控件就是一個(gè)頂級(jí)窗體,在這個(gè)例子中正是我們希望的。接下來(lái)我們創(chuàng)建兩個(gè)控件,并且保存它們的引用以便以后我們?cè)赺_init__()外部可以訪問(wèn)它們。因?yàn)槲覀儧](méi)有傳遞父類給這兩個(gè)控件,似乎它們會(huì)成為頂級(jí)窗體——這是沒(méi)有意義的。我們將簡(jiǎn)單地介紹它們是如何在初始化過(guò)程中獲取父類的。我們給QLineEdit提供一個(gè)初始顯示文本,并選取全部文本,這樣做可以保證當(dāng)用戶開(kāi)始輸入時(shí),我們提供的初始文本被替換。


我們希望窗體控件垂直的顯示,一個(gè)在另一個(gè)上方。這可以通過(guò)創(chuàng)建一個(gè)QVBoxLayout布局并添加這兩個(gè)窗體控件實(shí)現(xiàn),然后設(shè)置好窗體的布局。如果你運(yùn)行程序并改變窗體的大小,會(huì)發(fā)現(xiàn)增加的垂直空間被分配給了QTextBrowser控件,兩個(gè)控件都會(huì)沿水平方向增長(zhǎng)。這是通過(guò)布局管理器自動(dòng)實(shí)現(xiàn)的,也可以通過(guò)設(shè)置布局進(jìn)行調(diào)整。


使用布局的一個(gè)重要的作用是PyQt自動(dòng)代理所有被展示的控件。因此,盡管我們沒(méi)有定義控件的父類為主窗體,但當(dāng)我們調(diào)用setLayout()函數(shù)時(shí),布局管理器會(huì)擁有控件的所有權(quán),同時(shí)將自己的所有權(quán)給主窗體,此外,它也會(huì)擁有它內(nèi)部的布局管理器的所有權(quán)。這表示所有被展示的控件都不是頂級(jí)窗體,它們都擁有父類,這也是我們希望看到的。所以當(dāng)主程序被釋放時(shí),它的所有的子控件和布局管理器都會(huì)以正確的順序被釋放。


窗體中的控件的布局可以有多久方式。我們可以使用resize()或者move()函數(shù)來(lái)定義它們的絕對(duì)大小和位置;也可以重新執(zhí)行resizeEvent()函數(shù)來(lái)自動(dòng)計(jì)算它們的大小和位置,或者使用PyQt的布局管理器。使用絕對(duì)大小或者位置非常的麻煩。一方面,我們需要進(jìn)行大量的人工計(jì)算,另一方面,如果我們改變了窗體的布局,我們需要重新進(jìn)行所有的計(jì)算。自動(dòng)計(jì)算控件的大小與位置是一個(gè)更好的方式,但我們同樣需要編寫大量的計(jì)算代碼。


使用布局管理器讓一切事情變得簡(jiǎn)單。布局管理器非常的智能:它們自動(dòng)地適應(yīng)調(diào)整大小事件和內(nèi)容改變。任何人如果使用過(guò)不同版本的Windows的對(duì)話框,會(huì)很感謝對(duì)話框可改變大小所帶來(lái)的好處,因?yàn)楫?dāng)用戶的內(nèi)容太大時(shí),使用小的而且不可改變大小的對(duì)話框會(huì)帶來(lái)非常多的不方便。對(duì)于國(guó)際化應(yīng)用程序需要根據(jù)語(yǔ)言調(diào)整內(nèi)容時(shí),布局管理器也可以讓事情變得簡(jiǎn)單,而不用擔(dān)心如果翻譯過(guò)后的語(yǔ)言長(zhǎng)度大于原始的語(yǔ)言時(shí)被截?cái)唷?/p>


PyQt提供三種布局管理器:垂直布局管理器,水平布局管理器以及網(wǎng)格布局管理器。布局管理器可以嵌套,這讓非常復(fù)雜的布局也變成可能。還有其他的布局方式,例如使用splitter或者tab控件。所有的這些方式都會(huì)在第9章更深入地介紹。


出于對(duì)用戶使用上的方便,我們?cè)诔绦蜻\(yùn)行的開(kāi)始將焦點(diǎn)設(shè)置為QLineEdit控件;可以通過(guò)調(diào)用setFocus()函數(shù)實(shí)現(xiàn),這必須在設(shè)置好布局管理器后調(diào)用。


函數(shù)connect()的調(diào)用我們將在以后的章節(jié)中深入地介紹。目前只要知道每一個(gè)控件(或者一些其他的QObject)通過(guò)發(fā)送一個(gè)“信號(hào)(signals)”來(lái)聲明它們的狀態(tài)改變就足夠了。這些信號(hào)(與Unix系統(tǒng)的信號(hào)沒(méi)有任何關(guān)系)通常被忽略。然而,當(dāng)我們選擇關(guān)注我們感興趣的那些信號(hào)時(shí),我們可以通過(guò)這個(gè)方式識(shí)別我們想要知道的那些QObject對(duì)象,它們發(fā)送出的信號(hào)是我們感興趣的,當(dāng)信號(hào)發(fā)出時(shí),我們希望執(zhí)行哪些函數(shù)或者方法。


在這個(gè)例子中,當(dāng)用戶在QLineEdit中按下“回車(Enter)”鍵時(shí),會(huì)觸發(fā)returnPressed()信號(hào),因?yàn)檎{(diào)用了connect()函數(shù),當(dāng)觸發(fā)信號(hào)時(shí),用調(diào)用updateUi()方法。我們將在一會(huì)看到發(fā)生了什么改變。


最后一件事是通過(guò)__init__()函數(shù)來(lái)設(shè)置窗體的標(biāo)題。


正如我們一會(huì)將看到,窗體被創(chuàng)建并且調(diào)用了show()方法。一旦事件循環(huán)開(kāi)始,窗體會(huì)顯示出來(lái)——沒(méi)有更多的事情發(fā)生。應(yīng)用程序只是簡(jiǎn)單地執(zhí)行事件循環(huán),等待用戶點(diǎn)擊鼠標(biāo)或者按下按鍵。一旦用戶開(kāi)始交互,它們交互的結(jié)果將被處理。因此如果用戶輸入一個(gè)表達(dá)式,QLineEdit控件會(huì)關(guān)注用戶輸入的內(nèi)容,一旦用戶按下“回車(Enter)“鍵,我們定義的updateUi()方法將被調(diào)用。


def updateUi(self):

        try:

            text = unicode(self.lineedit.text())

            self.browser.append('%s = %s' % (text, eval(text)))

        except:

            self.browser.append('%s is invalid!' % text)


當(dāng)調(diào)用updateUi()時(shí),首先解析QLineEdit中的文本字符,然后將其轉(zhuǎn)換為unicode對(duì)象。接下來(lái)我們利用Python自帶的eval()函數(shù)來(lái)計(jì)算字符表達(dá)式的結(jié)果。如果成功,將追加該字符表達(dá)式,等號(hào)符號(hào)和用粗體顯示的表達(dá)式結(jié)果到QTextBrowser對(duì)象中。盡管我們通常會(huì)盡快地將QStrings對(duì)象轉(zhuǎn)換為unicode對(duì)象,我們?nèi)匀豢蓚鬟fQStrings、unicode和strs對(duì)象到PyQt方法中,該方法期望的對(duì)象是QStrings對(duì)象,但PyQt會(huì)自動(dòng)完成必要的轉(zhuǎn)換。如果任何異常發(fā)生,相應(yīng)地,我們追加一個(gè)錯(cuò)誤消息。使用catch-all-except代碼塊通常并不是很好的方式,但在這個(gè)30行的程序代碼中它是合理的。


通過(guò)使用eval()函數(shù)我們可以避免所有的解析與錯(cuò)誤檢查工作,而如果使用編譯型語(yǔ)言,這部分工作需要我們自己去實(shí)現(xiàn)。


app = QApplication(sys.argv)

form = Form()

form.show()

app.exec_()


現(xiàn)在我們定義好了Form類,在calculate.pyw文件的最后,我們創(chuàng)建一個(gè)QApplication對(duì)象以及一個(gè)Form類的實(shí)例form,增加一個(gè)繪圖的計(jì)劃,并開(kāi)始事件循環(huán)。


這就是完整的應(yīng)用程序。然而一切并沒(méi)有結(jié)束。我們并沒(méi)有說(shuō)明如何去終止應(yīng)用程序,但因?yàn)槲覀兊膄orm是從QDialog對(duì)象派生出來(lái)的,它繼承了某些行為。例如,如果用戶點(diǎn)擊窗體的關(guān)閉按鈕X,或者用戶按下了Esc按鍵,窗體form會(huì)關(guān)閉。當(dāng)窗體form關(guān)閉時(shí),它是隱藏著的。PyQt會(huì)自動(dòng)檢查應(yīng)用程序是否有非隱藏的窗體,以及是否有進(jìn)一步交互的可能。如果沒(méi)有,那么會(huì)釋放掉整個(gè)窗體form并終止應(yīng)用程序。


在一些情況下,我們希望在窗體不可見(jiàn)的情況下讓應(yīng)用程序繼續(xù)運(yùn)行——例如,服務(wù)器。在這些情況下,我們可以調(diào)用QApplication.setQuitOnLastWindowClosed(False)函數(shù)來(lái)實(shí)現(xiàn)。


在Mac OS X,或者一些X Windows的窗口管理器例如twm中,本節(jié)中的例子并沒(méi)有關(guān)閉按鈕,在Mac平臺(tái)上,選擇菜單欄的Quit菜單也不起作用。在這個(gè)情況下,可以按下Esc鍵來(lái)終止應(yīng)用程序,或者使用Command+.來(lái)終止。考慮到這一點(diǎn),對(duì)于在Mac或者使用如twm作為窗口管理器的操作系統(tǒng)平臺(tái)上開(kāi)發(fā)GUI應(yīng)用程序時(shí),最好提供一個(gè)Quit按鈕。為對(duì)話框增加按鈕將在本章的最后一節(jié)介紹。


本例子的完整代碼為:


from __future__ import division

import sys

from math import *

from PyQt4.QtCore import *

from PyQt4.QtGui import *

 

class Form(QDialog):

    def __init__(self,parent=None):

        super(Form,self).__init__(parent)

        self.browser = QTextBrowser()

        self.lineedit = QLineEdit('Type an express and press Enter')

        self.lineedit.selectAll()

        layout = QVBoxLayout()

        layout.addWidget(self.browser)

        layout.addWidget(self.lineedit)

        self.setLayout(layout)

        self.lineedit.setFocus()

        self.connect(self.lineedit,SIGNAL('returnPressed()'),self.updateUi)

        self.setWindowTitle('Calculate')

 

    def updateUi(self):

        try:

            text = unicode(self.lineedit.text())

            self.browser.append('%s = %s' % (text, eval(text)))

        except:

            self.browser.append('%s is invalid!' % text)

 

app = QApplication(sys.argv)

form = Form()

form.show()

app.exec_()


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多