如何将额外的参数传递给 PyQt 插槽?

How to pass an extra arguments to PyQt slot?


大家好。我正在使用 python3.4 和 Windows 7.

中的 PyQt5 制作简单的 model/view 应用程序

首先,这是我的代码。

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()' 只显示 'Toyota'。 (也许是最后一个项目模型)
  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()' 只显示 'Toyota'。 (可能是最后一项模型)与 lambda 相同的结果。


问题是...

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

  2. 有什么有效的方法可以通过信号传递额外的参数吗?

感谢您阅读我的问题。

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

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 所述。