PyQt5 系統(tǒng)化學(xué)習(xí): 創(chuàng)建簡(jiǎn)單窗口

3 基本功能

參考自:pyqt5/firstprograms

在 PyQt5 教程的這一部分中誉己,我們學(xué)習(xí)一些基本功能芽死。這些示例顯示了一個(gè)提示窗口(tooltip)和一個(gè)圖標(biāo),關(guān)閉了一個(gè)窗口偷溺,顯示了一個(gè)消息框跨释,并在桌面上將窗口居中。

3.1 創(chuàng)建一個(gè)簡(jiǎn)單的窗口

每個(gè) PyQt5 應(yīng)用都必須創(chuàng)建一個(gè)應(yīng)用對(duì)象 QApplication吹截。

app = QApplication(sys.argv)

其中 sys.argv 是一組命令行參數(shù)的列表瘦陈。Python 可以在 shell 里運(yùn)行凝危,這個(gè)參數(shù)提供對(duì)腳本控制的功能。這是一種通過參數(shù)來選擇啟動(dòng)腳本的方式晨逝。如果不需要傳入?yún)?shù)蛾默,可以使用 [] 代替 sys.argv

QApplication 管理 GUI 程序的控制流和主要設(shè)置捉貌。它包含由窗口系統(tǒng)和其他來源處理過和發(fā)送過的主事件循環(huán)支鸡。它也處理應(yīng)用程序的初始化和收尾工作,并提供對(duì)話管理趁窃。它還可以對(duì)系統(tǒng)和應(yīng)用的大部分設(shè)置項(xiàng)進(jìn)行設(shè)置牧挣。對(duì)于用 Qt 寫的任何一個(gè) GUI 應(yīng)用,不管這個(gè)應(yīng)用有沒有窗口或多少個(gè)窗口醒陆,有且只有一個(gè) QApplication 對(duì)象瀑构。而對(duì)于用 Qt 寫的非 GUI 應(yīng)用,則有且只有一個(gè) QCoreApplication 對(duì)象刨摩,并且這個(gè)應(yīng)用不依賴 QtGui 庫寺晌。

為了讓 GUI 啟動(dòng),需要使用 app.exec_() 啟動(dòng)事件循環(huán)(啟動(dòng)應(yīng)用澡刹,直至用戶關(guān)閉它)呻征。app.exec_() 的作用是運(yùn)行主循環(huán),必須調(diào)用此函數(shù)才能開始事件處理像屋,調(diào)用該方法進(jìn)入程序的主循環(huán)直到調(diào)用 exit() 結(jié)束怕犁。主事件循環(huán)從窗口系統(tǒng)接收事件边篮,并將其分派給應(yīng)用程序小部件己莺。如果沒有該方法,那么在運(yùn)行的時(shí)候還沒有進(jìn)入程序的主循環(huán)就直接結(jié)束了戈轿,所以運(yùn)行的時(shí)候窗口會(huì)閃退凌受。

app.exec_() 在退出時(shí)會(huì)返回狀態(tài)代碼(如果程序運(yùn)行成功,則返回 0思杯,否則為非 0)胜蛉。也可以用 sys.exit(app.exec_())sys.exit(n) 的作用是退出應(yīng)用程序并返回 n 到父進(jìn)程)。我們進(jìn)入了應(yīng)用的主循環(huán)中色乾,事件處理器這個(gè)時(shí)候開始工作誊册。主循環(huán)從窗口上接收事件,并把事件傳入到派發(fā)到應(yīng)用控件里暖璧。當(dāng)調(diào)用 exit() 方法或直接銷毀主控件時(shí)案怯,主循環(huán)就會(huì)結(jié)束。sys.exit() 方法能確保主循環(huán)安全退出澎办。外部環(huán)境能通知主控件怎么結(jié)束嘲碱。

這樣便可以寫出最小化的 PyQt5 代碼:

import sys
from PyQt5.QtWidgets import QApplication

# You need one (and only one) QApplication instance per application.
# Pass in sys.argv to allow command line arguments for your app.
# If you know you won't use command line arguments QApplication([]) is fine.
app = QApplication(sys.argv)

# Start the event loop.
sys.exit(app.exec_())

# Your application won't reach here until you exit and the event
# loop has stopped.

此時(shí)運(yùn)行金砍,什么也沒有出現(xiàn)?這是因?yàn)槁缶猓覀儧]有創(chuàng)建一個(gè)可視化的窗口恕稠。

