实战PyQt5: 097-键盘事件

2023-05-16

在一个GUI桌面应用中,用户和程序之间的交互一般通过键盘和鼠标来完成,处理有关键盘和鼠标的事件是一个GUI程序几乎不可或缺的部分,下面介绍在Qt中处理输入焦点和键盘事件的相关知识。

设置控件的输入焦点

在一个窗口中,一般会有多个控件在其中,如果一个控件要获得键盘输入信息,必须将输入焦点设置到该控件上,在窗口中,一个时刻只有一个(或者没有) 控件可以获得输入焦点。可以使用QWidget的下列方法来操作控件的输入焦点。

  • setFocus([reason]):- 如果控件在活动窗口中,调用此方法后,该控件成为输入焦点。reason参数可为Qt.FoucsReason中的以下枚举变量。
    • MouseFocusReason (0): 使用鼠标获得焦点;
    • TabFocusReason (1): 按下了Tab键;
    • BacktabFocusReason (2): 按下了组合键+Tab键,组合键包括Shift或Control, 例如Shift+Tab;
    • ActiveWindowFocusReason (3): 窗口变为活动和非活动;
    • PopupFocusReason (4): 打开或关闭弹出窗口;
    • ShortcutFocusReason (5): 按下快捷键;
    • MenuBarFocusReason (6): 通过菜单操作;
    • OtherFocusReaaon (7): 其他方式。
  • clearFocus(): 清除输入焦点;
  • hasFocus(): 如果控件是输入焦点,返回True;否则,返回False;
  • focusWidget(): 返回最后调用setFocus()方法的控件对象;
  • setFocusProxy(): 指定获得输入焦点的控件对象;
  • focusProxy(): 返回获得非当前控件的输入焦点的控件对象;
  • focusNextChild(): 找到下一个可获得输入焦点的控件对象,并设置为输入焦点。相当于按了Tab键。如果有此控件,返回True;否则,返回False;
  • focusPreviousChild(): 找到上一个可获得输入焦点的控件对象,并设置为输入焦点。相当于按了Shift+Tab键。如果有此控件,返回True;否则,返回False;
  • focusNextPrevChild(): 如果isnext参数为True,功能相当于focusNextChild();如果isnext参数为False,功能相当于focusPreviousChild();
  • setTabOrder(,) - 静态函数。用于指定按下键时,输入焦点的移动顺序。component2是当输入焦点在component1是按下键后的输入焦点所在的控件。如果有多个控件,则需要调用多次。例如,指定输入焦点在按下键的变化顺序为widget1->widget2->widget3->widget4,相应的代码为:
                  QWidget.setTabOrder(widget1,widget2)
                  QWidget.setTabOrder(widget2,widget3)
                  QWidget.setTabOrder(widget3,widget4)
  • setFocusPolicy ():指定控件如何设置输入焦点。method可以Qt.FocusPolicy中的以下枚举变量:
    • NoFocus: 不能设置输入焦点;
    • TabFocus: 用Tab键设置输入焦点;
    • ClickFocus: 用点击鼠标来设置输入焦点;
    • StrongFocus: 用Tab键和点击鼠标来设置焦点;
    • WheelFocus:用Tab键、点击鼠标和滚轮来设置焦点。
  • focusPolicy():返回当前获得输入焦点的方式;
  • grabKeyboard():限定键盘输入。在调用releaseKeyboard()之前,其他控件无法获得输入焦点;
  • releaseKeyboard():释放之前所作的键盘输入限定。

QApplication类的静态方法focusWidget()返回拥有键盘输入焦点的应用程序顶级窗口。如果没有有,则返回None。

QWidget类的下列方法可用来处理焦点事件:

  • focusInEvent(self, event) - 获得焦点时被调用;
  • focusOutEvent(self,even) - 失去焦点时被调用。

上述函数中的event参数为QFocusEvent类的实例,有以下方法获得焦点事件相关信息:

  • gotFocus(): 如果event的类型为QEvent.FocusIn,返回True,否则,返回False;
  • lostFocus(): 如果event的类型为QEvent.FocusOut,返回True,否则,返回False;
  • reason(): 返回设置输入焦点的原因。

焦点设置测试

