How to enable / disable an item in a QTreeView based event?
I want to enable / disable a checked item in a QTreeWidget when a certain signal is sent.
The following code doesn't work:
model = QStandardItemModel() view = QTreeView() view.setModel(model) rootItem = QStandardItem() rootItem = model.invisibleRootItem() categoryItem = QStandardItem(item) categoryItem.setCheckable(True) rootItem.appendRow(categoryItem) signalSource.availabilityChanged.connect(categoryItem.setEnabled)
Gives an error message:
TypeError: unhashable type: 'PySide.QtGui.QStandardItem'
Is there a solution to change the state or data of a QStandardItem via a signal / slot?
source to share
This looks like a bug in PySide as it connect
should accept any callables (the sample code works correctly in PyQt4).
As a workaround, try wrapping the methods QStandardItem
in lambda:
signalSource.availabilityChanged.connect(
lambda enable: categoryItem.setEnabled(enable))
EDIT
To connect items in a loop, use the default argument, for example:
for button in buttonList:
item = QStandardItem("Test")
...
button.toggled.connect(
lambda enable, item=item: item.setEnabled(enable))
source to share
With the help of ekhumoros answer, I found a way to solve my problem, but it seems to be an ugly workaround in PySide using the sender to connect the signal correctly.
import sys
import argparse
import signal
#import sip
#sip.setapi('QString', 2)
#from PyQt4.QtGui import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QStandardItemModel, QStandardItem, QTreeView
from PySide.QtGui import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QStandardItemModel, QStandardItem, QTreeView
class MainWindow(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
buttonList = []
for i in xrange(10):
button = QPushButton("1")
button.setCheckable(True)
buttonList.append(button)
model = QStandardItemModel()
view = QTreeView()
view.setModel(model)
layout = QVBoxLayout()
self.setLayout(layout)
buttonLayout = QHBoxLayout()
layout.addLayout(buttonLayout)
for button in buttonList:
buttonLayout.addWidget(button)
layout.addWidget(view)
rootItem = QStandardItem()
rootItem = model.invisibleRootItem()
self.itemList = {}
for button in buttonList:
item = QStandardItem("Test")
item.setCheckable(True)
rootItem.appendRow(item)
self.itemList[button] = item
# Works with PyQt4, but not with PySide
#button.toggled.connect(item.setEnabled)
# Workaround for PySide
button.toggled.connect(self.workaround)
for button in buttonList:
button.setChecked(True)
def workaround(self, enable):
self.itemList[self.sender()].setEnabled(enable)
def main(argv):
app = QApplication(argv)
w = MainWindow()
w.show()
retcode = app.exec_()
if __name__ == "__main__":
main(sys.argv)
Just using a lambda construct doesn't work in a loop. It just hooks up the whole signal with the last link to repeat.
source to share