QWidget 控件(所有的窗口和控件都直接或者間接繼承自 QWidget)是一個(gè)用戶界面的基礎(chǔ)控件,它提供了基本的應(yīng)用構(gòu)造器扶欣。默認(rèn)情況下鹅巍,構(gòu)造器是沒有父級(jí)的,沒有父級(jí)的構(gòu)造器被稱為窗口(window)料祠。

這樣昆著,我們可以創(chuàng)建一個(gè)簡(jiǎn)單的窗口:

import sys
from PyQt5.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)
window = QWidget()
window.show() # IMPORTANT!!!!! Windows are hidden by default.
# Start the event loop.
app.exec_()

展示如下:

圖1 一個(gè)簡(jiǎn)單的窗口

PyQt5 創(chuàng)建的窗口默認(rèn)是隱藏的,需要調(diào)用 show() 顯示术陶。

QMainWindow凑懂、QWidgetQDialog 三個(gè)類都是用來創(chuàng)建窗口的,可以直接使用也可以繼承后來使用梧宫。QMainWindow 窗口可以包含菜單欄接谨、工具欄、狀態(tài)欄和標(biāo)題欄等塘匣,是最常見的窗口形式脓豪,是 GUI 程序的主窗口。QDialog 是對(duì)話框的基類忌卤,對(duì)話框主要用來執(zhí)行短期任務(wù)和與用戶進(jìn)行互動(dòng)任務(wù)扫夜,有模態(tài)和非模態(tài)兩種形式。QWidget 可以用作嵌入其他窗口驰徊。

本節(jié)僅僅介紹 QMainWindow笤闯、QWidget

3.2 自定義窗口

窗口是整個(gè)程序的整體界面棍厂,有邊框颗味、標(biāo)題欄、菜單欄牺弹、工具欄浦马、關(guān)閉按鈕、最小化按鈕张漂、最大化按鈕等晶默。控件是指按鈕、復(fù)選框航攒、文本框磺陡、表格、進(jìn)度條等這些組成 GUI 的基本元素。一個(gè)程序可以有多個(gè)窗口仅政,一個(gè)窗口可以有多個(gè)控件垢油。

3.2.1 窗口坐標(biāo)系統(tǒng)

PyQt5 使用統(tǒng)一的坐標(biāo)系統(tǒng)來定義窗口控件的位置和大小。以屏幕(或窗口)的左上角為坐標(biāo)原點(diǎn) (0,0)圆丹,從左到右為 x 軸的正方向滩愁,從上到下為 y 軸的正方向。一般稱窗口的原點(diǎn)與坐標(biāo)軸圍成的區(qū)域?yàn)榭蛻魠^(qū)(Client Area)辫封。

QWidget 的成員函數(shù)可分為三類:

  1. QWidget 直接提供的成員函數(shù):x()硝枉、y() 獲得窗口左上角坐標(biāo),width()倦微、height() 獲得客戶區(qū)的寬度和高度妻味。
  2. QWidgetgeometry() 提供的成員函數(shù):x()y() 獲得客戶區(qū)左上角的坐標(biāo)欣福,width()责球、height() 獲得客戶區(qū)的寬度和高度。
  3. QWidgetframeGeometry() 提供的成員函數(shù):x()拓劝、y() 獲得窗口左上角雏逾,width()height() 獲得客戶區(qū)郑临、標(biāo)題欄和邊框的整個(gè)窗口的的寬度和高度栖博。

Qt 提供 Window and Dialog Widgets 詳細(xì)說明了坐標(biāo)系統(tǒng),下圖是其截圖:

圖2 Window and Dialog Widgets

3.2.2 常用的幾何結(jié)構(gòu)

QWidget 包含兩種常見結(jié)構(gòu):不包含邊框的結(jié)構(gòu)與包含邊框的結(jié)構(gòu)厢洞。

一般情況下仇让,不包含邊框的部分是客戶區(qū),即用戶操作的界面躺翻,可以添加子控件丧叽。在 Qt 中使用 QRect 類保存了它的位置和大小。您可以對(duì)其進(jìn)行修改:

  1. 改變客戶區(qū)的大谢裰Α:QWidget.resize(width, height)蠢正『П剩可以通過鼠標(biāo)的來改變尺寸省店。
  2. 獲得客戶區(qū)的大小,寬度笨触、高度分別使用:QWidget.size()懦傍、QWidget.width()QWidget.height()芦劣。
  3. 設(shè)定不可使用鼠標(biāo)修改的寬度或者高度:QWidget.setFixedWidth(int width)粗俱、QWidget.setFixedHeight(int height)
  4. 同時(shí)修改客戶區(qū)的大小和位置虚吟,可以使用 QWidget.setGeometry(int x, int y, int width, int height)寸认。

