Переопределение функций виджетов в PyQT5 и QtDisigner

Я пишу программу на PyQt5 и для построения интерфейса использую Qt Designer. Во время написания логики работы программы, периодически приходится переопределять функции, например "dropEvent" или "mouseMoveEvent". И тут я столкнулся с проблемой, которая связана с тем, что после переведения .ui файла в .py, используются неизменённые классы, то есть весь интерфейс построен из дефолтных классов.
Но, для того что бы заработали переопределённые функции, я должен заменить все экземпляры классов виджетов на экземпляры классов с переопределёнными функциями.

Таким образом я должен либо менять автоматически сгенерированный код, либо полностью его дублировать и заменять нужные мне классы. Недостаточно просто повторно создать нужный мне экземпляр класса с именем из автоматически сгенерированного файла, так как он должен пройти все преобразования, которые следуют за его созданием, по этому надо копировать практически весь автоматически сгенерированный код.

С моей точки зрения такой подходи кажется крайне неудобным, и скорее всего есть более правильный и удобный способ работать с переопределёнными функциями.

Каким образом лучше всего это сделать, так чтобы каждый раз не дублировать код или не исправлять автоматически созданный код?

Для наглядности привожу пример, в котором переопределены функции для классов QPushButton и QFrame:

from PyQt5 import QtCore, QtGui, QtWidgets

class MyButton(QtWidgets.QPushButton):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)


    def mouseMoveEvent(self, e):
        mimeData = QtCore.QMimeData()

        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())

        dropAction = drag.exec_(QtCore.Qt.MoveAction)


class MyFrame(QtWidgets.QFrame):
    def __init__(self, parent):
        super(MyFrame, self).__init__(parent)

    def dragEnterEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        position = e.pos()
        e.source().setParent(self)
        e.source().move(position)
        e.source().show()

        e.setDropAction(QtCore.Qt.MoveAction)
        e.accept()

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(1051, 800)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalFrame = QtWidgets.QFrame(Dialog)
        self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
        self.horizontalFrame.setObjectName("horizontalFrame")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.pushButton_3 = QtWidgets.QPushButton(self.horizontalFrame)
        self.pushButton_3.setObjectName("pushButton_3")
        self.horizontalLayout_6.addWidget(self.pushButton_3)
        self.pushButton_2 = QtWidgets.QPushButton(self.horizontalFrame)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_6.addWidget(self.pushButton_2)
        self.pushButton = QtWidgets.QPushButton(self.horizontalFrame)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_6.addWidget(self.pushButton)
        self.verticalLayout.addWidget(self.horizontalFrame)
        self.horizontalFrame_2 = QtWidgets.QFrame(Dialog)
        self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
        self.horizontalFrame_2.setObjectName("horizontalFrame_2")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.verticalLayout.addWidget(self.horizontalFrame_2)
        self.horizontalFrame_3 = QtWidgets.QFrame(Dialog)
        self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
        self.horizontalFrame_3.setObjectName("horizontalFrame_3")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout.addWidget(self.horizontalFrame_3)

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

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.pushButton_3.setText(_translate("Dialog", "PushButton"))
        self.pushButton_2.setText(_translate("Dialog", "PushButton"))
        self.pushButton.setText(_translate("Dialog", "PushButton"))
