mah*_*tah 4 python qt pyqt5 pyside6
我正在将 pyqt5 GUI 移植到 pyside6,但遇到了一个我不明白的问题。
我有两个 QSpinbox,它们控制两个 GUI 参数:一个 Spinbox 控制拆分器的重量,另一个控制 QtableView 中的行高。
这是pyqt5中的代码:
spinbox1.valueChanged.connect(my_splitter.setHandleWidth)
spinbox2.valueChanged.connect(my_view.verticalHeader().setDefaultSectionSize)
Run Code Online (Sandbox Code Playgroud)
在 Pyside6 spinbox1 工作正常,但 spinbox2 没有完成其工作,并且有此警告:
您无法在源自 C++ 的对象上添加动态槽。
将第二行代码修改为:
spinbox2.valueChanged.connect(lambda x: my_view.verticalHeader().setDefaultSectionSize(x))
Run Code Online (Sandbox Code Playgroud)
很高兴找到解决方案,但我还想了解为什么两个连接在 PySide6 中表现不同以及为什么使用 lambda 可以解决问题。
警告消息可能提供了线索,但我不知道动态插槽是什么(快速谷歌对我没有多大帮助)。
编辑: 由于我更改了两件事:Qt5 > QT6 和 pyqt > pyside 我在 4 个 python 包装器(pyqt5、pyqt6、pyside2、pyside6)中查看了这一点,以了解哪些更改导致了问题。我可以看出 pyside 2 和 6 都显示了这种行为,并且 pyqt 都没有
看起来 PySide(或者更准确地说,Shiboken,允许 Python 访问 Qt 对象的包装器)无法直接连接到 Qt 直接创建的对象的插槽。
这似乎是一个 PySide 错误:PyQt 没有显示该行为,这意味着完全有可能实现它。
PyQt 有时也会发生类似的行为,但这只是在非常特殊的情况下:对于Qt 直接创建的对象的受保护方法。例如,尝试调用initStyleOption()项目视图的默认委托会引发RuntimeError(“无法访问不是从 Python 创建的对象的受保护函数或信号”)。
尽管如此,对于像这样的公共职能来说,这种情况不setDefaultSectionSize()应该发生。
不过,有一些可能的解决方法。
正如您已经发现的,您可以只使用 lambda。这将强制 PySide 连接到 python 函数而不是 Qt 函数:PySide 始终允许这种连接。
这种方法的缺点是 lambda 的常见问题:如果直接使用它作为参数connect(),则完全失去对它的任何引用,因此无法专门断开与该函数的连接,除非您断开该信号的所有函数(或整个物体)。
不过,可以参考 Lambda:
header = my_view.verticalHeader()
header.setDefaultSectionSize_ = lambda s: header.setDefaultSectionSize(s)
spinbox2.valueChanged.connect(header.setDefaultSectionSize_)
Run Code Online (Sandbox Code Playgroud)
使用上面的代码,您可以断开该函数的连接,因为您现在拥有对该函数的持久引用。
这与上面的类似,不同之处在于我们创建一个特定的方法来处理这个问题,假设您保留对标头(或者更好的是视图)的引用:
spinbox2.valueChanged.connect(self.updateMyViewSectionSize)
def updateMyViewSectionSize(self, size):
self.my_view.verticalHeader().setDefaultSectionSize(size)
Run Code Online (Sandbox Code Playgroud)
它可能有点冗长,但它也是一种更好的方法,因为它考虑了函数的动态性质,verticalHeader() 并提供了对在其他情况下可能需要调用的函数的公共访问。
这是我通常用于解决上述委托问题的一个技巧:每当我需要根据其从委托获取一些信息时initStyleOption(),我只需创建一个新的“虚拟”委托;由于它是用Python创建的,所以不再出现这个问题。
对于这种情况也同样适用:创建并设置一个虚拟标题视图。
my_view.setVerticalHeader(QHeaderView(Qt.Vertical, my_view))
Run Code Online (Sandbox Code Playgroud)
请注意,方向和参数都是强制性的,并且上述操作应始终尽快完成(在创建表格小部件之后)。
我仍然建议您在Qt bug tracker中提交一份报告,希望他们能够至少为 PySide6 修复它(PySide2 可能会被忽略,但你永远不知道)。