川小胖学python

博客园 首页 新随笔 联系 订阅 管理

PyQt中提供了两种针对事件处理的机制:一种是事件,另一种则是信号和槽

 一、事件

事件处理在PyQt中是比较底层的,常用的事件有键盘事件、鼠标事件、拖放事件、滚轮事件、定时事件、焦点事件、进入和离开事件(光标移入控件或者移出),移动事件(窗口位置变化),显示和隐藏事件,窗口事件(窗口是否为当前窗口)、以及常见的Qt事件:Socket事件、剪贴板事件、文字改变事件,布局改变事件等。

针对这些事件,PyQt提供了多种事件处理和过滤方法,其中最常用的有两种:

(1)重写事件具体的函数(例如:mousePressEvent()/keyPressEvent()....)

(2)重新实现QObject.event()一般用在PyQt没有提供该事件的处理函数的情况下,即添加一个新的事件;

1.1 重写事件

 1 import sys,os
 2 from PyQt5.QtCore import Qt
 3 from PyQt5.QtWidgets import QWidget, QApplication,QMessageBox
 4 from PyQt5.QtGui import QIcon
 5 
 6 path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 7 
 8 class MyWindow(QWidget):
 9 
10     def __init__(self):
11         super(MyWindow, self).__init__()
12         self.initUI()
13 
14     def initUI(self):
15         self.setGeometry(300, 300, 300, 250)
16         self.setWindowTitle('重写事件示例')
17         self.setWindowIcon(QIcon(r'%s\4.图标素材\chuan.ico' % path))
18 
19     def closeEvent(self, QCloseEvent):
20         '''
21         重写closeEvent方法,关闭窗口时触发
22         '''
23         reply = QMessageBox.question(self,'本程序',"是否要退出程序?",
24                                               QMessageBox.Yes | QMessageBox.No,
25                                               QMessageBox.No)
26         if reply == QMessageBox.Yes:
27             QCloseEvent.accept()
28         else:
29             QCloseEvent.ignore()
30 
31 
32     def keyPressEvent(self, QKeyEvent):
33         '''
34         重写keyPressEvent事件,按下ESC就会退出程序
35         '''
36         if QKeyEvent.key() == Qt.Key_Escape:
37             self.close()
38 
39 
40 if __name__ == '__main__':
41     app = QApplication(sys.argv)
42     win = MyWindow()
43     win.show()
44     sys.exit(app.exec_())
重写事件示例

这段代码里重写了keyPressEvent和closeEvent两个事件。实现了两个功能:(1)按下ESC是可退出关闭窗口;(2)关闭当前窗口时,弹出对话框。

效果图如下:

在pycharm中编辑时,我们可以发现,QWidget类下虽然有该keyPressEvent和closeEvent方法,但并没有编写有意义的内容。

1.2 创建新事件

可参考前面小节的center(),不再详述。

除上述内容外,再对三个概念加以学习,即事件对象、事件发送。

事件对象时python用来描述一系列自身属性的对象。

 1 import sys,os
 2 from PyQt5.QtWidgets import QApplication,QWidget,QGridLayout,QLabel
 3 from PyQt5.QtGui import QIcon
 4 from PyQt5.QtCore import Qt
 5 
 6 path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 7 
 8 class MyWindow(QWidget):
 9 
10     def __init__(self):
11         super().__init__()
12         self.initUI()
13 
14     def initUI(self):
15         self.setGeometry(600,300,350,250)
16         self.setWindowTitle('信号和槽')
17         self.setWindowIcon(QIcon(r'%s\4.图标素材\chuan.ico' % path))
18 
19         grid = QGridLayout()
20         grid.setSpacing(10)
21 
22         x=0
23         y=0
24         self.text = "x:{},y:{}".format(x,y)
25         self.label = QLabel(self.text,self)
26         grid.addWidget(self.label,0,0,Qt.AlignTop)
27 
28         self.setMouseTracking(True) #开启鼠标追踪
29         self.setLayout(grid)
30 
31     def mouseMoveEvent(self, QMouseEvent):
32         x = QMouseEvent.x()
33         y = QMouseEvent.y()
34         text = "x:{},y:{}".format(x, y)
35         self.label.setText(text)
36 
37 
38 if __name__ == '__main__':
39     app = QApplication(sys.argv)
40     win = MyWindow()
41     win.show()
42     sys.exit(app.exec_())
事件对象示例

