PyQt5编程(18):键盘事件

 键盘事件被频繁处理。例如,按下F1,显示帮助信息;在文本编辑框中,按下回车键,输入焦点自动跳到另一控件。下面详细介绍键盘事件。
1.设置输入焦点
在某一时刻,只有一个控件(或根本没有)可以获得输入焦点。指定输入焦点可使用QWidget的下列方法:

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

下面的代码为:
创建一个带有按钮和两个单行编辑框的窗口。 对于单行编辑框,我们处理获得和失去输入焦点的事件。通过按下按钮,我们将输入焦点设置为第二个单行编辑框。 另外,通过按键可切换输入焦点。

-- coding: utf-8 --

from PyQt5 import QtWidgets

class MyLineEdit(QtWidgets.QLineEdit):
def init(self, id, parent=None):
QtWidgets.QLineEdit.init(self, parent)
self.id = id
def focusInEvent(self, e):
print("输入焦点在", self.id)
QtWidgets.QLineEdit.focusInEvent(self, e)
def focusOutEvent(self, e):
print(self.id,"失去输入焦点")
QtWidgets.QLineEdit.focusOutEvent(self, e)

class MyWindow(QtWidgets.QWidget):
def init(self, parent=None):
QtWidgets.QWidget.init(self, parent)
self.resize(300, 100)
self.button = QtWidgets.QPushButton("设置输入焦点在编辑框 2")
self.line1 = MyLineEdit(1)
self.line2 = MyLineEdit(2)
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.button)
self.vbox.addWidget(self.line1)
self.vbox.addWidget(self.line2)
self.setLayout(self.vbox)
self.button.clicked.connect(self.on_clicked)
# 指定顺序
QtWidgets.QWidget.setTabOrder(self.line1, self.line2)
QtWidgets.QWidget.setTabOrder(self.line2, self.button)
def on_clicked(self):
self.line2.setFocus()

if name == "main":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

2.设置快捷键
快捷键(也要称热键)一些特别键的组合,用来快速设置输入焦点。按下输入焦点所在按钮的快捷键,按钮将被按下。
要设置快捷键,需要在相应字母前加上“&”,程序运行后,在相应字母下加上下划线以提示用户。 按下+带下划线的字母,对应的控件获得输入焦点。对于编辑框这类没有文本的控件,在设置快捷键时,要先创建一个QLabel对象,并通过调用 setBuddy(component)与控件相关联。如果不想创建QLabel对象,可使用QWidget的下列方法:

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

      Context参数可设置为Qt中的枚举变量: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对象。

-- coding: utf-8 --

from PyQt5 import QtCore, QtGui, QtWidgets

class MyLineEdit(QtWidgets.QLineEdit):
def init(self, parent=None):
QtWidgets.QLineEdit.init(self, parent)
self.id = None
def event(self, e):
if e.type() == QtCore.QEvent.Shortcut:
if self.id == e.shortcutId():
self.setFocus(QtCore.Qt.ShortcutFocusReason)
return True
return QtWidgets.QLineEdit.event(self, e)

class MyWindow(QtWidgets.QWidget):
def init(self, parent=None):
QtWidgets.QWidget.init(self, parent)
self.resize(300, 100)
self.label = QtWidgets.QLabel("(&E)设置输入焦点在编辑框1")
self.lineEdit1 = QtWidgets.QLineEdit()
self.label.setBuddy(self.lineEdit1)
self.lineEdit2 = MyLineEdit()
self.lineEdit2.id = self.lineEdit2.grabShortcut(
QtGui.QKeySequence.mnemonic("&D"))
self.button = QtWidgets.QPushButton("(&R)删除编辑框1的输入焦点")
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.label)
self.vbox.addWidget(self.lineEdit1)
self.vbox.addWidget(self.lineEdit2)
self.vbox.addWidget(self.button)
self.setLayout(self.vbox)
self.button.clicked.connect(self.on_clicked)
def on_clicked(self):
self.lineEdit1.clearFocus()

if name == "main":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

除了上面介绍的方式,还可以通过QtWidgets模块中的QShortcut类来实现:

self.lineEdit2 = QtWidgets.QLineEdit()
self.shc = QtWidgets.QShortcut(QtGui.QKeySequence.mnemonic("&D"), self)
self.shc.setContext(QtCore.Qt.WindowShortcut)
self.shc.activated.connect(self.lineEdit2.setFocus)
或者使用QtWidgets模块中的QAction类来实现:
self.lineEdit2 = QtWidgets.QLineEdit()
self.act = QtWidgets.QAction(self)
self.act.setShortcut(QtGui.QKeySequence.mnemonic("&е"))
self.act.triggered.connect(self.lineEdit2.setFocus)
self.addAction(self.act)

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

keyPressEvent(self,event) - 按下某一键时,该方法被调用直到键被释放为止;
keyReleaseEvent(self,event) - 释放之前按下的键时被调用。event参数为QKeyEvent对象,包括事件的相关信息,有以下方法可调用。(详见QKeyEvent文档http://doc.qt.io/qt-5/qkeyevent.html)
key():返回按下键的值;
text():返回按下键的Unicode字符编码信息,当按键为Shift, Control, Alt等时,则该函数返回的字符为空值;
modifiers():判断按下了哪些修饰键(Shift,Ctrl , Alt,等等)。返回值为QtCore.Qt 类以下枚举变量的组合:
    NoModifier - 没有修饰键;
    ShiftModifier - 修饰键;
    ControlModifier - 修饰键;
    AltModifier - 修饰键;
    MetaModifier - 修饰键;
    KeypadModifier - 附加键盘上的任何按键;
    GroupSwitchModifier - 按下键(仅限X11系统)。
isAutoRepeat(): 如果一直按着某键,返回True;否则,返回False;
match(QKeySequence.StandardKey key): 如果当前的键组合与key相同,返回True;否则,返回False. 比如,是否按下了复制快捷键的代码:
if e.matches(QtGui.QKeySequence.Copy):
    print("组合键为 +")

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

控件必须可以设置为输入焦点。有些控件,如QLabel是不能接受输入焦点的。
捕获键盘事件要使用grabKeyboard( )方法,释放时,调用rekeaseKeyboard().
可能拦截除和+以外的任何键。要拦截这两个键,只能在event(self,event)中完成。
如果要让父控件继续收到键盘事件,要调用事件的ignore()方法;否则,调用accept()。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容