小部件失去焦点时如何截取
问题内容:
我有一个QPlainTextEdit,想在内容失去焦点时进行处理。我已经看到我可以使用focusChanged事件或focusOutEvent虚拟函数来执行此操作。
我不知道如何使用新语法传递参数(即本地定义的函数my_app.focusChanged.connect(my_handler)
在哪里my_handler
)。因此,我尝试使用虚函数。
由于使用QT
Designer创建该接口时,继承QPlainTextEdit
会显得过大,因此我尝试通过简单地使用来覆盖虚拟函数my_text_edit.focusOutEvent = my_handler
。这确实拦截了我想要的消息,但显然覆盖了一些内置功能,QPlainTextEdit
并且出现了伪影-
即文本编辑中的光标在失去焦点时不会消失。我认为我应该以某种方式调用原始事件,而对我有用的是:
用我的__init__
方法,我有:
self.original_handler = self.my_text_edit.focusOutEvent
self.my_text_edit.focusOutEvent = self.my_handler
的定义my_handler
是:
def my_handler(self, event):
self.original_handler(event)
# my own handling follows...
我基本上是在复制我希望图书馆为我做的事情。我觉得这太笨拙了,我可以看到它在维护期间如何在许多方面产生适得其反的效果。谁能建议一个更整洁的方法吗?谢谢!
问题答案:
就我个人而言,我从来没有使用覆盖虚拟方法的猴子修补样式,但是保留原始行为的正确方法是直接调用基类方法,如下所示:
def my_handler(self, event):
QtGui.QPlainTextEdit.focusOutEvent(self.my_text_edit, event)
# my own handling follows...
不过,我不明白为什么您不能使用该focusChanged
信号。它的处理程序将简单地是:
def my_handler(self, old, new):
if old is self.my_text_edit:
print('focus out')
elif new is self.my_text_edit:
print('focus in')
但是,我自己的偏好是使用事件过滤器:
class Window(QtGui.QMainWindow)
def __init__(self):
...
self.my_text_edit.installEventFilter(self)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.FocusOut and
source is self.my_text_edit):
print('eventFilter: focus out')
# return true here to bypass default behaviour
return super(Window, self).eventFilter(source, event)
这是一个更加灵活的解决方案,它为处理通过Qt
Designer导入的任何窗口小部件(或者实际上是您不希望子类化的任何窗口小部件)提供一种通用方法来处理任何事件类型。
还可以进行小部件升级,可以用自己的子类直接替换生成的ui模块中的小部件。然后,这将允许您通过继承覆盖任何虚拟方法,而不是通过猴子修补单个实例。如果您要从Qt
Designer导入多个具有相同自定义功能的相同类型的小部件,则可以提供非常干净的解决方案。
我对以下问题的回答提供了有关如何在PyQt中进行小部件升级的简单说明:在运行时替换QWidget对象。