包含邊框的結(jié)構(gòu)是窗口在屏幕上顯示的整個(gè)區(qū)域签财。它包含如下函數(shù):

  1. 獲得窗口的大小和位置:QWidget.frameGeometry()
  2. 設(shè)置窗口的位置:QWidget.move(int x, int y)偏塞。
  3. 獲得窗口左上角坐標(biāo):QWidget.pos()

下面是一個(gè)簡(jiǎn)單的例子:

from PyQt5.QtWidgets import QApplication, QWidget


if __name__ == '__main__':
    app = QApplication([])
    w = QWidget()
    #不同操作系統(tǒng)可能對(duì)窗口最小寬度有規(guī)定唱蒸,若設(shè)置寬度小于規(guī)定值,則會(huì)以規(guī)定值進(jìn)行顯示
    w.resize(250, 150)
    # 以 QWidget 左上角為(0, 0)點(diǎn)
    w.move(300, 300)
    w.setWindowTitle('PyQt5 坐標(biāo)系統(tǒng)例子') # 修改窗口的標(biāo)題
    w.show()
    print('控件的左上角坐標(biāo)灸叼,寬度,高度,以及尺寸分別為', (w.x(), w.y()), w.width(), w.height(), w.size())
    print('客戶區(qū)的左上角坐標(biāo)军掂,寬度右蹦,高度,以及尺寸分別為', (w.geometry().x(), w.geometry().y()), 
          w.geometry().width(), w.geometry().height(), w.geometry().size())
    print('窗口的左上角坐標(biāo)捉腥,寬度氓拼,高度分別為', w.pos(), w.frameGeometry().width(), 
          w.frameGeometry().height())

    app.exec_()

展示效果如下:

圖2 簡(jiǎn)單的窗口的常用屬性

其中 QWidget.setWindowTitle 用于修改窗口的標(biāo)題。

3.2.3 設(shè)置窗口的圖標(biāo)

