3

I want to enable/disable a checkable item in a QTreeWidget, when a specific signal is sent.

The following code dows not 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)

It produces the error:

TypeError: unhashable type: 'PySide.QtGui.QStandardItem'

Is there a solution for changing the state or data of a QStandardItem via signal/slot?

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
leviathan
  • 363
  • 3
  • 10

2 Answers2

3

This looks like a bug in PySide, as connect should accept any callable (the example code works correctly in PyQt4).

As a workaround, try wrapping QStandardItem methods in a lambda:

signalSource.availabilityChanged.connect(
    lambda enable: categoryItem.setEnabled(enable))

EDIT

To connect the items in a loop, use a default argument, like this:

for button in buttonList:
    item = QStandardItem("Test")
    ...
    button.toggled.connect(
        lambda enable, item=item: item.setEnabled(enable))
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
1

With the help of ekhumoros answer, I found a way to get my problem solved, but it seems to be an ugly workaround in PySide, using the sender to get the signal hooked up 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 didn't work in the loop. It just connect all the signal with the last reference to iterate over.

leviathan
  • 363
  • 3
  • 10