class Playground_widget(Ui_Dialog):
    def __init__(self,  Dialog, stacked_widget_general=None, stack_dict_general=None):
        super(Playground_widget, self).__init__()
        self.setupUi(Dialog)

        self.horizontalFrame.setAcceptDrops(True)
        self.horizontalFrame_2.setAcceptDrops(True)
        self.horizontalFrame_3.setAcceptDrops(True)

    def setupUi_reload(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(1051, 800)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalFrame = MyFrame(Dialog)
        self.horizontalFrame.setStyleSheet(
            "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
        self.horizontalFrame.setObjectName("horizontalFrame")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.pushButton_3 = MyButton(self.horizontalFrame)
        self.pushButton_3.setObjectName("pushButton_3")
        self.horizontalLayout_6.addWidget(self.pushButton_3)
        self.pushButton_2 = MyButton(self.horizontalFrame)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_6.addWidget(self.pushButton_2)
        self.pushButton = MyButton(self.horizontalFrame)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_6.addWidget(self.pushButton)
        self.verticalLayout.addWidget(self.horizontalFrame)
        self.horizontalFrame_2 = MyFrame(Dialog)
        self.horizontalFrame_2.setStyleSheet(
            "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
        self.horizontalFrame_2.setObjectName("horizontalFrame_2")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.verticalLayout.addWidget(self.horizontalFrame_2)
        self.horizontalFrame_3 = MyFrame(Dialog)
        self.horizontalFrame_3.setStyleSheet(
            "background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
        self.horizontalFrame_3.setObjectName("horizontalFrame_3")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout.addWidget(self.horizontalFrame_3)

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

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.pushButton_3.setText(_translate("Dialog", "PushButton"))
        self.pushButton_2.setText(_translate("Dialog", "PushButton"))
        self.pushButton.setText(_translate("Dialog", "PushButton"))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Playground_widget(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

Ответы (1 шт):

Автор решения: S. Nick

Встраивание пользовательских виджетов в Qt Designer посмотрите здесь

После преобразования .ui файла в .py, создайте другой класс, который наследуется от соответствующего виджета, и используйте созданный класс для его заполнения.

В конечном виде вы прийдете к следующему решению:

from PyQt5 import QtCore, QtGui, QtWidgets


class MyButton(QtWidgets.QPushButton):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def mouseMoveEvent(self, e):
        mimeData = QtCore.QMimeData()
        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())
        #print(f'class MyButton(QPushButton):{e.pos()} - {self.rect().topLeft()}') 
        dropAction = drag.exec_(QtCore.Qt.MoveAction)


class MyFrame(QtWidgets.QFrame):
    def __init__(self, parent):
        super(MyFrame, self).__init__(parent)

    def dragEnterEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        position = e.pos()
        e.source().setParent(self)
        e.source().move(position)
        e.source().show()

        e.setDropAction(QtCore.Qt.MoveAction)
        e.accept()


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(1051, 800)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        
#        self.horizontalFrame = QtWidgets.QFrame(Dialog)
        self.horizontalFrame = MyFrame(Dialog)                            # !!! +++  
        
        self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
        self.horizontalFrame.setObjectName("horizontalFrame")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        
#        self.pushButton_3 = QtWidgets.QPushButton(self.horizontalFrame)
        self.pushButton_3 = MyButton(self.horizontalFrame)                # !!! +++
        
        self.pushButton_3.setObjectName("pushButton_3")
        self.horizontalLayout_6.addWidget(self.pushButton_3)
        
#        self.pushButton_2 = QtWidgets.QPushButton(self.horizontalFrame)
        self.pushButton_2 = MyButton(self.horizontalFrame)                # !!! +++

        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_6.addWidget(self.pushButton_2)
#        self.pushButton = QtWidgets.QPushButton(self.horizontalFrame)
        self.pushButton = MyButton(self.horizontalFrame)                  # !!! +++
        
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_6.addWidget(self.pushButton)
        
        self.verticalLayout.addWidget(self.horizontalFrame)
        
#        self.horizontalFrame_2 = QtWidgets.QFrame(Dialog)                # !!! +++
        self.horizontalFrame_2 = MyFrame(Dialog)       
        
        self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
        self.horizontalFrame_2.setObjectName("horizontalFrame_2")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.verticalLayout.addWidget(self.horizontalFrame_2)
        
#        self.horizontalFrame_3 = QtWidgets.QFrame(Dialog)
        self.horizontalFrame_3 = MyFrame(Dialog)                          # !!! +++
        
        self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
        self.horizontalFrame_3.setObjectName("horizontalFrame_3")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout.addWidget(self.horizontalFrame_3)

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

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.pushButton_3.setText(_translate("Dialog", "PushButton 3"))
        self.pushButton_2.setText(_translate("Dialog", "PushButton 2"))
        self.pushButton.setText(_translate("Dialog", "PushButton"))
        
# -----------------------------> vvvvvvv, vvvvvvvvv   # <----------------
class PlayGroundWidget(QtWidgets.QDialog, Ui_Dialog):
    def __init__(self):
        super(PlayGroundWidget, self).__init__()
        
        self.setupUi(self)
        
        self.horizontalFrame.setAcceptDrops(True)
        self.horizontalFrame_2.setAcceptDrops(True)
        self.horizontalFrame_3.setAcceptDrops(True)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    
#    Dialog = QtWidgets.QDialog()
#    ui = Playground_widget(Dialog)
#    Dialog.show()
    
    w = PlayGroundWidget()                                                # !!! +++
    w.show()                                                              # !!! +++
    sys.exit(app.exec_())

введите сюда описание изображения

введите сюда описание изображения

→ Ссылка