代码之家  ›  专栏  ›  技术社区  ›  Dennis Miller

PyQt:在基类中重写mousepresessevent方法时,将mousepresessevent传递给原始小部件

  •  0
  • Dennis Miller  · 技术社区  · 6 年前

    我正在尝试为小部件创建一个全局上下文帮助系统。其中所有小部件都可以用ContextHelpBase类进行扩展,并具有向Context Help Display小部件发送信号所需的所有逻辑。

    其思想是,当用户单击小部件时,它将显示一些上下文帮助。所以我超载了 mousePressEvent 发送一个信号,但是现在正常的按钮和QComboBox行为不起作用,因为我假设我在重写它之后没有将信号传递给正常的事件处理程序。

    from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QPushButton, QComboBox, QHBoxLayout, QVBoxLayout
    from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
    
    class ContextHelpSignals(QObject):
        """ Used to send signals globally through the application
            Eventually will be a Global Singelton
        """
        textHelp = pyqtSignal(str)
    
        def __init__(self):
            super(ContextHelpSignals, self).__init__()
    
    #Eventually will be a Global Singleton
    _contextHelp = ContextHelpSignals()
    
    class ContextHelpBaseClass(QObject):
        """All Widget that have context help inherits this class"""
        def __init__(self, **kw):
            super(ContextHelpBaseClass, self).__init__()
            self.helpText = None
    
        def mousePressEvent(self, event):
            """ THIS DISABLE WIDGETS NORMAL CLICK BEHAVIOR """
            _contextHelp.textHelp.emit(self.helpText)
            # How can emit a signal and then pass this event to the normal widget
            print(type(super()))
    
        def SetHelpText(self, helpText):
            self.helpText = helpText
    
    class ContexHelpDisplay(QLabel):
        """Dislpay Context Help frow widgets that have Context Help"""
        def __init__(self, text):
            super(ContexHelpDisplay, self).__init__()
            self.setText(text)
            _contextHelp.textHelp.connect(self.__displayHelp)
            # Need to pass event to original widget
            # type.mousePresseEvent() - How do I get type?
    
        @pyqtSlot(str)
        def __displayHelp(self, contextHelpText):
            self.setText(contextHelpText)
    
    class ContextHelpButton(QPushButton, ContextHelpBaseClass):
        """QPush Button with Context Help"""
        def __init__(self, text):
            super(ContextHelpButton, self).__init__()
            self.setText(text)
            self.helpText = "This is QPushButton Context Help Text"
    
    ## It would be nice if I could use a Python Decorator, but
    ## don't know how yet.
    ## @ContextHelp
    class ContextHelpComboBox(QComboBox, ContextHelpBaseClass):
        """QPush Button with Context Help"""
        def __init__(self):
            super(ContextHelpComboBox, self).__init__()
            self.helpText = "This is QComboBox Context Help Text"
    
    class MainWindow(QWidget):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent=parent)
            self.setupUI()
    
        def setupUI(self):
            self.resize(250, 150)
            self.setWindowTitle('Context Help Example')
            self.show()
    
            button = ContextHelpButton("Test Button")
    
            comboBox = ContextHelpComboBox()
            comboBox.addItem("Test Item 1")
            comboBox.addItem("Test Item 2")
            comboBox.addItem("Test Item 3")
    
            helpTextDisplay = ContexHelpDisplay("Context Help")
    
            vBox = QVBoxLayout()
            vBox.addWidget(button)
            vBox.addWidget(comboBox)
    
            hBox = QHBoxLayout()
            hBox.addLayout(vBox)
            hBox.addWidget(helpTextDisplay)
    
            self.setLayout(hBox)
    
    if __name__ == "__main__":
        app = QApplication([])
        ex = MainWindow()
        exit(app.exec_())
    

    主要问题 :

    其他问题 :

    1. 对于Python装饰器,这可能吗
    2. 有没有更好的设计模式更适合这种情况?
    3 回复  |  直到 6 年前
        1
  •  0
  •   S. Nick    6 年前

    @eyllanesc所说的可能是这样的:

    from PyQt5.QtWidgets import (QApplication, QLabel, QWidget, QPushButton, 
                                 QComboBox, QHBoxLayout, QVBoxLayout)
    from PyQt5.QtCore    import QObject, pyqtSignal, pyqtSlot,  QEvent, Qt
    
    
    class ContextHelpSignals(QObject):
        """ Used to send signals globally through the application
            Eventually will be a Global Singelton                """
        textHelp = pyqtSignal(str)
    
        def __init__(self):
            super(ContextHelpSignals, self).__init__()
    
    
    # Eventually will be a Global Singleton
    _contextHelp = ContextHelpSignals()
    
    
    class ContextHelpBaseClass(QObject):   
        """ All Widget that have context help inherits this class """
        def __init__(self, **kw):
            super(ContextHelpBaseClass, self).__init__()
            self.helpText = None
    
        def mousePressEvent(self, event):
            ''' THIS DISABLE WIDGETS NORMAL CLICK BEHAVIOR '''
            _contextHelp.textHelp.emit(self.helpText)
            # How can emit a signal and then pass this event to the normal widget
            print(type(super()))
    
        def SetHelpText(self, helpText):              # ???
            self.helpText = helpText
    
    
    class ContexHelpDisplay(QLabel):
        """Dislpay Context Help frow widgets that have Context Help"""
        def __init__(self, text):
            super(ContexHelpDisplay, self).__init__()
            self.setText(text)
            _contextHelp.textHelp.connect(self.__displayHelp)
            # Need to pass event to original widget
            # type.mousePresseEvent() - How do I get type?
    
        @pyqtSlot(str)
        def __displayHelp(self, contextHelpText):
            self.setText(contextHelpText)
    
    class ContextHelpButton(QPushButton, ContextHelpBaseClass):
        """QPush Button with Context Help"""
        def __init__(self, text):
            super(ContextHelpButton, self).__init__()
            self.setText(text)
            self.helpText = "This is <b>QPushButton</b> Context Help Text"
    
    
    class ContextHelpComboBox(QComboBox):             # - --> , ContextHelpBaseClass):
        """QPush Button with Context Help"""
        def __init__(self):
            super(ContextHelpComboBox, self).__init__()
            self.helpText = "This is <b>QComboBox</b> Context Help Text"
    
    
    class MainWindow(QWidget):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent=parent)
            self.setupUI()
    
        def setupUI(self):
            self.resize(250, 150)
            self.setWindowTitle('Context Help Example')
            self.show()
    
            button = ContextHelpButton("Test Button")
    
            self.comboBox = ContextHelpComboBox()     # + self.
            self.comboBox.addItem("Test Item 1")
            self.comboBox.addItem("Test Item 2")
            self.comboBox.addItem("Test Item 3")
    
            self.comboBox.installEventFilter(self)    # <- Installs an event filter filterObj on this object. 
    
            self.helpTextDisplay = ContexHelpDisplay("Context Help")
    
            vBox = QVBoxLayout()
            vBox.addWidget(button)
            vBox.addWidget(self.comboBox)
    
            hBox = QHBoxLayout()
            hBox.addLayout(vBox)
            hBox.addWidget(self.helpTextDisplay)
            self.setLayout(hBox)
    
        # Filters events if this object has been installed as an event filter for the watched object.
        def eventFilter(self, obj, event):
            if event.type() == QEvent.MouseButtonPress and obj is self.comboBox:
                self.helpTextDisplay.setText(self.comboBox.helpText)
            return super(MainWindow, self).eventFilter(obj, event)
    
    
    if __name__ == "__main__":
        app = QApplication([])
        ex  = MainWindow()
        exit(app.exec_())
    

    enter image description here

        2
  •  0
  •   Dennis Miller    6 年前

    作为后续工作,我通过在基类中存储子类的引用,然后使用该引用传递事件,实现了我想要的目标。

    from PyQt5.QtWidgets import (QApplication, QLabel, QWidget, QPushButton,
                                 QComboBox, QHBoxLayout, QVBoxLayout)
    from PyQt5.QtCore    import QObject, pyqtSignal, pyqtSlot
    
    class ContextHelpSignals(QObject):
        """ Used to send signals globally through the application
            Eventually will be a Global Singleton                """
        textHelp = pyqtSignal(str)
    
        def __init__(self):
            super(ContextHelpSignals, self).__init__()
    
    # Eventually will be a Global Singleton
    _contextHelp = ContextHelpSignals()
    
    class ContexHelpDisplay(QLabel):
        """Display Context Help from widgets that have Context Help"""
        def __init__(self, text):
            super(ContexHelpDisplay, self).__init__()
            self.setText(text)
            _contextHelp.textHelp.connect(self.__displayHelp)
    
        @pyqtSlot(str)
        def __displayHelp(self, contextHelpText):
            self.setText(contextHelpText)
    
    class ContextHelpBaseClass(QObject):
        """ All Widget that have context help inherits this class """
        def __init__(self, childObject):
            super(ContextHelpBaseClass, self).__init__()
            self.helpText = None
            self.childObject = childObject
            print( type(childObject) )
    
        def mousePressEvent(self, event):
            _contextHelp.textHelp.emit(self.helpText)
            # Pass mouse click event to native widget
            self.childObject.mousePressEvent(event)
    
    class ContextHelpButton(QPushButton, ContextHelpBaseClass):
        """QPush Button with Context Help"""
        def __init__(self, text):
            super(ContextHelpButton, self).__init__(self)
            self.setText(text)
            self.helpText = "This is <b>QPushButton</b> Context Help Text"
    
        def test(self):
            print("BUTTON")
    
    class ContextHelpComboBox(QComboBox, ContextHelpBaseClass):
        """QPush Button with Context Help"""
        def __init__(self):
            super(ContextHelpComboBox, self).__init__(self)
            self.helpText = "This is <b>QComboBox</b> Context Help Text"
    
        def test(self):
            print("Combo Box")
    
    class MainWindow(QWidget):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent=parent)
            self.setupUI()
    
        def setupUI(self):
            self.resize(250, 150)
            self.setWindowTitle('Context Help Example')
            self.show()
    
            button = ContextHelpButton("Test Button")
    
            comboBox = ContextHelpComboBox()
            comboBox.addItem("Test Item 1")
            comboBox.addItem("Test Item 2")
            comboBox.addItem("Test Item 3")
    
            helpTextDisplay = ContexHelpDisplay("Context Help")
    
            button.clicked.connect(button.test)
    
            vBox = QVBoxLayout()
            vBox.addWidget(button)
            vBox.addWidget(comboBox)
    
            hBox = QHBoxLayout()
            hBox.addLayout(vBox)
            hBox.addWidget(helpTextDisplay)
            self.setLayout(hBox)
    
    if __name__ == "__main__":
        app = QApplication([])
        ex  = MainWindow()
        exit(app.exec_())
    
        3
  •  0
  •   Dennis Miller    6 年前

    from PyQt5.QtWidgets import (QApplication, QLabel, QWidget, QPushButton,
                                 QComboBox, QHBoxLayout, QVBoxLayout)
    from PyQt5.QtCore    import QObject, pyqtSignal, pyqtSlot
    
    def ContextHelp(text):
        """Decorates a class by adding mousePressEvent method"""
        def AddMouseClickEventDecorator(_class):
            """ Adds 'mousePressEvent()' method to class"""
            def mousePressEvent(self, event):
                _contextHelp.textHelp.emit(text)       #Emit a signal to global ContextHelp Singleton
                super(_class, self).mousePressEvent(event) #Call Widget Base Class event
    
            #Add 'mousePressEvent' to _class
            setattr(_class, 'mousePressEvent', mousePressEvent)
            return _class #Decorated class
        return AddMouseClickEventDecorator
    
    
    
    class ContextHelpSignals(QObject):
        """ Used to send signals globally through the application
            Eventually will be a Global Singleton                """
        textHelp = pyqtSignal(str)
    
        def __init__(self):
            super(ContextHelpSignals, self).__init__()
    
    # Eventually will be a Global Singleton
    _contextHelp = ContextHelpSignals()
    
    class ContexHelpDisplay(QLabel):
        """Display Context Help from widgets that have Context Help"""
        def __init__(self, text):
            super(ContexHelpDisplay, self).__init__()
            self.setText(text)
            _contextHelp.textHelp.connect(self.__displayHelp)
    
        @pyqtSlot(str)
        def __displayHelp(self, contextHelpText):
            self.setText(contextHelpText)
    
    @ContextHelp("This is a push button")
    class ContextHelpButton(QPushButton):
        """QPush Button with Context Help"""
        def __init__(self, text):
            super(ContextHelpButton, self).__init__()
            self.setText(text)
    
    @ContextHelp("This is Combo Box")
    class ContextHelpComboBox(QComboBox):
        """QPush Button with Context Help"""
        def __init__(self):
            super(ContextHelpComboBox, self).__init__()
    
    
    class MainWindow(QWidget):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent=parent)
            self.setupUI()
    
        def setupUI(self):
            self.resize(250, 150)
            self.setWindowTitle('Context Help Example')
            self.show()
    
            button = ContextHelpButton("Test Button")
    
            comboBox = ContextHelpComboBox()
            comboBox.addItem("Test Item 1")
            comboBox.addItem("Test Item 2")
            comboBox.addItem("Test Item 3")
    
            helpTextDisplay = ContexHelpDisplay("Context Help")
    
            button.clicked.connect(self.TestButton)
    
            vBox = QVBoxLayout()
            vBox.addWidget(button)
            vBox.addWidget(comboBox)
    
            hBox = QHBoxLayout()
            hBox.addLayout(vBox)
            hBox.addWidget(helpTextDisplay)
            self.setLayout(hBox)
    
        def TestButton(self):
            print("Button Pressed.")
    
    if __name__ == "__main__":
        app = QApplication([])
        ex  = MainWindow()
        exit(app.exec_())