PyQt:从QWidget双重继承时崩溃

时间:2019-07-03 20:21:21

标签: python pyqt pyqt5 qwidget

PyQt5,Qt 5.9.6发生以下问题。

我想基于另一个类(Dialog)生成模式对话框类(UserForm)。但是,如果UserForm已经继承自QWidget,则我的脚本会引发异常

  

“对话框”对象没有属性“ exec _”

或者只是默默崩溃或在控制台中崩溃并显示消息:

  

QDialog :: exec:检测到递归调用

如果UserForm是否从QWidget继承,则MRO看起来完全相同:

(<class '__main__.Dialog'>, <class '__main__.UserForm'>, <class
'PyQt5.QtWidgets.QDialog'>, <class 'PyQt5.QtWidgets.QWidget'>, <class
'PyQt5.QtCore.QObject'>, <class 'sip.wrapper'>, <class
'PyQt5.QtGui.QPaintDevice'>, <class 'sip.simplewrapper'>, <class 'object'>)

示例:

from PyQt5 import QtWidgets
app = QtWidgets.QApplication([])

class UserForm(QtWidgets.QWidget):
    pass

# class Dialog(UserForm, QtWidgets.QDialog):
#     pass
Dialog = type("Dialog", (UserForm, QtWidgets.QDialog), {})

print(Dialog.__mro__)
Dialog().exec_()

我还尝试使用Qt 5.12的PySide2运行此代码,它可以正常工作。这是否意味着PyQt中存在一些错误?

1 个答案:

答案 0 :(得分:2)

相反,这是PySide2的错误,因为它与docs相矛盾:

  

多重继承要求QObject首先出现

     

如果您正在使用   多重继承,moc假定第一个继承的类是   QObject的子类。另外,请确保只有第一个继承的类   是一个QObject。

如果考虑到上一部分中描述的行为,则Dialog类应仅考虑UserForm而不考虑QDialog,因此Dialog不应具有exec_()方法,因为只有从QDialog继承的类才可以拥有它。 >

  • 在Qt中,您不应该从2个QObject继承,仅支持混合(QObject +不支持QObject)(1)(2)

  • 如果是mixin,则第一个必须是QObject。

这就是pyuic继承的模式:

from PyQt5 import QtCore, QtGui, QtWidgets
# or
# from PySide2 import QtCore, QtGui, QtWidgets

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 300)
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(30, 240, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(
            QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok
        )
        self.buttonBox.setObjectName("buttonBox")

        self.retranslateUi(Dialog)
        self.buttonBox.accepted.connect(Dialog.accept)
        self.buttonBox.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

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


def init(self, parent=None):
    super(self.__class__, self).__init__(parent)
    self.setupUi(self)

# or
# class Dialog(QtWidgets.QDialog, Ui_Dialog):
#    def __init__(self, parent=None):
#        super(Dialog, self).__init__(parent)
#        self.setupUi(self)

Dialog = type("Dialog", (QtWidgets.QDialog, Ui_Dialog), {"__init__": init})

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    Dialog().exec_()

(1)Multiple Inheritance
(2)Cooperative Multi-inheritance