窗口圖標(biāo)通常是顯示在窗口的左上角抵碟,標(biāo)題欄的最左邊披诗。QWidget.setWindowIcon(QIcon('cartoon1.ico') 提供了設(shè)置圖標(biāo)的方法。在某些環(huán)境下立磁,圖標(biāo)顯示不出來呈队。如果你遇到了這個(gè)問題,看我在Stackoverfolw的回答

import sys
from PyQt5.QtGui import QIcon  
from PyQt5.QtWidgets  import QWidget, QApplication


class Icon(QWidget):  
    def __init__(self,  parent = None):  
        super(Icon,self).__init__(parent)    
        self.initUI()
      
    def initUI(self):
        self.setGeometry(500, 500, 450, 150)  
        self.setWindowTitle('演示程序圖標(biāo)例子')  
        self.setWindowIcon(QIcon('7092.gif'))  
              
if __name__ == '__main__':   
    app = QApplication(sys.argv)
    icon = Icon()  
    icon.show()
    sys.exit(app.exec_())
圖3 設(shè)置窗口圖標(biāo)

3.3 顯示氣泡提示信息

import sys
from PyQt5.QtWidgets import QWidget, QToolTip, QApplication
from PyQt5.QtGui import QFont

class Winform(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        QToolTip.setFont(QFont('SansSerif', 10))
        self.setToolTip('這是一個(gè)<b>氣泡提示</b>')
        self.setGeometry(200, 300, 400, 400)
        self.setWindowTitle('氣泡提示')           
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Winform()
    win.show()
    sys.exit(app.exec_())

效果:

圖4 氣泡提示

3.4 創(chuàng)建主窗口類

QWidget 可以作為嵌套型的窗口存在唱歧,結(jié)構(gòu)簡(jiǎn)單宪摧,而 QMainWindow 是一個(gè)程序框架,有自己的布局颅崩,可以在布局中添加控件几于,如將工具欄添加到布局管理器中。它常常作為 GUI 的主窗口沿后。

主窗口在 GUI 程序是唯一的沿彭,是所有窗口中的最頂層窗口,其他窗口都是它的直接或間接子窗口尖滚。PyQt5 中喉刘,主窗口中會(huì)有一個(gè)控件(QWidget)占位符來占著中心窗口,可以使用 setCentralWidget() 來設(shè)置中心窗口漆弄。QMainWindow 繼承自 QWidget 類睦裳,擁有 QWidget 所有的派生方法和屬性。QMainWindow 類中比較重要的方法撼唾,如下表:

方法 描述
addToolBar() 添加工具欄
centralWidget() 返回窗口中心的一個(gè)控件廉邑,未設(shè)置時(shí)返回 NULL
menuBar() 返回主窗口的菜單欄
setCentralWidget() 設(shè)置窗口中心的控件
setStatusBar() 設(shè)置狀態(tài)欄
statusBar() 獲得狀態(tài)欄對(duì)象后,電泳狀態(tài)欄對(duì)象的 showMessage(message, int timeout=0) 方法,顯示狀態(tài)欄信息蛛蒙。其中第一個(gè)參數(shù)是要顯示的狀態(tài)欄信息糙箍;第二個(gè)參數(shù)是信息要停留的時(shí)間,單位是毫秒牵祟,默認(rèn)是 0倍靡,表示一直顯示狀態(tài)欄信息

QMainWindow 不能設(shè)置布局(使用 setLayout() 方法),因?yàn)樗凶约旱牟季帧?/p>

3.4.1 創(chuàng)建狀態(tài)欄

使用腳本創(chuàng)建簡(jiǎn)單的主窗口课舍,代碼如下:

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication
class MainWidget(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # 設(shè)置主窗體標(biāo)簽
        self.setWindowTitle("QMainWindow 例子")         
        self.resize(400, 200) 
        self.status = self.statusBar() 
        # 5 秒后狀態(tài)欄消失
        self.status.showMessage("這是狀態(tài)欄提示", 5000)

if __name__ == "__main__": 
    app = QApplication(sys.argv)
    main = MainWidget()
    main.show()
    sys.exit(app.exec_())

3.4.2 菜單欄

菜單欄是一組命令的集合:

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 創(chuàng)建一個(gè)圖標(biāo)塌西、一個(gè) exit 的標(biāo)簽和一個(gè)快捷鍵組合,都執(zhí)行了一個(gè)動(dòng)作
        exitAct = QAction(QIcon('7092.gif'), '&Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        # 創(chuàng)建了一個(gè)狀態(tài)欄筝尾,當(dāng)鼠標(biāo)懸停在菜單欄的時(shí)候捡需,能顯示當(dāng)前狀態(tài)
        exitAct.setStatusTip('Exit application')
        # 當(dāng)執(zhí)行這個(gè)指定的動(dòng)作時(shí),就觸發(fā)了一個(gè)事件筹淫。
        ## 這個(gè)事件跟 QApplication 的 quit() 行為相關(guān)聯(lián)站辉,所以這個(gè)動(dòng)作就能終止這個(gè)應(yīng)用。
        exitAct.triggered.connect(qApp.quit)
       
        self.statusBar()
        # 創(chuàng)建菜單欄
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAct)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Simple menu')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

我們創(chuàng)建了只有一個(gè)命令的菜單欄损姜,這個(gè)命令就是終止應(yīng)用饰剥。同時(shí)也創(chuàng)建了一個(gè)狀態(tài)欄。而且還能使用快捷鍵 Ctrl+Q 退出應(yīng)用摧阅。QAction 是菜單欄汰蓉、工具欄或者快捷鍵的動(dòng)作的組合。

3.4.3 子菜單

子菜單是嵌套在菜單里面的二級(jí)或者三級(jí)等的菜單棒卷。


import sys
from PyQt5.QtWidgets import QMainWindow, QAction, QMenu, QApplication


class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('File')
        # 使用 QMenu 創(chuàng)建一個(gè)新菜單
        impMenu = QMenu('Import', self)
        impAct = QAction('Import mail', self)
        impMenu.addAction(impAct)
        newAct = QAction('New', self)
        fileMenu.addAction(newAct)
        fileMenu.addMenu(impMenu)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Submenu')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

顯示:

圖5 創(chuàng)建菜單欄

3.4.4 勾選菜單

下面是一個(gè)能勾選菜單的例子顾孽。

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, QApplication

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.statusbar = self.statusBar()
        self.statusbar.showMessage('Ready')
        menubar = self.menuBar()
        viewMenu = menubar.addMenu('View')
        viewStatAct = QAction('View statusbar', self, checkable=True)
        viewStatAct.setStatusTip('View statusbar')
        viewStatAct.setChecked(True)  # 默認(rèn)設(shè)置為選中狀態(tài)
        viewStatAct.triggered.connect(self.toggleMenu)
        viewMenu.addAction(viewStatAct)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Check menu')
        self.show()

    def toggleMenu(self, state):
        if state:
            self.statusbar.show()
        else:
            self.statusbar.hide()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

本例創(chuàng)建了一個(gè)行為菜單。這個(gè)行為/動(dòng)作能切換狀態(tài)欄顯示或者隱藏比规。用 checkable 選項(xiàng)創(chuàng)建一個(gè)能選中的菜單若厚。

3.4.5 context 菜單

context menu 也叫彈出框,是在某些場(chǎng)合下顯示的一組命令蜒什。例如测秸,Opera 瀏覽器里,網(wǎng)頁上的右鍵菜單里會(huì)有刷新灾常,返回或者查看頁面源代碼霎冯。如果在工具欄上右鍵,會(huì)得到一個(gè)不同的用來管理工具欄的菜單岗憋。

為了使 context menu 生效肃晚,需要實(shí)現(xiàn) contextMenuEvent() 方法。

import sys
from PyQt5.QtWidgets import QMainWindow, qApp, QMenu, QApplication

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Context menu')
        self.show()

    def contextMenuEvent(self, event):
        cmenu = QMenu(self)
        newAct = cmenu.addAction("New")
        openAct = cmenu.addAction("Open")
        quitAct = cmenu.addAction("Quit")
        # 使用 exec_() 方法顯示菜單仔戈。從鼠標(biāo)右鍵事件對(duì)象中獲得當(dāng)前坐標(biāo)。
        # mapToGlobal() 方法把當(dāng)前組件的相對(duì)坐標(biāo)轉(zhuǎn)換為窗口(window)的絕對(duì)坐標(biāo)。
        action = cmenu.exec_(self.mapToGlobal(event.pos()))
        if action == quitAct:
            qApp.quit()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
圖6 右鍵菜單

3.4.6 工具欄

菜單欄包含了所有的命令监徘,工具欄就是常用的命令的集合晋修。

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QFileInfo

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        #root = QFileInfo(__file__).absolutePath() # 避免圖標(biāo)不顯示,而使用絕對(duì)路徑
        exitAct = QAction(QIcon('paper.png'), 'Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.triggered.connect(qApp.quit)
        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(exitAct)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Toolbar')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
圖7 工具欄

3.5 主窗口居中顯示

QMainWindow 利用 QDesktopWidget 類實(shí)現(xiàn)窗口居中顯示凰盔,如下示例:

from PyQt5.QtWidgets import QDesktopWidget, QApplication, QMainWindow
import sys

class Winform(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('主窗口放在屏幕中間例子')
        self.resize(300, 200)
        self.center()

    def center(self):
        # 獲取屏幕信息
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        x = int((screen.width() - size.width()) / 2)
        y = int((screen.height() - size.height()) / 2)
        self.move(x, y)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Winform()
    win.show()
    sys.exit(app.exec_())

也可以直接使用 QDesktopWidget().availableGeometry().center() 設(shè)置窗口居中:

import sys
from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication

class CenterWin(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):               
        self.resize(250, 150)
        self.center()
        self.setWindowTitle('Center')    
        self.show()

    def center(self):
        qr = self.frameGeometry() # 獲得主窗口所在的框架
        # 獲取顯示器的分辨率墓卦,然后得到屏幕中間點(diǎn)的位置
        cp = QDesktopWidget().availableGeometry().center()
        # 然后把主窗口框架的中心點(diǎn)放置到屏幕的中心位置
        qr.moveCenter(cp)
        # 然后通過 move 函數(shù)把主窗口的左上角移動(dòng)到其框架的左上角,這樣就把窗口居中了
        self.move(qr.topLeft())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = CenterWin()
    sys.exit(app.exec_())

3.6 關(guān)閉窗口

關(guān)閉一個(gè)窗口最直觀的方式就是點(diǎn)擊標(biāo)題欄的那個(gè)叉户敬,接下來落剪,我們展示的是如何用程序關(guān)閉一個(gè)窗口。這里我們將接觸到一點(diǎn) signalsslots 的知識(shí)尿庐。本例使用的是 QPushButton 組件類忠怖。

QPushButton(string text, QWidget parent = None)

text 參數(shù)是想要顯示的按鈕名稱,parent 參數(shù)是放在按鈕上的組件抄瑟,在我們的例子里凡泣,這個(gè)參數(shù)是 QWidget。應(yīng)用中的組件都是一層一層的皮假,在這個(gè)層里鞋拟,大部分的組件都有自己的父級(jí),沒有父級(jí)的組件惹资,是頂級(jí)的窗口(即主窗口)贺纲。

下面創(chuàng)建一個(gè)點(diǎn)擊之后就退出窗口的按鈕:

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        qbtn = QPushButton('Quit', self)
        qbtn.clicked.connect(QApplication.instance().quit)
        qbtn.resize(qbtn.sizeHint())
        qbtn.move(50, 50)
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Quit button')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

事件傳遞系統(tǒng)在 PyQt5 內(nèi)建的 signal 和 slot 機(jī)制里面。點(diǎn)擊按鈕之后褪测,信號(hào)會(huì)被捕捉并給出既定的反應(yīng)哮笆。QCoreApplication 包含了事件的主循環(huán),它能添加和刪除所有的事件汰扭,instance() 創(chuàng)建了一個(gè)它的實(shí)例稠肘。QCoreApplication 是在 QApplication 里創(chuàng)建的。點(diǎn)擊事件和能終止進(jìn)程并退出應(yīng)用的 quit 函數(shù)綁定在了一起萝毛。在發(fā)送者和接受者之間建立了通訊项阴,發(fā)送者就是按鈕,接受者就是應(yīng)用對(duì)象笆包。

3.7 消息盒子

默認(rèn)情況下环揽,我們點(diǎn)擊標(biāo)題欄的 X 按鈕,QWidget 就會(huì)關(guān)閉庵佣。但是有時(shí)候歉胶,我們修改默認(rèn)行為。比如巴粪,如果我們打開的是一個(gè)文本編輯器通今,并且做了一些修改粥谬,我們就會(huì)想在關(guān)閉按鈕的時(shí)候讓用戶進(jìn)一步確認(rèn)操作。

import sys
from PyQt5.QtWidgets import QWidget, QMessageBox, QApplication


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Message box')
        self.show()

    def closeEvent(self, event):
        # 第一個(gè)字符串顯示在消息框的標(biāo)題欄辫塌,
        # 第二個(gè)字符串顯示在對(duì)話框漏策,第三個(gè)參數(shù)是消息框的倆按鈕,
        # 最后一個(gè)參數(shù)是默認(rèn)按鈕臼氨,這個(gè)按鈕是默認(rèn)選中的掺喻。
        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)
        # 這里判斷返回值,如果點(diǎn)擊的是Yes按鈕储矩,我們就關(guān)閉組件和應(yīng)用感耙,否者就忽略關(guān)閉事件。
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

如果關(guān)閉 QWidget持隧,就會(huì)產(chǎn)生一個(gè) QCloseEvent即硼,并且把它傳入到 closeEvent 函數(shù)的 event 參數(shù)中。改變控件的默認(rèn)行為舆蝴,就是替換掉默認(rèn)的事件處理谦絮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市洁仗,隨后出現(xiàn)的幾起案子层皱,更是在濱河造成了極大的恐慌,老刑警劉巖赠潦,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叫胖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡她奥,警方通過查閱死者的電腦和手機(jī)瓮增,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哩俭,“玉大人绷跑,你說我怎么就攤上這事》沧剩” “怎么了砸捏?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長隙赁。 經(jīng)常有香客問我垦藏,道長,這世上最難降的妖魔是什么伞访? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任掂骏,我火速辦了婚禮,結(jié)果婚禮上厚掷,老公的妹妹穿的比我還像新娘弟灼。我一直安慰自己级解,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布袜爪。 她就那樣靜靜地躺著蠕趁,像睡著了一般薛闪。 火紅的嫁衣襯著肌膚如雪辛馆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天豁延,我揣著相機(jī)與錄音昙篙,去河邊找鬼。 笑死诱咏,一個(gè)胖子當(dāng)著我的面吹牛苔可,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播袋狞,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼焚辅,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了苟鸯?” 一聲冷哼從身側(cè)響起同蜻,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎早处,沒想到半個(gè)月后湾蔓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砌梆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年默责,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咸包。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桃序,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烂瘫,到底是詐尸還是另有隱情媒熊,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布忱反,位于F島的核電站泛释,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏温算。R本人自食惡果不足惜怜校,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望注竿。 院中可真熱鬧茄茁,春花似錦魂贬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至愈犹,卻和暖如春键科,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漩怎。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工勋颖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勋锤。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓饭玲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叁执。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茄厘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348