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()。

推荐阅读更多精彩内容