Python GUI 编程 | QWidget 窗口控件详解 — 事件消息

🌟想系统化学习 GUI 编程?看看这个:[Python GUI 编程] PySide & PyQt - 学习手册-CSDN博客

上图是 QWidget 支持的常见消息方法(不全但够用了,读者可以自行去进行父类追踪以获得更全的事件),本章只讲解各个消息的触发条件,不讲解消息触发时传入的消息对象的具体属性和函数(这个可以等用到时再去细查)。

小提示

上图中每个事件触发时都会传入对应事件的消息对象,对象是有自己的属性和方法的。通过传入的事件消息对象,我们可以得知事件触发时,触发该事件对象的具体信息。

0x01:QWidget 事件消息 — 显示和关闭事件

0x0101:showEvent(QShowEvent)

当控件显示时,会自动调用该控件的 showEvent() 方法,并传入一个 QShowEvent 对象:

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
​
    def showEvent(self, QShowEvent):
        """
        重写 showEvent 方法, 拦截事件信息
        """
        print("窗口显示了, 我该干 ....")
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0102:closeEvent(QCloseEvent)

当控件关闭时,会自动调用该控件的 closeEvent() 方法,并传入一个 QCloseEvent 对象:

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def closeEvent(self, QCloseEvent):
        """
        重写 closeEvent 方法, 拦截事件信息
        """
        print("窗口关闭了, 我该干 ....")
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

上面代码运行,会显示一个窗口,当我们点击窗口的 X 键,即关闭按钮,就会触发 closeEvent() 方法,打印其中的内容。

0x02:QWidget 事件消息 — 窗口移动事件

当控件移动时,会自动调用该控件的 moveEvent() 方法,并传入一个 QMoveEvent 对象:

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def moveEvent(self, QMoveEvent):
        """
        重写 moveEvent 方法, 拦截事件信息
        """
        print("窗口移动了, 我该干 ....")
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x03:QWidget 事件消息 — 窗口大小调整

当控件移动时,会自动调用该控件的 resizeEvent() 方法,并传入一个 QResizeEvent 对象:

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def resizeEvent(self, QResizeEvent):
        """
        重写 resizeEvent 方法, 拦截事件信息
        """
        print("窗口大小改变了, 我该干....")
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x04:QWidget 事件消息 — 鼠标事件

直接上示例,运行后会显示一个窗口,读者自行到窗口点点,看看触发了哪个方法就行:

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def enterEvent(self, QEvent):
        print("鼠标进来啦")
    
    def leaveEvent(self, QEvent):
        print("鼠标离开啦")
    
    def mousePressEvent(self, QMouseEvent):
        print("鼠标按下啦")
    
    def mouseReleaseEvent(self, QMouseEvent):
        print("鼠标释放啦")
    
    def mouseDoubleClickEvent(self, QMouseEvent):
        print("鼠标双击啦")
    
    def mouseMoveEvent(self, QMouseEvent):
        """
        未设置 setMouseTracking(True) 时,只有鼠标按下时,鼠标移动才会触发事件
        """
        print("鼠标移动啦")
    
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0401:演示案例 — 无 Title 窗口的左键拖拽移动

在前面的学习中,我们想要移动一个窗口,就必须拖动窗口的标题,在后续的开发中,我们有可能会想去掉窗口的标题,那去了窗口的标题栏,我们要怎么移动窗口呢?Try 一下?下面是示例代码(目前还没有讲到如何去掉窗口上面的标题,所以就先不去了,先实现功能):

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def mousePressEvent(self, event):
        """
        在用户鼠标点击时,获取当前用户鼠标在窗口中的绝对位置和窗口在屏幕中的绝对位置
        """
        if event.button() == Qt.LeftButton: # 判断用户是否按下鼠标左键
            self.move_flag = True # 设置移动标志为 True
        self.mouse_start_pos_x = event.globalPos().x() # 获取当前鼠标在窗口中的绝对位置 x 轴
        self.mouse_start_pos_y = event.globalPos().y() # 获取当前鼠标在窗口中的绝对位置 y 轴
        self.window_start_pos_x = self.x() # 获取窗口在屏幕中的绝对位置 x 轴
        self.window_start_pos_y = self.y() # 获取窗口在屏幕中的绝对位置 y 轴
    
    def mouseMoveEvent(self, event):
        """
        在用户鼠标移动时会不断触发该事件,获取用户当前鼠标位置并对比初始位置,计算其相对位置
        """
        if self.move_flag == True:
            mouse_current_pos_x = event.globalPos().x() # 获取当前鼠标在窗口中的绝对位置 x轴
            mouse_current_pos_y = event.globalPos().y() # 获取当前鼠标在窗口中的绝对位置 y轴
