Reputation: 493
Hello everyone. I am making simple model/view application using python3.4 and PyQt5 in Windows 7.
First of all, here is my code.
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_())
This works fine. But I want to add extra arguments with 'itemChanged' signal. So, I've used lambda and functools
lambda
functools.partial
The questions are...
I don't know why lambda and functools shows wrong text.
Is any effective way to pass an extra args with signal?
Thank you for read my question.
Upvotes: 2
Views: 4844
Reputation: 2733
To answer your first question, the problem with functools.partial
and lambda
function usage lies in the fact the when you connect the signal to the slot, the variable item
is set and it references the last QStandardItem
you added in the QStandardItemModel
. So basically you are in this situation:
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))
The reason why it prints "Toyota" is simply the fact that it's the last element in the carMaker
list, so it's the last QStandardItem
created, hence the item
variable references this very object.
To answer the second question instead, you can make use of the setData()
method of QStandardItem
to store some data you need in the item, and then retrieve them using 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_())
Alternatively you can make use of a signal mapper as described here.
Upvotes: 4