在 QtDesigner 生成的小部件中捕获事件

Catching events within QtDesigner generated widget

我正在尝试制作一个允许使用鼠标操作 QGraphicsView/QGraphicScene 中的某些对象(添加、移动、调整大小等)的应用程序。 UI 是从 QtDesigner 生成的。 我用谷歌搜索的所有示例都显示鼠标事件是从主应用程序 class 中处理的。但是,如果有更多处理鼠标事件的小部件,我认为将鼠标逻辑单独保留在这些小部件中是明智的。 我试图通过单独的 class 遵循 建议,但由于我的小部件是由设计师生成的,它似乎不起作用。

我的设计师生成的代码:

# Created by: PyQt5 UI code generator 5.13.0

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.DesignWindowView = QtWidgets.QGraphicsView(self.centralwidget)
        self.DesignWindowView.setGeometry(QtCore.QRect(20, 20, 761, 501))
        self.DesignWindowView.setObjectName("DesignWindowView")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

主文件:

import sys
from PyQt5 import QtWidgets, uic, QtGui, QtCore
from Ui_MainWindow import Ui_MainWindow

class DesignWindowView(QtWidgets.QGraphicsView):

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            print("Press on DesignWindowView!")

    def mouseMoveEvent(self, event):
        print("Mouse on DesignWindowView")

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, *args, obj=None, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        DesignWindowScene = QtWidgets.QGraphicsScene()
        DesignWindowScene.addSimpleText("The Text")
        self.DesignWindowView.setScene(DesignWindowScene)
        self.DesignWindowView.setCursor(QtCore.Qt.CrossCursor)
        self.setMouseTracking(True)
        self.DesignWindowView.setMouseTracking(True)

        self.show()

app = QtWidgets.QApplication(sys.argv)
# load MainWindow design
mainwindow = MainWindow()
# start the UI's event loop
app.exec_()

DesignWindowView class 将负责从 QtDesigner 生成的 worwidget,但这显然不起作用并且 none 鼠标事件被捕获。 我没有任何 OOP 经验,也不完全理解 subclassing 的概念(因为我认为这是应该完成的方式)。

事件没有被捕获的原因是因为在从QtDesigner 文件生成的.py 文件中,self.DesignWindowView 仍然是一个QtWidgets.QGraphicsView 对象。解决方案是将 Qt Designer 中的 QtWidgets.QGraphicsView 提升为 DesignerWindowView 对象。

为此,最好将 DesignerWindowView 的定义放在一个单独的 .py 文件中(例如 designerwindowview.py),以防止主 .py 文件和 .py 文件之间的循环依赖从 QtDesigner 文件生成的 .py 文件。

在设计器中,右键单击要推广的小部件并选择 Promote to ...。填写提升的 class 名称 (DesignerWindowView)。对于头文件的名称,您应该使用提升的 class 的定义填写 .py 文件的名称,不带 .py 扩展名(例如 designerwindowview)。

像以前一样保存并 运行 到 pyuic5。在生成的 .py 文件中 self.DesignWindowView 现在应该是一个 DesignWindowView 对象,并且在 .py 文件的底部应该有一个类似于 from designwindowview import DesignWindowView 的导入语句。