【问题标题】:How to pass an extra arguments to PyQt slot?如何将额外的参数传递给 PyQt 插槽?
【发布时间】:2016-02-16 13:14:53
【问题描述】:


大家好。我正在 Windows 7 中使用 python3.4 和 PyQt5 制作简单的模型/视图应用程序

首先,这是我的代码。

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QListView
from PyQt5.Qt import QStandardItemModel, QStandardItem

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.list = QListView(self)

        model = QStandardItemModel(self.list)

        carMaker = ['Ford', 'GM', 'Renault', 'VW', 'Toyota']

        for maker in carMaker:
            item = QStandardItem(maker)
            item.setCheckable(True)
            model.appendRow(item)
        self.list.setModel(model)

        model.itemChanged.connect(self.on_item_changed)
        #model.itemChanged.connect(functools.partial(self.on_item_changed, item, 1))
        #model.itemChanged.connect(lambda: self.on_item_changed(item, 2))

        self.list.setMinimumSize(300, 300)
        self.setWindowTitle("Simple modelView")
        self.show()

    def on_item_changed(self, item):
        print(item.text())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

这很好用。但我想用 'itemChanged' 信号添加额外的参数。所以,我使用了 lambda 和 functools

  1. λ

    • 从 'def on_item_changed(self, item)' 更改为 'def on_item_changed(self, item, num)'
    • 从 'model.itemChanged.connect(self.on_item_changed)' 更改为 'model.itemChanged.connect(lambda: self.on_item_changed(item, 1))'
    • 没有错误。但“item.text()”只显示“丰田”。 (可能是最后一个项目模型)
  2. functools.partial

    • 从 'def on_item_changed(self, item)' 更改为 'def on_item_changed(self, item, num)'
    • 从 'model.itemChanged.connect(self.on_item_changed)' 更改为 'model.itemChanged.connect(functools.partial(self.on_item_changed, item, 1))'
    • 没有错误。但“item.text()”只显示“丰田”。 (可能是最后一个项目模型)与 lambda 的结果相同。


问题是……

  1. 我不知道为什么 lambda 和 functools 显示错误的文本。

  2. 是否有任何有效的方法可以通过信号传递额外的参数?

感谢您阅读我的问题。

【问题讨论】:

    标签: python-3.x pyqt pyqt4 pyqt5


    【解决方案1】:

    回答你的第一个问题,functools.partiallambda 函数使用的问题在于,当你将信号连接到插槽时,变量item 被设置并且它引用了最后一个QStandardItem您在QStandardItemModel 中添加。所以基本上你处于这种情况:

    def initUI(self):
        self.list = QListView(self)
        model = QStandardItemModel(self.list)
        carMaker = ['Ford', 'GM', 'Renault', 'VW', 'Toyota']
    
        for maker in carMaker:
            item = QStandardItem(maker) # here you create a item variable that is overwritten
            item.setCheckable(True)     # on every iteration of the for loop
            model.appendRow(item)
    
        self.list.setModel(model)
    
        # here you use again the item variable (the same applies for lambda)
        model.itemChanged.connect(functools.partial(self.on_item_changed, item, 1))
    

    它打印“Toyota”的原因仅仅是因为它是carMaker 列表中的最后一个元素,所以它是最后一个创建的QStandardItem,因此item 变量引用了这个对象。

    要回答第二个问题,您可以使用QStandardItemsetData() 方法在项目中存储您需要的一些数据,然后使用data() 检索它们。

    import sys
    
    from PyQt5.QtCore import pyqtSlot, Qt
    from PyQt5.QtWidgets import QApplication, QWidget, QListView
    from PyQt5.QtGui import QStandardItemModel, QStandardItem
    
    class Example(QWidget):
    
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
    
            self.list = QListView(self)
            model = QStandardItemModel(self.list)
            carMaker = ['Ford', 'GM', 'Renault', 'VW', 'Toyota']
            index = 0 # just to store something different for each QStandardItem
    
            for maker in carMaker:
                item = QStandardItem(maker)
                item.setCheckable(True)
                item.setData(index, Qt.UserRole + 1)
                model.appendRow(item)
                index += 1
    
            self.list.setModel(model)
    
            model.itemChanged.connect(self.on_item_changed)
    
            self.list.setMinimumSize(300, 300)
            self.setWindowTitle("Simple modelView")
            self.show()
    
        @pyqtSlot('QStandardItem')
        def on_item_changed(self, item):
            print("%s - %s" % (item.text(), item.data(Qt.UserRole + 1)))
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    

    或者,您可以使用here 所述的信号映射器。

    【讨论】:

    • 谢谢 Daniele Pantaleone!你提出了很好的解决方案。但是您的代码结果看起来有问题。 'item.data()' 只显示无。不是增量数字。你能教我为什么吗?
    • 我已将 'item.setData(index, Qt.userRole) 更改为 'item.setData(index, Qt.userRole + 1)' 和 item.data(Qt.UserRole + 1)。这按我的预期工作。现在,很清楚什么是 setData()、data()、Qt.UserRole。再次感谢。 Daniele Pantaleone。
    • 感谢您关注此问题。我会用更正来更新我的答案,以防其他人需要它;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 2020-03-12
    • 2018-10-07
    • 1970-01-01
    • 2020-03-15
    • 2022-01-10
    相关资源
    最近更新 更多