​
            # 计算鼠标相对位置
            mouse_move_x = (mouse_current_pos_x - self.mouse_start_pos_x)
            mouse_move_y = (mouse_current_pos_y - self.mouse_start_pos_y)
​
            window_move_x = self.window_start_pos_x + mouse_move_x
            window_move_y = self.window_start_pos_y + mouse_move_y
​
            # 移动窗口
            self.move(window_move_x, window_move_y)
    
    def mouseReleaseEvent(self, event):
        """
        在用户鼠标释放时,删除初始位置
        """
        if self.move_flag == True:
            self.move_flag = False
            del self.mouse_start_pos_x
            del self.mouse_start_pos_y
            del self.window_start_pos_x
            del self.window_start_pos_y
        
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x05:QWidget 事件消息 — 键盘事件

直接上示例,运行后会显示一个窗口,读者随机敲击键盘按键,看看触发了哪个方法就行(前提是当前应用程序的窗口要获取焦点):

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
​
    def keyPressEvent(self, QKeyEvent):
        print("键盘上某一个按键被按下了")
    
    def keyReleaseEvent(self, QKeyEvent):
        print("键盘上某一个按键被释放了")
    
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0501:演示案例 — 让指定控件获取键盘事件

不知道读者有没有想过一个事情,比如我又有两个控件,QLabel 控件在 QWidget 控件内部,我想让 QLabel 控件捕获键盘事件,我该怎么做?看下面这个示例(主要是 grabKeyboard() 方法,该方法能让指定控件捕获键盘事件):

import sys
from PyQt5.Qt import *
​
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def keyPressEvent(self, QKeyEvent):
        print("zzz")
​
class MyLabel(QLabel):
    def __init__(self):
        super().__init__()
        self.resize(300, 300)
        self.setStyleSheet("background-color: cyan;")
    
    def keyPressEvent(self, QKeyEvent):
        print("xxx")
​
    
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()
​
label = MyLabel()
label.setParent(window)
label.grabKeyboard()    # 让标签控件获取键盘事件
​
# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0502:演示案例 — 监听用户输入指定单个按键

在下面这个案例中,我们想让 QLabel 标签捕获用户输入的指定单个按键,比如 Tab 键。示例代码如下:

import sys
from PyQt5.Qt import *

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def keyPressEvent(self, QKeyEvent):
        print("zzz")

class MyLabel(QLabel):
    def __init__(self):
        super().__init__()
        self.resize(300, 300)
        self.setStyleSheet("background-color: cyan;")
    
    def keyPressEvent(self, QKeyEvent):
        # QKeyEvent.key() 获取键盘事件的键值
        if (QKeyEvent.key() == Qt.Key_Tab): # Qt.Key_Tab 表示 Tab 键
            print('用户点击了 Tab 键')

    
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()

label = MyLabel()
label.setParent(window)
label.grabKeyboard()    # 让标签控件获取键盘事件

# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0503:演示案例 — 监听用户输入指定组合键

在上面的案例中,我们捕获了单个按键的输入,那么这个案例,我们再补充一个 “组合键” 怎么获取,比如说 ctrl + sctrl + shift + A 怎么获取。

ctrl + shift + A 为例,三个按键里面,ctrlshift 都是修饰键,因为单纯的点击 ctrl 或者单纯的点击 shift,页面上都不会出现对应的字符。分清了修饰键和有普通键后,我们再来补充一条 QKeyEvent 的方法:modifiers()

modifiers() 函数可以捕获修饰键,多个修饰键之间需要使用按位或运算进行判断。直接上案例:

import sys
from PyQt5.Qt import *

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(800, 800)
    
    def keyPressEvent(self, QKeyEvent):
        print("zzz")

class MyLabel(QLabel):
    def __init__(self):
        super().__init__()
        self.resize(300, 300)
        self.setStyleSheet("background-color: cyan;")
    
    def keyPressEvent(self, QKeyEvent):
        # 捕获 Ctrl + S 快捷键
        if QKeyEvent.modifiers() == Qt.ControlModifier and QKeyEvent.key() == Qt.Key_S:
            print("Ctrl + S 被按下了")
        
        # 捕获 Ctrl + Alt + E 快捷键
        if QKeyEvent.modifiers() == (Qt.ControlModifier | Qt.AltModifier) and QKeyEvent.key() == Qt.Key_E:
            print("Ctrl + Alt + E 被按下了")
    
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
window = MyWidget()

label = MyLabel()
label.setParent(window)
label.grabKeyboard()    # 让标签控件获取键盘事件

# 3. 展示控件
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blue17 :: Hack3rX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值