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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/La_vie_est_belle/article/details/82707815

第十六章 事件处理

17.1 窗口关闭事件

17.2 鼠标事件

17.3 键盘事件

17.4 小结:


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

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

17.1 窗口关闭事件

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

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

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QPushButton, QMessageBox, QVBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()

        self.is_saved = True                                            # 1

        self.textedit = QTextEdit(self)                                 # 2
        self.textedit.textChanged.connect(self.on_textchanged_func)

        self.button = QPushButton('Save', self)                         # 3
        self.button.clicked.connect(self.on_clicked_func)

        self.v_layout = QVBoxLayout()   
        self.v_layout.addWidget(self.textedit)
        self.v_layout.addWidget(self.button)
        self.setLayout(self.v_layout)

    def on_textchanged_func(self):                      
        if self.textedit.toPlainText(): 
            self.is_saved = False
        else:
            self.is_saved = True

    def on_clicked_func(self):
        self.save_func(self.textedit.toPlainText())
        self.is_saved = True

    def save_func(self, text):          
        with open('saved.txt', 'w') as f:
            f.write(text)

    def closeEvent(self, QCloseEvent):                                  # 4
        if not self.is_saved:
            choice = QMessageBox.question(self, '', 'Do you want to save the text?',
                                          QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
            if choice == QMessageBox.Yes:
                self.save_func(self.textedit.toPlainText())
                QCloseEvent.accept()
            elif choice == QMessageBox.No:
                QCloseEvent.accept()
            else:
                QCloseEvent.ignore()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

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

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

def on_textchanged_func(self):                      
    if self.textedit.toPlainText(): 
        self.is_saved = False
    else:
        self.is_saved = True

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

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

def on_clicked_func(self):
    self.save_func(self.textedit.toPlainText())
    self.is_saved = True

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

def save_func(self, text):          
    with open('saved.txt', 'w') as f:
        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 鼠标事件

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

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.button_label = QLabel('No Button Pressed', self)              # 1
        self.xy_label = QLabel('x:0, y:0', self)                           # 2
        self.global_xy_label = QLabel('global x:0, global y:0', self)      # 3

        self.button_label.setAlignment(Qt.AlignCenter)
        self.xy_label.setAlignment(Qt.AlignCenter)
        self.global_xy_label.setAlignment(Qt.AlignCenter)

        self.v_layout = QVBoxLayout()
        self.v_layout.addWidget(self.button_label)
        self.v_layout.addWidget(self.xy_label)
        self.v_layout.addWidget(self.global_xy_label)
        self.setLayout(self.v_layout)

        self.resize(300, 300)                                          
        self.setMouseTracking(True)                                        # 4

    def mouseMoveEvent(self, QMouseEvent):                                 # 5
        x = QMouseEvent.x()
        y = QMouseEvent.y()
        global_x = QMouseEvent.globalX()
        global_y = QMouseEvent.globalY()

        self.xy_label.setText('x:{}, y:{}'.format(x, y))
        self.global_xy_label.setText('global x:{}, global y:{}'.format(global_x, global_y))

    def mousePressEvent(self, QMouseEvent):                                # 6
        if QMouseEvent.button() == Qt.LeftButton:
            self.button_label.setText('Left Button Pressed')
        elif QMouseEvent.button() == Qt.MidButton:
            self.button_label.setText('Middle Button Pressed')
        elif QMouseEvent.button() == Qt.RightButton:
            self.button_label.setText('Right Button Pressed')

    def mouseReleaseEvent(self, QMouseEvent):                              # 7
        if QMouseEvent.button() == Qt.LeftButton:
            self.button_label.setText('Left Button Released')
        elif QMouseEvent.button() == Qt.MidButton:
            self.button_label.setText('Middle Button Released')
        elif QMouseEvent.button() == Qt.RightButton:
            self.button_label.setText('Right Button Released')

    def mouseDoubleClickEvent(self, QMouseEvent):                          # 8
        if QMouseEvent.button() == Qt.LeftButton:
            self.button_label.setText('Left Button Double Clikced')
        elif QMouseEvent.button() == Qt.MidButton:
            self.button_label.setText('Middle Button Double Clicked')
        elif QMouseEvent.button() == Qt.RightButton:
            self.button_label.setText('Right Button Double Clikced')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    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 键盘事件

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

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.pic_label = QLabel(self)                                   # 1
        self.pic_label.setPixmap(QPixmap('images/keyboard.png'))
        self.pic_label.setAlignment(Qt.AlignCenter)
    
        self.key_label = QLabel('No Key Pressed', self)                 # 2
        self.key_label.setAlignment(Qt.AlignCenter)

        self.v_layout = QVBoxLayout()
        self.v_layout.addWidget(self.pic_label)
        self.v_layout.addWidget(self.key_label)
        self.setLayout(self.v_layout)
    
    def keyPressEvent(self, QKeyEvent):                                 # 3
        if QKeyEvent.key() == Qt.Key_Up:
            self.pic_label.setPixmap(QPixmap('images/up.png'))
            self.key_label.setText('Key Up Pressed')
        elif QKeyEvent.key() == Qt.Key_Down:
            self.pic_label.setPixmap(QPixmap('images/down.png'))
            self.key_label.setText('Key Down Pressed')
        elif QKeyEvent.key() == Qt.Key_Left:
            self.pic_label.setPixmap(QPixmap('images/left.png'))
            self.key_label.setText('Key Left Pressed')
        elif QKeyEvent.key() == Qt.Key_Right:
            self.pic_label.setPixmap(QPixmap('images/right.png'))
            self.key_label.setText('Key Right Pressed')
    
    def keyReleaseEvent(self, QKeyEvent):                               # 4
        self.pic_label.setPixmap(QPixmap('images/keyboard.png'))
        self.key_label.setText('Key Released')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    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找到所有键盘值:

图片下载地址:

keyboard.png: https://www.easyicon.net/download/png/1197696/64/

up.png: https://www.easyicon.net/download/png/16090/32/

down.png: https://www.easyicon.net/download/png/6294/32/

right.png: https://www.easyicon.net/download/png/4515/32/

left.png: https://www.easyicon.net/download/png/14605/32/

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

当按下向上键后:

释放后:

17.4 小结:

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

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

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

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

----------------------------------------------------------------------

喜欢的小伙伴可以加入这个Python QQ交流群一起学习:820934083

猜你喜欢

转载自blog.csdn.net/La_vie_est_belle/article/details/82707815