Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement itemChecked and itemUnchecked signals for QTreeWidget in PyQt4?

Where are the signals itemChecked and itemUncheсked on the QTreeWidget?

Qt Signals: (quote from PyQt4 QTreeWidget documentation page)

void currentItemChanged (QTreeWidgetItem *,QTreeWidgetItem *)
void itemActivated (QTreeWidgetItem *,int)
void itemChanged (QTreeWidgetItem *,int)
void itemClicked (QTreeWidgetItem *,int)
void itemCollapsed (QTreeWidgetItem *)
void itemDoubleClicked (QTreeWidgetItem *,int)
void itemEntered (QTreeWidgetItem *,int)
void itemExpanded (QTreeWidgetItem *)
void itemPressed (QTreeWidgetItem *,int)
void itemSelectionChanged ()

At current moment I solved it like this:

self.treeWidget.itemClicked.connect (self.handle)

def handle (item, column): 
    print 'emitted!', item.text(column)
    if item.checkState(column) == QtCore.Qt.Checked:
        # there are a lot of my functions inside which work with item data
        self.handleChecked(item, column)
    elif item.checkState(column) == QtCore.Qt.Unchecked:
        self.handleUnchecked(item, column)

But it's a bad solution for me, because itemClicked emitted in a really lot of cases. It emitted in the case of Left/Right Mouse Clicks on the item text, which is absolutely unnecessary (I have heavy functions within self.handleChecked, and unnecessary calls of them on the context menu opening are pretty lousy).

Well, I also tried to use itemChanged:

self.treeWidget.itemChanged.connect (self.handle)

but this way situation is even worse! self.handle function calls himself recursively to infinity and beyond, because my functions within self.handleChecked change item data and this signal emits again and again. Also, I need signal which emits only on item checkbox toggling.

Can someone tell me, what I'm doing wrong?

like image 690
Bruno Gelb Avatar asked Dec 01 '12 17:12

Bruno Gelb


1 Answers

To avoid problems with recursion when using the itemChanged signal, try temporarily blocking signals until the handler has completed:

def handle(self, item, column):
    self.treeWidget.blockSignals(True)
    if item.checkState(column) == QtCore.Qt.Checked:
        self.handleChecked(item, column)
    elif item.checkState(column) == QtCore.Qt.Unchecked:
        self.handleUnchecked(item, column)
    self.treeWidget.blockSignals(False)

UPDATE

The other part of your question asked about emitting a signal only when an item is checked.

One way to do this would be to subclass QTreeWidgetItem and reimplement it's setData function:

class TreeWidgetItem(QtGui.QTreeWidgetItem):
    def setData(self, column, role, value):
        state = self.checkState(column)
        QtGui.QTreeWidgetItem.setData(self, column, role, value)
        if (role == QtCore.Qt.CheckStateRole and
            state != self.checkState(column)):
            treewidget = self.treeWidget()
            if treewidget is not None:
                treewidget.itemChecked.emit(self, column)

class Window(QtGui.QTreeWidget):
    itemChecked = QtCore.pyqtSignal(object, int)

    def __init__(self, rows, columns):
        QtGui.QTreeWidget.__init__(self)
        self.itemChecked.connect(self.handleItemChecked)

    def handleItemChecked(self, item, column):
        print 'ItemChecked', int(item.checkState(column))
like image 62
ekhumoro Avatar answered Sep 17 '22 08:09

ekhumoro