1. 程式人生 > >【第五節】PyQt5事件和訊號

【第五節】PyQt5事件和訊號

文章目錄 [ 顯示 ]

在這一部分的pyqt5教程中,我們將探討PyQt5中的事件Event

事件 Event

所有的GUI程式都是事件驅動的。事件主要由使用者觸發,但也可能有其他觸發方式:例如網路連線、window manager或定時器。當我們呼叫QApplication的exec_()方法時會使程式進入主迴圈。主迴圈會獲取並分發事件。

在事件模型中,有三個參與者:

  • 事件源
  • 事件物件
  • 事件接收者

事件源是狀態發生變化的物件。它會生成事件。事件(物件)封裝了事件源中狀態的變動。事件接收者是要通知的物件。事件源物件將事件處理的工作交給事件接收者。

PyQt5有一個獨特的signal&slot(訊號槽)機制來處理事件。訊號槽用於物件間的通訊。signal在某一特定事件發生時被觸發,slot可以是任何callable物件

。當signal觸發時會呼叫與之相連的slot。

訊號槽 Signals & slots

這是一個使用訊號槽的PyQt5例子。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

#!/usr/bin/python3

# -*- coding: utf-8 -*-

"""

Py40 PyQt5 tutorial

In this example, we connect a signal

of a QSlider to a slot of a QLCDNumber.

author: Jan Bodnar

website: py40.com

last edited: January 2015

"""

import sys

from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,

    QVBoxLayout, QApplication)

class Example(QWidget):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        lcd = QLCDNumber(self)

        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()

        vbox.addWidget(lcd)

        vbox.addWidget(sld)

        self.setLayout(vbox)

        sld.valueChanged.connect(lcd.display)

        self.setGeometry(300, 300, 250, 150)

        self.setWindowTitle('Signal & slot')

        self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)

    ex = Example()

    sys.exit(app.exec_())

這個例子中展示了一個QtGui.QLCDNumber和QtGui.QSlider。lcd的值會隨著滑塊的拖動而改變。

1

sld.valueChanged.connect(lcd.display)

在這裡我們將滾動條的valueChanged訊號連線到lcd的display插槽。

sender是發出訊號的物件。receiver是接收訊號的物件。slot(插槽)是對訊號做出反應的方法。

sigslot

重新實現事件處理器

在PyQt5中常通過重新實現事件處理器來處理事件。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

#!/usr/bin/python3

# -*- coding: utf-8 -*-

"""

pyu40 PyQt5 tutorial

In this example, we reimplement an

event handler.

author: Jan Bodnar

website: py40.com

last edited: January 2015

"""

import sys

from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import QWidget, QApplication

class Example(QWidget):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):      

        self.setGeometry(300, 300, 250, 150)

        self.setWindowTitle('Event handler')

        self.show()

    def keyPressEvent(self, e):

        if e.key() == Qt.Key_Escape:

            self.close()

if __name__ == '__main__':

    app = QApplication(sys.argv)

    ex = Example()

    sys.exit(app.exec_())

在示例中我們重新實現了keyPressEvent()事件處理器。

1

2

3

def keyPressEvent(self, e):

    if e.key() == Qt.Key_Escape:

        self.close()

我們按下Escape鍵會使程式退出。

事件傳送者

有時需要知道訊號是由哪個控制元件發出的。對此PyQt5提供了sender()方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

# -*- coding: utf-8 -*-

"""

PyQt5 tutorial

In this example, we determine the event sender

object.

author: py40.com

last edited: 2017年3月

"""

import sys

from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication

class Example(QMainWindow):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):      

        btn1 = QPushButton("Button 1", self)

        btn1.move(30, 50)

        btn2 = QPushButton("Button 2", self)

        btn2.move(150, 50)

        btn1.clicked.connect(self.buttonClicked)            

        btn2.clicked.connect(self.buttonClicked)

        self.statusBar()

        self.setGeometry(300, 300, 290, 150)

        self.setWindowTitle('Event sender')

        self.show()

    def buttonClicked(self):

        sender = self.sender()

        self.statusBar().showMessage(sender.text() + ' was pressed')

if __name__ == '__main__':

    app = QApplication(sys.argv)

    ex = Example()

    sys.exit(app.exec_())

我們建立了兩個按鈕。在buttonClicked()方法中通過呼叫sender()方法來判斷當前按下的是哪個按鈕。

1

2

btn1.clicked.connect(self.buttonClicked)            

btn2.clicked.connect(self.buttonClicked)

兩個按鈕連線到了同一個插槽。

1

2

3

4

def buttonClicked(self):

    sender = self.sender()

    self.statusBar().showMessage(sender.text() + ' was pressed')

我們通過呼叫sender()方法來判斷訊號源, 並將其名稱顯示在窗體的狀態列中。

QQ圖片20170327093224

發出訊號

通過QObject建立的物件可以發出訊號。下面的示例演示瞭如何發出自定義訊號

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

# -*- coding: utf-8 -*-

"""

PyQt5 tutorial

In this example, we determine the event sender

object.

author: py40.com

last edited: 2017年3月

"""

import sys

from PyQt5.QtCore import pyqtSignal, QObject

from PyQt5.QtWidgets import QMainWindow, QApplication

class Communicate(QObject):

    closeApp = pyqtSignal()

class Example(QMainWindow):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):      

        self.c = Communicate()

        self.c.closeApp.connect(self.close)      

        self.setGeometry(300, 300, 290, 150)

        self.setWindowTitle('Emit signal')

        self.show()

    def mousePressEvent(self, event):

        self.c.closeApp.emit()

if __name__ == '__main__':

    app = QApplication(sys.argv)

    ex = Example()

    sys.exit(app.exec_())

我們建立了一個名為closeApp的訊號。這個訊號會在按下滑鼠時觸發,它連線著QMainWindow的close()插槽。

1

2

class Communicate(QObject):

    closeApp = pyqtSignal()

訊號closeApp是Communicate的類屬性,它由pyqtSignal()建立。

1

2

self.c = Communicate()

self.c.closeApp.connect(self.close)

自定義closeApp訊號連線到QMainWindow的close槽

1

2

3

def mousePressEvent(self, event):

    self.c.closeApp.emit()

當在窗體上點選滑鼠時會觸發closeApp訊號,使程式退出。