我有一个使用pyqt5制作的小GUI应用程序。我发现一个奇怪的问题,而使用eventFilter…
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress:
# RETURN
if event.key() == QtCore.Qt.Key_Return:
if source is self.userLineEdit:
self.pswLineEdit.setFocus()
elif source is self.pswLineEdit:
self.LoginButton.click()
# TAB
elif event.key() == QtCore.Qt.Key_Tab:
if source is self.userLineEdit:
self.pswLineEdit.setFocus()
return super().eventFilter(source, event)
按回车键正常,tab键不正常。我不知道问题出在哪里。我将链接一个视频来展示具体的问题因为我无法描述它是如何不起作用的
视频链接我知道它有像素化(抱歉)但重要的是光标
的行为<标题>小例子import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit
from PyQt5 import QtCore
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Hello, world!'
self.left = 10
self.top = 10
self.width = 640
self.height = 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.userEdit = QLineEdit(self)
self.pswEdit = QLineEdit(self)
self.userEdit.setPlaceholderText("Username")
self.pswEdit.setPlaceholderText("Password")
self.userEdit.installEventFilter(self)
self.pswEdit.installEventFilter(self)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.userEdit)
mainLayout.addWidget(self.pswEdit)
self.setLayout(mainLayout)
self.show()
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress:
# RETURN
if event.key() == QtCore.Qt.Key_Return:
if source is self.userEdit:
self.pswEdit.setFocus()
# TAB
elif event.key() == QtCore.Qt.Key_Tab:
if source is self.userEdit:
self.pswEdit.setFocus()
return super().eventFilter(source, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
标题>如果不过滤事件,它们将由对象处理并最终传播回父对象。
默认情况下,QWidget将尝试通过调用其focusNextPrevChild()
来聚焦焦点链中的下一个(或前一个,对于Shift+Tab)子部件。如果它可以这样做,它实际上会将焦点设置在该小部件上,否则该事件将被忽略并传播到父组件。
由于大多数小部件(包括QLineEdit)不处理tab键的焦点变化自己,因为他们没有孩子,他们的父将接收它,这将调用focusNextPrevChild()
寻找另一个子小部件,等等,直到一个小部件最终可以处理键,最终改变焦点。
在你的例子中,是这样发生的:
- 您检查事件,发现tab键事件被第一行编辑接收;
- 将焦点设置在其他行编辑,密码字段;
- 你让事件无论如何由小部件处理,因为你没有忽略或过滤它;
- 第一行编辑调用
focusNextPrevChild()
,但不能用它做任何事情; - 事件被传播到父进程,然后父进程调用自己的
focusNextPrevChild()
; - 函数检查当前聚焦的子部件,这是您刚刚聚焦的密码字段,并找到下一个,碰巧是第一行编辑,它再次聚焦;
简单的解决方案是在更改焦点后添加return True
,这样事件就不会传播到父节点,从而导致进一步的焦点更改:
if event.key() == QtCore.Qt.Key_Tab:
if source is self.userEdit:
self.pswEdit.setFocus()
return True
请注意,重写焦点行为是相当复杂的,您必须非常小心如何处理焦点和事件,特别是对于可能以特定方式处理事件的特定小部件(研究Qt源代码对此非常有用),否则您将得到意想不到的行为甚至致命的递归。
例如,通常不需要返回键的事件过滤器,因为QLineEdit已经提供了returnPressed
信号:
self.userEdit.returnPressed.connect(self.pswEdit.setFocus)
Qt已经有一个相当彻底的焦点管理系统,如果你只是想更多地控制选项卡链的工作方式,使用现有的功能,如父窗口或顶层窗口的setTabOrder()
,如果你想更多地控制如何(或如果)他们得到它,使用setFocusPolicy()
。