在测试代码中,我们创建一个带有QPushButton按钮和两个QLineEdit单行编辑的窗口。对于单行编辑框,处理获得和失去输入焦点的事件。通过按下按钮,我们将输入焦点设置为第二个单行编辑框。 另外,通过Tab键顺向切换焦点,或者通过S hift+Tab反向切换焦点。完整代码如下:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, 
                             QLineEdit, QPushButton, QVBoxLayout, QFormLayout)
 
class MyLineEdit(QLineEdit):
    def __init__(self, id, parent=None):
        super(MyLineEdit, self).__init__(parent)
        self.id = id
        
    #焦点进入事件
    def focusInEvent(self, evt):
        print('输入焦点在:', self.id)
        QLineEdit.focusInEvent(self, evt)
        
    #焦点离开事件
    def focusOutEvent(self, evt):
        print(self.id, ':失去输入焦点')
        QLineEdit.focusOutEvent(self, evt)
 
class FocusSetDemo(QMainWindow):
    def __init__(self, parent = None):
        super(FocusSetDemo, self).__init__(parent)
        
        # 设置窗口标题
        self.setWindowTitle('实战PyQt5:焦点设置演示')
        # 设置窗口大小
        self.resize(300, 200)
        
        self.initUi()
        
    def initUi(self):
        mainWidget = QWidget()
        mainLayout = QVBoxLayout()
        mainLayout.setSpacing(10)
        
        btnChangeFocus = QPushButton('将焦点设置到编辑框2')
        btnChangeFocus.clicked.connect(self.onButtonChangeFocus)
        
        self.lineEdit1 = MyLineEdit(1)
        self.lineEdit2 = MyLineEdit(2)
        
        fLayout = QFormLayout()
        fLayout.addRow('编辑框1', self.lineEdit1)
        fLayout.addRow('编辑框2', self.lineEdit2)
        
        mainLayout.addWidget(btnChangeFocus)
        mainLayout.addLayout(fLayout)
 
        mainWidget.setLayout(mainLayout)
        self.setCentralWidget(mainWidget)
        
    def onButtonChangeFocus(self):
        self.lineEdit2.setFocus()
        
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = FocusSetDemo()
    window.show()
    sys.exit(app.exec())

运行结果如下图:

实战PyQt5: 097-键盘事件

测试焦点事件

快捷键设置

快捷键(也称热键)是GUI程序交互操作的一种常见功能,在一个GUI应用的系统菜单里,我们常常可以见到菜单项有对应的快捷键操作。快捷键用来快速设置输入焦点,要设置快捷键,可以在相应的字母上加上“&”,程序运行后,会在相应的字母下加下划线以提示用户。按下Alt+带下划线的字母,对应的控件即可获得输入焦点,执行相应动作。

对于编辑框这类没有文本的控件,在设置快捷键时,可以创建一个QLabel对象,并通过调用setBuddy(component)与控件相关联。如果不创建QLabel对象,则可以使用QWidget的下列的方法来设置和管理快捷键:

  • grabShortcut (keys [,context]): 登记快捷键,返回一个标识符。参数keys为QtGui.QKeySequence对象。设置控制键+快捷键的Keys设置方式为:
    • QKeySequence.mnemonic("&e")
    • QKeySequence("Alt+e")
    • QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_E)

context参数可以是Qt.ShortcutContext中的枚举变量:WidgetShortcut、WidgetWithChildrenShortcut、WindowsShortcut(默认值 )和ApplicationShortcut。

  • releaseshortcut (id) - 删除标识符为id的组合键;
  • setShortcutEnabled(id [,flag]): flag为True时,标识符为id的组合键有效;否则无效。

按下快捷键时,产生QEvent.Shortcut事件,可在函数event(self,event)中处理。event参数是QShortcutEvent对象,有以下方法:

  • shortcutId(): 返回快捷键的标识符;
  • isAmbiguous(): 如果事件同时发送给几个控件,返回True;否则,返回Fasle;
  • key():返回代表所按下快捷键的QkeySequence对象。

快捷键设置测试

测试代码演示了直接为按钮设置快捷键,使用QLabel.setBuddy()方法为编辑框1设置快捷键和使用QWidget. grabShortcut为编辑框2设置快捷键,完整演示代码如下:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel,
                             QLineEdit, QPushButton, QVBoxLayout, QFormLayout)
 
