当窗口小部件失去焦点时,我如何拦截

时间:2014-09-24 16:17:37

标签: python qt pyside

我有一个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...

我基本上复制了我期望图书馆为我做的事情。我发现这太笨拙了,我可以看到它在维护过程中会以多种方式适得其反。任何人都可以建议一个更简洁的方法吗?谢谢!

1 个答案:

答案 0 :(得分:6)

就个人而言,我从不使用覆盖虚拟方法的猴子修补方式,但保留原始行为的正确方法是直接调用基类方法,如下所示:

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')

但是,我自己的偏好是使用event filter

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导入的小部件event type(或者,实际上,任何你不想要的小部件)子类)。

还有widget promotion的可能性,它可以用来直接用你自己的子类替换生成的ui模块中的小部件。这将允许您通过继承覆盖任何虚拟方法,而不是猴子修补单个实例。如果要从Qt Designer导入多个相同类型的小部件,这些小部件共享许多自定义功能,这可以提供非常干净的解决方案。

在PyQt中如何进行小部件推广的简单解释可以在我的答案中找到:Replace QWidget objects at runtime