在这个示例中,我们再label里显示鼠标的坐标。mouseMoveEvent方法下的QMouseEvent即鼠标移动的事件对象,也就是需要捕捉的信号来源。

 

事件发送是在程序设计与调试时,我们需要知道是哪一个控件发送了信号,利用PyQt5中的sender()方法可以实现。

 1 import sys,os
 2 from PyQt5.QtWidgets import QMainWindow,QApplication,QPushButton
 3 from PyQt5.QtGui import QIcon
 4 
 5 path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 6 
 7 class MyWindow(QMainWindow):
 8 
 9     def __init__(self):
10         super().__init__()
11         self.initUI()
12 
13     def initUI(self):
14         self.setGeometry(600,300,300,260)
15         self.setWindowTitle('事件发送')
16         self.setWindowIcon(QIcon(r'%s\4.图标素材\chuan.ico' % path))
17 
18         btn1 = QPushButton('按钮一',self)
19         btn2 = QPushButton('按钮二',self)
20 
21         btn1.move(30,50)
22         btn2.move(150,50)
23 
24         btn1.clicked.connect(self.buttonClicked)
25         btn2.clicked.connect(self.buttonClicked)
26 
27         self.statusBar()
28 
29     def buttonClicked(self):
30         sender = self.sender()
31         self.statusBar().showMessage(sender.text() + '被按下')
32 
33  
34 if __name__ == '__main__':
35     app = QApplication(sys.argv)
36     win = MyWindow()
37     win.show()
38     sys.exit(app.exec_())
事件发送示例

sender()方法可以返回发送信号的控件名称。这在我们调试时可以起到极大的辅助作用。方便快速了解程序背后的设计思路。

 

二、信号和槽

信号(Signal)和槽(Slot)是Qt中的核心机制,也是在PyQt编程中对象之间进行通信的机制。在Qt中,每个QObject对象和PyQt中所有继承自QWidget的控件(这些都是QObject的子对象)都支持信号与槽机制。当信号发射时,连接的槽函数将会自动执行。在PyQt5中信号与槽通过object.signal.connect()方法连接。

使用时,既可以自定义信号,也可以使用pyqt内置信号。信号与槽具有以下几个特点:

  • 一个信号可以连接多个槽;
  • 一个信号也可以连接另一个信号;
  • 一个槽可以监听多个信号;
  • 信号与槽的连接可能同步或者异步,还可能跨线程连接;
  • 信号也可能断开。

除此之外,还有几个常用的操作方法需要说明:

  1. connect()方法可以将信号与槽函数连接。注意这里的槽函数不能加括号(后面会讲到);
  2. disconnect可以将接触信号与槽的连接;
  3. emit()可以发射信号
  4. 如果需要自定义信号,可以使用PyQt5.QtCore下的pyqtSignal方法。
 1 import sys,os
 2 from PyQt5.QtCore import pyqtSignal,QObject
 3 from PyQt5.QtWidgets import QMainWindow,QApplication
 4 from PyQt5.QtGui import QIcon
 5 
 6 path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 7 
 8 class Communicate(QObject):
 9     closeApp = pyqtSignal()
10 
11 class MyWindow(QMainWindow):
12 
13     def __init__(self):
14         super(MyWindow, self).__init__()
15         self.initUI()
16 
17     def initUI(self):
18         self.setGeometry(600,300,500,400)
19         self.setWindowIcon(QIcon(r'%s\4.图标素材\chuan.ico' % path))
20         self.setWindowTitle('信号发送')
21 
22         self.c = Communicate()
23         self.c.closeApp.connect(self.close)
24 
25     def mousePressEvent(self, *args, **kwargs):
26         self.c.closeApp.emit()
27 
28 
29 if __name__ == '__main__':
30     app = QApplication(sys.argv)
31     win = MyWindow()
32     win.show()
33     sys.exit(app.exec_())
信号与槽

在这个示例中,我们创建了一个closeApp的信号,该信号会在鼠标按下时触发。且该事件与QMainwindow绑定。

class Communicate(QObject):
    closeApp = pyqtSignal()

  这里,我们创建了一个Communicate类,并在该类下创建了信号。

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

  首先将communicate()类示例化给self.c。然后将closeApp信号与窗口的close()方法连接。

    def mousePressEvent(self, *args, **kwargs):
        self.c.closeApp.emit()

  点击鼠标按键时,emit()方法会将closeApp信号发射。

posted on 2019-03-15 11:30  川小胖学Python  阅读(1160)  评论(0编辑  收藏  举报