class MyLineEdit(QLineEdit):
    def __init__(self, parent = None):
        super(MyLineEdit, self).__init__(parent)
        self.id = None
        
    def event(self, evt):
        if evt.type() == QEvent.Shortcut:
            if self.id == evt.shortcutId():
                self.setFocus(Qt.ShortcutFocusReason)
                return True
        return QLineEdit.event(self, evt)
 
class FocusSetDemo(QMainWindow):
    def __init__(self, parent = None):
        super(FocusSetDemo, self).__init__(parent)
        
        # 设置窗口标题
        self.setWindowTitle('实战PyQt5: 快捷键设置演示')
        # 设置窗口大小
        self.resize(360, 240)
        
        self.initUi()
        
    def initUi(self):
        mainWidget = QWidget()
        mainLayout = QVBoxLayout()
        mainLayout.setSpacing(10)
        
        btnClearFocus = QPushButton('(&R)清除编辑框1的输入焦点')
        btnClearFocus.clicked.connect(self.onButtonClearFocus)
        
        label1 = QLabel('编辑框1(&E)')
        self.lineEdit1 = MyLineEdit()
        self.lineEdit1.setText('test1')
        label1.setBuddy(self.lineEdit1)
        
        self.lineEdit2 = MyLineEdit()
        self.lineEdit2.setText('test2')
        self.lineEdit2.id = self.lineEdit2.grabShortcut(QKeySequence.mnemonic('&D'))
        
        fLayout = QFormLayout()
        fLayout.addRow(label1, self.lineEdit1)
        fLayout.addRow('编辑框2', self.lineEdit2)
        
        mainLayout.addWidget(btnClearFocus)
        mainLayout.addLayout(fLayout)
 
        mainWidget.setLayout(mainLayout)
        self.setCentralWidget(mainWidget)
        
    def onButtonClearFocus(self):
        self.lineEdit1.clearFocus()
        
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = FocusSetDemo()
    window.show()
    sys.exit(app.exec())

运行结果如下图所示:

实战PyQt5: 097-键盘事件

快捷键设置测试

按键事件

按下并释放键盘按键时,以下方法将被调用:

  • keyPressEvent(self,event): 按下某一键时,该方法被调用直到键被释放为止;
  • keyReleaseEvent(self,event) - 释放之前按下的键时被调用。

上述方法中的event参数为QKeyEvent对象,其常用方法有:

  • key(): 返回按下键的值;
  • text(): 返回按下键的Unicode字符编码信息,当按键为Shift, Control, Alt等时,则该函数返回的字符为空值。
  • modifiers(): 判断按下了哪些修饰键(Shift,Ctrl,Alt,等等)。返回值为Qt. KeyboardModifier 中下列枚举变量的组合:
    • NoModifier - 没有修饰键;
    • ShiftModifier - Shift修饰键;
    • ControlModifier - Ctrl修饰键;
    • AltModifier - Alt修饰键;
    • MetaModifier - 组合修饰键;
    • KeypadModifier - 附加键盘上的任何按键;
    • GroupSwitchModifier - 按下键(仅限X11系统)。
  • isAutoRepeat(): 如果一直按着某键,返回True;否则,返回False;
  • match(QKeySequence.StandardKey key): 如果当前的键组合与key相同,返回True;否则,返回False。

比如,是否按下了复制快捷键的代码:

         if e.matches(QKeySequence.Copy):
                   print("组合键为",QKeySequence.Copy)

处理键盘按键时,需要注意以下几点:

  • 控件必须可以设置为输入焦点。有些控件,如QLabel是不能接受输入焦点的;
  • 捕获键盘事件要使用grabKeyboard( )方法,释放时,调用rekeaseKeyboard();
  • 可能拦截除Tab键和Shift+Tab键以外的任何键。因为默认Tab /Shift+Tab事件(切换焦点)被先捕获了, 要拦截这两个键,只能在event(self,event)中完成;
  • 如果要让父控件继续收到键盘事件,要调用事件的ignore()方法;否则,调用accept()。

测试按键事件

测试代码演示里使用keyPressEvent和event来捕获键盘按下事件,并使用paintEvent将其显示在窗口中央。完整代码如下:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtGui import QPainter, QPen, QFont
from PyQt5.QtWidgets import QApplication, QWidget
 
