当前位置:   article > 正文

《快速掌握PyQt5》第十七章 事件处理

《快速掌握PyQt5》第十七章 事件处理

第十六章 事件处理

17.1 窗口关闭事件

17.2 鼠标事件

17.3 键盘事件

17.4 小结


《快速掌握PyQt5》专栏已整理成书出版,书名为《PyQt编程快速上手》,详情请见该链接。感谢大家一直以来的支持!祝大家PyQt用得越来越顺!

事件就是由窗口、控件本身或者PyQt5自身产生的,配合用户动作的各种响应。“事件”和“信号”非常相似,但请不要归为一类。

事件类型种类繁多,这里主要介绍一些常用的:窗口关闭事件处理、鼠标事件处理以及键盘事件处理。

17.1 窗口关闭事件

当笔者在该CSDN博客编辑器中进行写作时,若没有点击保存直接关闭窗口时(触发窗口关闭事件),会出现弹框询问是否确定离开:

我们来用PyQt5实现类似功能,代码如下:

  1. import sys
  2. from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QPushButton, QMessageBox, QVBoxLayout
  3. class Demo(QWidget):
  4. def __init__(self):
  5. super(Demo, self).__init__()
  6. self.is_saved = True # 1
  7. self.textedit = QTextEdit(self) # 2
  8. self.textedit.textChanged.connect(self.on_textchanged_func)
  9. self.button = QPushButton('Save', self) # 3
  10. self.button.clicked.connect(self.on_clicked_func)
  11. self.v_layout = QVBoxLayout()
  12. self.v_layout.addWidget(self.textedit)
  13. self.v_layout.addWidget(self.button)
  14. self.setLayout(self.v_layout)
  15. def on_textchanged_func(self):
  16. if self.textedit.toPlainText():
  17. self.is_saved = False
  18. else:
  19. self.is_saved = True
  20. def on_clicked_func(self):
  21. self.save_func(self.textedit.toPlainText())
  22. self.is_saved = True
  23. def save_func(self, text):
  24. with open('saved.txt', 'w') as f:
  25. f.write(text)
  26. def closeEvent(self, QCloseEvent): # 4
  27. if not self.is_saved:
  28. choice = QMessageBox.question(self, '', 'Do you want to save the text?',
  29. QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
  30. if choice == QMessageBox.Yes:
  31. self.save_func(self.textedit.toPlainText())
  32. QCloseEvent.accept()
  33. elif choice == QMessageBox.No:
  34. QCloseEvent.accept()
  35. else:
  36. QCloseEvent.ignore()
  37. if __name__ == '__main__':
  38. app = QApplication(sys.argv)
  39. demo = Demo()
  40. demo.show()
  41. sys.exit(app.exec_())

1. is_saved变量用于记录用户是否已经进行保存;

2. 实例化一个QTextEdit控件用于文本编辑,将其textChanged信号和自定义的槽函数连接起来:

  1. def on_textchanged_func(self):
  2. if self.textedit.toPlainText():
  3. self.is_saved = False
  4. else:
  5. self.is_saved = True
'
运行

在槽函数中我们判断在每次文本内容发生变化时,textedit中是否还有文本,若有的话则将is_saved变量设为False,即未保存;若无文本,则将其设为True(如果没有文本的话,那可以直接关闭窗口,程序不会询问是否需要保存,因为没必要)。

3. 实例化一个按钮用于保存操作,将clicked信号与自定义的槽函数进行连接:

  1. def on_clicked_func(self):
  2. self.save_func(self.textedit.toPlainText())
  3. self.is_saved = True
'
运行

每次点击该按钮就进行保存,不管文本编辑框中是否有文本,文本保存通过save_fcun()函数完成:

  1. def save_func(self, text):
  2. with open('saved.txt', 'w') as f:
  3. f.write(text)
'
运行

我们将内容保存在当前目录下的saved.txt函数中。PyQt5提供一个QFileDialog类可以让我们更好的完成保存操作,后续章节会涉及,这里只是先简单的完成下保存功能。

4. 这里我们重新定义了QWidget的窗口关闭函数closeEvent(),如果用户还没有进行保存,则弹出一个QMessageBox窗口询问是否保存,若用户点击Yes,则调用save_func()函数进行保存,然后通过accept()方法来接收关闭窗口操作,窗口随之关闭;若点击No,则不进行保存,但同样得关闭窗口;若点击cancel,也不进行保存,并通过ignore()方法来忽略这次关闭窗口的操作。

运行截图如下,输入la vie est belle后不点击Save按钮,直接关闭窗口,则会出现弹窗询问是否需要保存:

我们点击Yes后,则窗口关闭,在项目路径下出现一个‘saved.txt’文件,里面的文本正是我们之前所输入的la vie est belle:

17.2 鼠标事件

鼠标移动、按下或者释放动作都会唤起相应的鼠标事件:

  1. import sys
  2. from PyQt5.QtCore import Qt
  3. from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
  4. class Demo(QWidget):
  5. def __init__(self):
  6. super(Demo, self).__init__()
  7. self.button_label = QLabel('No Button Pressed', self) # 1
  8. self.xy_label = QLabel('x:0, y:0', self) # 2
  9. self.global_xy_label = QLabel('global x:0, global y:0', self) # 3
  10. self.button_label.setAlignment(Qt.AlignCenter)
  11. self.xy_label.setAlignment(Qt.AlignCenter)
  12. self.global_xy_label.setAlignment(Qt.AlignCenter)
  13. self.v_layout = QVBoxLayout()
  14. self.v_layout.addWidget(self.button_label)
  15. self.v_layout.addWidget(self.xy_label)
  16. self.v_layout.addWidget(self.global_xy_label)
  17. self.setLayout(self.v_layout)
  18. self.resize(300, 300)
  19. self.setMouseTracking(True) # 4
  20. def mouseMoveEvent(self, QMouseEvent): # 5
  21. x = QMouseEvent.x()
  22. y = QMouseEvent.y()
  23. global_x = QMouseEvent.globalX()
  24. global_y = QMouseEvent.globalY()
  25. self.xy_label.setText('x:{}, y:{}'.format(x, y))
  26. self.global_xy_label.setText('global x:{}, global y:{}'.format(global_x, global_y))
  27. def mousePressEvent(self, QMouseEvent): # 6
  28. if QMouseEvent.button() == Qt.LeftButton:
  29. self.button_label.setText('Left Button Pressed')
  30. elif QMouseEvent.button() == Qt.MidButton:
  31. self.button_label.setText('Middle Button Pressed')
  32. elif QMouseEvent.button() == Qt.RightButton:
  33. self.button_label.setText('Right Button Pressed')
  34. def mouseReleaseEvent(self, QMouseEvent): # 7
  35. if QMouseEvent.button() == Qt.LeftButton:
  36. self.button_label.setText('Left Button Released')
  37. elif QMouseEvent.button() == Qt.MidButton:
  38. self.button_label.setText('Middle Button Released')
  39. elif QMouseEvent.button() == Qt.RightButton:
  40. self.button_label.setText('Right Button Released')
  41. def mouseDoubleClickEvent(self, QMouseEvent): # 8
  42. if QMouseEvent.button() == Qt.LeftButton:
  43. self.button_label.setText('Left Button Double Clikced')
  44. elif QMouseEvent.button() == Qt.MidButton:
  45. self.button_label.setText('Middle Button Double Clicked')
  46. elif QMouseEvent.button() == Qt.RightButton:
  47. self.button_label.setText('Right Button Double Clikced')
  48. if __name__ == '__main__':
  49. app = QApplication(sys.argv)
  50. demo = Demo()
  51. demo.show()
  52. sys.exit(app.exec_())

1. button_label用来显示鼠标的点击和释放动作;

2. xy_label用于记录鼠标相对于QWidget窗口的坐标;

3. global_xy_label用于记录鼠标相对于显示屏屏幕的坐标;

4. setMouseTracking(True)方法可以让窗口始终追踪鼠标,否则只能每次等鼠标被点击后,窗口才会开始记录鼠标的动作变化;而鼠标释放后,窗口又会不进行记录了,这样比较麻烦。

5. mouseMoveEvent()为鼠标移动时所触发的响应函数,在函数中,我们通过x()和y()方法获取鼠标相对于QWidget窗口的坐标,用globalX()和globalY()方法获取鼠标相对于显示屏屏幕的坐标;

6. mousePressEvent()为鼠标被按下时所触发的响应函数,在函数中,我们通过button()方法来确认被按下的键,然后用button_label显示被按下的键;

7. mouseReleaseEvent()为鼠标释放时所触发的响应函数,同理,在函数中,我们通过button()方法来确认被释放的键,然后用button_label显示被释放的键;

8. mouseDoubleClickEvent()为鼠标被双击时所触发的响应函数,同理,在函数中,我们通过button()方法来确认被双击的键,然后用button_label显示被双击的键;

运行截图如下,刚开始坐标都为(0, 0),鼠标也没有键被按下:

之后我们移动鼠标,发现坐标值随之变化:

按下鼠标左键,button_label显示被按下的键:

释放左键后,文本信息变化,显示被释放的键:

双击鼠标左键,同样显示对应信息:

17.3 键盘事件

每当用户按下或释放键盘上的任意键时都会触发键盘事件:

  1. import sys
  2. from PyQt5.QtCore import Qt
  3. from PyQt5.QtGui import QPixmap
  4. from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
  5. class Demo(QWidget):
  6. def __init__(self):
  7. super(Demo, self).__init__()
  8. self.pic_label = QLabel(self) # 1
  9. self.pic_label.setPixmap(QPixmap('images/keyboard.png'))
  10. self.pic_label.setAlignment(Qt.AlignCenter)
  11. self.key_label = QLabel('No Key Pressed', self) # 2
  12. self.key_label.setAlignment(Qt.AlignCenter)
  13. self.v_layout = QVBoxLayout()
  14. self.v_layout.addWidget(self.pic_label)
  15. self.v_layout.addWidget(self.key_label)
  16. self.setLayout(self.v_layout)
  17. def keyPressEvent(self, QKeyEvent): # 3
  18. if QKeyEvent.key() == Qt.Key_Up:
  19. self.pic_label.setPixmap(QPixmap('images/up.png'))
  20. self.key_label.setText('Key Up Pressed')
  21. elif QKeyEvent.key() == Qt.Key_Down:
  22. self.pic_label.setPixmap(QPixmap('images/down.png'))
  23. self.key_label.setText('Key Down Pressed')
  24. elif QKeyEvent.key() == Qt.Key_Left:
  25. self.pic_label.setPixmap(QPixmap('images/left.png'))
  26. self.key_label.setText('Key Left Pressed')
  27. elif QKeyEvent.key() == Qt.Key_Right:
  28. self.pic_label.setPixmap(QPixmap('images/right.png'))
  29. self.key_label.setText('Key Right Pressed')
  30. def keyReleaseEvent(self, QKeyEvent): # 4
  31. self.pic_label.setPixmap(QPixmap('images/keyboard.png'))
  32. self.key_label.setText('Key Released')
  33. if __name__ == '__main__':
  34. app = QApplication(sys.argv)
  35. demo = Demo()
  36. demo.show()
  37. sys.exit(app.exec_())

1. pic_label用于设置图片,先将初始化的图片设为keyboard.png;

2. key_label用于记录按键状态;

3. keyPressEvent()为键盘某个键被按下时所触发的响应函数,在这个函数中我们判断被按下的键种类,并将pic_label设为相应的箭头图片,将key_label设为相应的文本;

4. keyReleasedEvent()在键盘上的任意键被释放时所触发的响应函数,在这个函数中,我们将pic_label设为初始图片keyboard.png,并将key_label文本设为‘Key Released'。

注:可以在QtAssistant中输入Qt::Key找到所有键盘值:

图片下载地址:

运行截图如下,初始状态:

当按下向上键后:

释放后:

关于事件的进阶用法,请大家阅读《PyQt5高级编程实战》事件处理深入应用

17.4 小结

1. 本章一共介绍了三种事件类型:窗口关闭事件、鼠标事件和键盘事件,分别是对窗口关闭、鼠标和键盘动作的响应。当然事件类型还有很多,之后章节会有涉及;

2. setMouseTracking(True)可以让窗口时刻追踪鼠标,而不需要在鼠标被按下时才会进行追踪;

3. x()和y()获取鼠标相对于窗口部件的坐标值,而globalX()和globalY()获取鼠标相对于显示屏窗口的坐标值;

4. button()方法用于获取鼠标被按下或释放的键,key()方法用于获取键盘被按下或释放的键。

欢迎关注我的微信公众号,发现更多有趣内容:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/909145
推荐阅读
相关标签
  

闽ICP备14008679号