首页 > 解决方案 > 从 Qt4 更新到 Qt5 后,selectionChanged 和我的 pyQtSlot 之间的 connect() 失败

问题描述

我最近参与了一个使用 PyQt 的项目。它使用的是 Qt4,但由于在最新系统上安装它以及所有其他工具和包的痛苦,我决定将所有内容更新到 Python3、Qt5 等。

在旧代码中,

self.selectionModel().selectionChanged.connect(self.selection_changed_event)

有效且有效。

@QtCore.pyqtSlot("QTreeView, QItemSelection, QItemSelection")
    def selection_changed_event(self, selected, deselected):
        """Event handler.
        Triggered by TreeView selection change.
        Get Title from selected/deselected items. Send SelectionEvent(title) to widgets to show/hide content as needed.
        :param selected: New selected item.
        :param deselected: Item that was selected.
        :return:
    """

自从更新到 Qt5,现在说 connect() 失败了。虽然我是个菜鸟,但我的理解是我确实想检索视图selectionModel然后连接到它的selectionChanged信号。所以我应该有self.ITEM.selectionModel().selectionChanged.connect(self.SLOT). 在插槽内,它似乎符合标准,我应该有QModelIndex告诉在活动期间选择了QModelIndex什么以及告诉在活动期间取消选择了什么。

因此,我对此所做的唯一其他值得注意的更改是从 QTGui 切换到 QtWidget。这是由于 QtGui 和 QtWidget 从 Qt4 到 Qt5 的转变。

老的:

class QMenuTreeView(QtGui.QTreeView):
    selectionChangeEvent = QtCore.pyqtSignal(str)
    def __init__(self, parent=None, log=None):
        QtGui.QTreeView.__init__(self, parent)
        self.parent = parent
        ...
        self.selectionModel().selectionChanged.connect(self.selection_changed_event)

新的:

class QMenuTreeView(QtWidgets.QTreeView):
    selectionChangeEvent = QtCore.pyqtSignal(str)
    def __init__(self, parent=None, log=None):
        QtWidgets.QTreeView.__init__(self, parent)
        self.parent = parent
        ...             
        self.selectionModel().selectionChanged.connect(self.selection_changed_event)

Qt4 和 QT5 之间是否还有其他我不理解的变化,并且会导致这种情况?看来我不能使用 QtGui,因为对 QTreeView 的引用不再有效,此外,它现在在他们的文档中列为 QtWidgets。还有什么我需要转换的,还是这个 connect() 问题与其他问题有关?

标签: python-3.xpyqt5pyqt4qwidgetqtreeview

解决方案


pyqtSlot语法似乎是错误的(即使对于 PyQt4):签名不应包含视图的类,因为它不是信号的一部分。
它在 PyQt4 上工作的原因是,在那个版本中,插槽装饰器语法和类型检查不如 PyQt5 严格。

考虑到,在正常情况下,应该不需要插槽装饰器(特别是对于“通用”小部件和不处理线程时),所以我会立即删除装饰器,至少通过评论它。

然后,如果实际需要该特定要求,则语法应为:

    @QtCore.pyqtSlot(QtCore.QItemSelection, QtCore.QItemSelection)
    def selection_changed_event(self, selected, deselected):
        # ...

请注意,没有引号,它们仅在 PyQt 不提供类型并且插槽无论如何都需要它们(例如,QStringList)的非常特定的情况下需要。此外,参数的串联不应同一字符串内。

这被正确调用并打印两个选择(请注意:

    @pyqtSlot('QItemSelection', 'QItemSelection'):
    def test(self, selected, deselected):
        print(selected, deselected)

这引发了一个异常,因为插槽只识别第一种类型,但函数需要两种:

    @pyqtSlot('QItemSelection, QItemSelection')
    def test(self, selected, deselected):
        print(selected, deselected)

最后,这是可行的,但只给出了第一个参数:

    @pyqtSlot('QItemSelection, QItemSelection')
    def test(self, *args):
        print(args)

推荐阅读