class DemoKeyboardEvent(QWidget):
    def __init__(self, parent=None):
        super(DemoKeyboardEvent, self).__init__(parent)
 
        # 设置窗口标题
        self.setWindowTitle('实战PyQt5: 键盘按键事件演示')
        # 设置窗口大小
        self.resize(400, 320)
        
        self.key=''
        
    #重绘窗口事件
    def paintEvent(self, event):           
        painter = QPainter(self)
        painter.setFont(QFont(self.font().family(), 36))
        painter.setPen(QPen(Qt.blue))
        painter.setRenderHint(QPainter.TextAntialiasing)
        
        #居中绘制文本信息
        painter.drawText(self.rect(), Qt.AlignCenter, self.key)  
        
        #键盘按键事件
    def keyPressEvent(self, event):
        self.key = ''           
        if event.key() == Qt.Key_Home:
            self.key = 'Home'
        elif event.key() == Qt.Key_End:
            self.key = 'End'
        elif event.key() == Qt.Key_PageUp:
            if event.modifiers() & Qt.ControlModifier:
                self.key = "Ctrl+PageUp"
            else:
                self.key = "PageUp"
        elif event.key() == Qt.Key_PageDown:
            if event.modifiers() & Qt.ControlModifier:
                self.key = "Ctrl+PageDown"
            else:
                self.key = "PageDown"
        elif Qt.Key_0 <= event.key() <= Qt.Key_9:
            self.key = event.text()
        elif Qt.Key_A <= event.key() <= Qt.Key_Z:
            if event.modifiers() & Qt.ShiftModifier:
                self.key = "Shift+"
            self.key += event.text()
        
        #如果key有字符,不为空,则绘制字符
        if self.key:
            self.update()
        #否则就继续监视这个事件
        else:
            QWidget.keyPressEvent(self, event)
    
    #Tab键由于涉及焦点切换,不会传递给keyPressEvent,因此,需要在这里重新定义。  
    def event(self, event):
        #如果有按键按下,并且按键是tab键
        if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab:
            self.key = "Tab"
            self.update()
            return True
        return QWidget.event(self, event)   
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DemoKeyboardEvent()
    window.show()
    sys.exit(app.exec())

测试结果如下图:

实战PyQt5: 097-键盘事件

测试按键事件

本文知识点

  • 焦点事件;
  • 快捷键设置;
  • 键盘按下和释放事件;
  • 使用QPainter 绘制指定样式的文字信息。

前一篇: 实战PyQt5: 096-窗口事件

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实战PyQt5: 097-键盘事件 的相关文章

