# code#1import sysfrom PyQt5.QtWidgets import QApplication, QPushButtondef onResize(event): print("Nice to get here!")if __name__ == "__main__": app = QApplication(sys.argv) widget = QPushButton('Test') widget.resize(640, 480) widget.show() widget.resizeEvent = onResize sys.exit(app.exec_())在此代码#1中永远不会触发新的resizeEvent(当我手动调整窗口大小时)。# code#2import sysfrom PyQt5.QtWidgets import QApplication, QPushButtondef onResize(event): print("Nice to get here!")if __name__ == "__main__": app = QApplication(sys.argv) widget = QPushButton('Test') widget.resize(640, 480) widget.resizeEvent = onResize widget.show() sys.exit(app.exec_())在代码2中很好地触发了新的resizeEvent(当我手动调整窗口大小时)。而且我可以看到味精打印出来。有人知道原因吗?即使我在代码#1的widget.update()之后添加widget.show()和widget.resizeEvent = onResize,resizeEvent代码也保持沉默... 最佳答案 resizeEvent是一种“虚拟保护”方法,并且这样的方法不应被“覆盖”。为了以安全的方式实现它们,您最好使用子类化:class MyButton(QtWidgets.QPushButton): def resizeEvent(self, event): print("Nice to get here!")虚方法是大多数用于子类的函数。当子类调用该方法时,它将首先在其类方法中查找。如果存在该方法,则将调用该方法,否则将遵循MRO(如Method Resolution Order中所述):简单地说,“遵循从类返回其继承的步骤,并在找到该方法时停止”。注意:在Python中,除了“魔术方法”(“ dunder方法”,用双下划线括起来的内置方法,如__init__)外,几乎所有东西都是虚拟的。使用像PyQt这样的绑定,事情变得更加复杂,“猴子补丁”(完全依赖于Python的虚拟特性)变得比以前更加不直观。在您的情况下,继承遵循以下路径:[python对象]Qt对象QtWidget.QWidgetQtWidget.QAbstractButtonQtWidget.QPushButton因此,当您创建QPushButton('Test')(调用其__init__(self, *args, **kwargs))时,路径将被反转:__init__()一个QtWidget.QPushButton,其中新实例作为第一个参数,后跟“ test”参数;QPushButton调用继承的QAbstractButton类__init__(self, text),该类获取实例之后的第一个参数作为按钮文本;QAbstractButton将调用其“某些”方法或QWidget的方法以进行大小提示,字体管理等。等等...以相同的方式,每当调用yourButton.resizeEvent时,路径将被反转:寻找QtWidget.QPushButton.resizeEvent寻找QtWidget.QAbstractButton.resizeEvent...SIP(创建用于为Qt生成python绑定的工具)对虚拟机使用缓存,一旦找到虚拟[继承的]函数,将来会在另一个Qt函数需要时调用该函数。这意味着,一旦未找到python覆盖并且方法查找成功,则从那时起将始终使用该方法,除非明确调用(在python代码中使用“ self.resizeEvent()”)。调用show()之后,QEvent.Resize(它是一个虚拟的本身)会收到一个QWidget.event()。如果event()没有被覆盖,则将调用基类实现,该实现将查找类resizeEvent函数,并以事件作为参数进行调用。由于此时您尚未覆盖它,因此PyQt将回退到默认的小部件resizeEvent函数,从那时起,它将始终使用该函数(根据上面的列表和QPushButton实现,它将是基本的通话)。在您的第二个示例中,在重写QWidget.resizeEvent函数之后调用show(),允许resizeEvent函数“查找”它(从而忽略其基本实现以及继承的类中定义的那些实现),并将使用您的直到程序退出。同样,在这种情况下,由于SIP / Qt将不再使用缓存,因此该方法可以再次被覆盖。请记住,这是一个微妙的但仍然非常重要的区别:从这一刻起,您可以确定要被覆盖的实例(注意粗体字符)方法,只要您确定它从未被调用过即可。def onResize1(event): print("Nice to get here!")def onResize2(event): print("Can you see me?")def changeResizeEvent(widget, func): widget.resizeEvent = funcif __name__ == "__main__": app = QApplication(sys.argv) widget = QPushButton('Test') widget.resize(640, 480) # change the resize event function *before* it might be called changeResizeEvent(widget, onResize1) widget.show() # change the function again after clicking widget.clicked.connect(lambda: changeResizeEvent(widget, onResize2)) sys.exit(app.exec_())根据经验,在Qt官方文档中看到的所有标记为event()的内容通常都需要一个子类才能正确覆盖它。您可以在virtual/protected定义的右侧看到“ [virtual protected]”文本,并且该功能也在Protected Function列表中。PS:使用PyQt,某些级别的猴子修补程序也可以与类一起使用(这意味着您可以覆盖将由其子类自动继承的类方法),但这不能保证并且它们的行为通常是意外的,特别是由于跨平台的性质Qt。它主要取决于类,其内部C ++行为和继承以及SIP与原始C ++对象的关系。关于python - 小部件调用show()后,resizeEvent不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58995898/
10-09 19:46