使用 uic.loadUI() 在 PyQt5 中重新定义(覆盖)方法

Redefine (override) methods in PyQt5 with uic.loadUI()

几周以来,我实际上正在使用 PyQt5 和 QtDesigner 开发一个小型软件。我看了很多教程并在 SO 上寻找了许多答案,但我找不到关于使用 uic.loadUI().

覆盖 QWidget 方法的方法的答案

请注意,我已尽可能简化我的测试代码以准确指出我的问题所在:

1/ 这个不起作用,它加载我的 file.ui 正确但点击没有做任何事情:

import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QWidget

class Window(QWidget):
    def __init__(self):
        super().__init__() # Or QWidget.__init__(self)
        self.dlg = uic.loadUi("file.ui")
        self.dlg.show()

    def mousePressEvent(self, event):
        print("click !")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    app.exec_()

2/ 但我发现那个确实有效:

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setWindowTitle("My window")
        self.show()

    def mousePressEvent(self, event):
        print("click !")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    app.exec_()

据我所知,这似乎是因为我无法覆盖事件的方法。由于 mousePressEvent 不是附加到我的 QWidget 子类的方法 self.dlg.

现在我知道为什么了,我想知道如何重写 mousePressEvent 方法并使用它。我想知道 'loading' 重写后的方法,或者调用 QWidget 方法重新定义它,或者简单地创建我自己的方法来捕获任何事件,但我尝试的一切都完全失败了。

无论如何,提前感谢您的回答/提示/祈祷。

假设您在创建 file.ui 时使用的是 Widget 模板:

那么解决方法如下:

import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QWidget

class Window(QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi("file.ui", self)
        self.show()

    def mousePressEvent(self, event):
        print("click !")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    app.exec_()

为什么在使用时不起作用 self.dlg = uic.loadUi("file.ui")因为正如你指出的那样创建了小部件is self.dlg 这仍然是从未显示的胜利 window 的属性,在 uic.loadUi("file.ui", self) 的情况下,您指出它不会创建 window 但会填充现有的 window

更新:

根据你得到的错误:

TypeError: ('Wrong base class of toplevel widget', (<class '__main__.Window'>, 'QMainWindow'))

这让我推断你没有使用QWidget作为基础,而是QMainWindow,所以Window必须继承自QMainWindow:

import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("file.ui", self)
        self.show()

    def mousePressEvent(self, event):
        print("click !")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    app.exec_()

我的方法是在 Qt Designer 对象检查器中使用 Promote to... 上下文菜单条目。

这允许您在设计器中指定特定的小部件应该使用您在图形构建器中推动的内容的子classes。 uic.loadUi会遵守的。

假设您在 my_graphics_view.py 中有一个 MyGraphicsView。您可以放置​​一个 QGraphicsView,然后是 select Promote to... 并输入以下内容:

  • 基本 class 名称:(预填至 QGraphicsView
  • 晋级 class 姓名:MyGraphicsView
  • 头文件:my_graphics_view.hloadUi会为您调整扩展名)

...然后点击“添加”,然后点击“推广”,您就完成了。

我只注意到两个注意事项:

  1. 据我所知,在子部件树之前使用 uic.loadUi__init__ returns 时没有 setupUi 方法已经构建,所以如果你想 运行 __init__ 之后的任何自定义代码,你必须将它放在一个名称类似于 widget.configure_children() 的方法中,并在调用 [=26= 之后自己调用它].

  2. 由于我不知道的原因,我正在使用的来自 Kubuntu Linux 16.04 LTS 的 Qt Designer 5.5.1 的副本在“升级”对话框中不提供 QMainWindow已知小部件的下拉菜单。

    但是,如果您编辑 .ui 文件,Qt Designer 和 loadUi 都不会出现问题。它似乎正是它看起来的样子......下拉小部件的一个神秘遗漏,仅此而已。

这是它在原始 .ui 文件中的样子:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
  <class>MainWindow</class>
  <widget class="MyMainWindow" name="MainWindow">
    <!-- ... --->
  </widget>
  <customwidgets>
    <customwidget>
      <class>MyMainWindow</class>
      <extends>QMainWindow</extends>
      <header>my_main_window.h</header>
    </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
</ui>

同样重要的是要注意,根据 this page,相当于 uic.loadUi 的 PySide2 将父级作为第二个参数而不是自定义子 class,所以你'在 PySide2 下基本上被迫使用这种方法。