随机推荐

  • SQLServer2019安装(Windows)

    目录 一 SQLServer2019下载 1 官网下载地址 2 下载安装包 2 1 选择Developer版本 立即下载 2 2 选择下载位置 3 安装 3 1 打开 SQLServer2019 x64 CHS Dev iso
  • 香橙派4在armbian上应用自启动设置

    编辑了一个qt界面 需要设置开机启动 xff0c 费了九牛二虎之力 xff0c 终于搞定了 设置开机显示命令行 开机不显示图形界面 xff0c 直接显示命令行的操作有两种方法 xff1a 多用户方法 sudo systemctl set s
  • vscode 中git解决冲突,合并代码的两种方法

    一 报错信息 有文件冲突的话 xff0c 会报错 xff1a git merge pre span class token operator span master span class token comment 合并 pre maste
  • 用Python爬取淘宝4403条大裤衩数据进行分析,终于找到可以入手的那一条

    炎炎夏日 xff0c 长裤已难以满足广大男生的需求 xff0c 为了在搬砖和摆摊的过程中增添一丝舒适感 xff0c 他们开始寻找一种神奇的存在 大裤衩 J哥在种菜的这些日子里也日益感受到大裤衩的重要性 xff0c 于是 xff0c 默默打开
  • 用户标签有哪些类型,如何进行科学分类?

    标签的分类 xff0c 是理解用户标签 理解用户画像的基础 优秀的标签分类 xff0c 将使得标签画像系统易于用户的使用 本篇文章和大家简单介绍一下标签数据的分类 按照不同的分类方法 xff0c 标签的分类也自然不同 本文主要介绍几种最常规
  • Python字符串查找函数find

    Python字符串查找函数find 比较简单 xff0c 直接上代码 总结下规则 xff0c 结果数字说明 按字符串索引下标查询 xff0c 索引从0开始 xff0c 空格会占位并且有下标结果 1 xff0c 代表没有查找到英文区分大小写
  • 闲着看看jquery.ajax源码

    框架的作用就是简化我们做的事情 xff0c 却又不失灵活性 jquery是js框架中的中流砥柱 xff0c 灵活并且强大 jquery中对ajax的封装很完美 xff0c 且不说底层的ajax函数的强大 xff0c 但是其上层的get xf
  • java 转json 报错处理机制 案例 .

    JSON lib这个Java类包用于把bean map和XML转换成JSON并能够把JSON转回成bean和DynaBean http kingpingping iteye com blog 1157771 报错处理机制 commons b
  • 关于jquery对象的remove参数中出现伪位置类选择器,出现非预期结果的研究

    记得前几天有人在论坛发帖问了一个关于jquery删除节点的问题 原帖是这样的 xff08 原帖的地址是 xff1a 原帖 xff09 lt ul gt lt li gt 1 lt li gt lt li title 61 34 a 34 g
  • linux源码阅读利器-GNU GLOBAL Source Code Tag System

    学习浏览linux源码 xff0c 如果自己用自带的文本编辑器就太麻烦了 xff0c 但是如果安装强大的lxr那就太麻烦了 xff08 对于非debian用户来说 xff09 xff0c 找了很久找到了一个用起来很不错的源码浏览工具 xff
  • android 4.0.1源码编译,学习错误解决

    主机是fedora 14 linux内核2 6 35 6 swapon交换分区1 5G make version 3 81 官方指定的make版本 xff09 jdk 1 6 磁盘预留空间大概需要大于13G 具体的编译步骤可参考 Fedor
  • android webApp 调试问题解决

    前不久做了个webapp xff0c 在pc上chrome调试都是可以的 但是手机上显示却有点问题 xff0c 所以一直是想在手机浏览器上调试 xff0c 但是一直没有相关支持 xff0c 后来google终于出了chrome beta版
  • android系统源代码分析 书评

    其实接触android应用开发差不多两年了 xff0c 但是实际上并没与多少拿得出手的作品 因为在很长一段时间里我都在问自己android是什么 xff0c 内部怎么运行的 xff0c 为什么我的java代码就可以在linux上运行 xff
  • Fedora18博通430g电信无线拨号上网

    回家折腾了有两三天 xff0c 想让fedora18 也能蹭上网 首当其冲的问题就是fedora 没有为无线网卡安装驱动 xff0c 只能自己慢慢找驱动 费了好久找到上传了驱动下载 xff0c 满心欢喜按照README 编译 xff0c 结
  • VR技术的发展趋势,未来有哪些展望?

    虚拟现实技术Virtual Reality xff0c 缩写为VR xff0c 是一项全新的实用技术 虚拟现实技术包含计算机 电子信息 仿真技术于一体 xff0c 其基本实现方式是计算机模拟虚拟环境从而给人以环境沉浸感 目前来看 xff0c
  • APM2.8 Rover 自动巡航车设计(超声波和红外测距仪的安装和设置)

    xff08 转载 xff09 4 1 ROVER自动巡航车自主壁障的设置 APM2 8的飞控驾驶仪的传感器接入支持超声波 xff0c 电压传感器 xff0c 电流传感器 xff0c 光流传感器 xff0c 红外传感器 其中超声波和红外传感器
  • 学习笔记(一)-古月ROS机器视觉开发入门 -摄像头参数标定

    我们做图像处理为的就是要得到图像的数据 xff0c 在得到这些数据之后怎么对这些数据进行处理 xff0c 这才是我们主要关心的问题 但是 xff0c 在此之前 xff0c 我们还需要做一个非常主要的步骤 对摄像头的参数进行参数标定 安装标定
  • 卸载ROS的方法

    1 卸载全部ros span class token variable sudo span span class token variable apt get span span class token variable remove sp
  • Json String to Java Bean

    34 version 34 1 34 consentId 34 34 b618924f 8a6c 42bc 8553 99e3a8a0fec4 34 34 domain 34 34 cd site15294072534021 com 34
  • 实战PyQt5: 097-键盘事件

    在一个GUI桌面应用中 xff0c 用户和程序之间的交互一般通过键盘和鼠标来完成 xff0c 处理有关键盘和鼠标的事件是一个GUI程序几乎不可或缺的部分 xff0c 下面介绍在Qt中处理输入焦点和键盘事件的相关知识 设置控件的输入焦点 在一