Question

I subclassed a QListWidget (named List) which has a pyqtSignal named dataChanged that is emitted in another baseclass DataWidget. Actually everything works, but

if the methods setForeground or setTooltip of an item (QListWidgetItem) in the List are called, I get this

TypeError: native Qt signal is not callable

message. Another pyqtSignal named itemLeft of the List class if emitted not in a baseclass but in the List class itself and does not have the problem.

So, what I'd like to know is:

  • Why does this message appear when calling a method of a listitem?
    How come calling a method is related to that signal?!
  • What is wrong with the code? / What do I need to change?

Here is a MWE to reproduce it.

from __future__ import print_function
import sys
from PyQt4.QtGui import (QMainWindow, QApplication, QFormLayout, QListWidget,
                         QListWidgetItem, QColor)
from PyQt4.QtCore import pyqtSignal

class DataWidget(object):
    """ A widget to drop data """
    def dropEvent(self, event):
        """ Emits the dataChanged signal """
        # actions to be taken on drop
        self.dataChanged.emit()

class List(QListWidget, DataWidget):
    """ List widget used for, e. g. features  """
    # This signal makes no problems
    itemLeft = pyqtSignal()
    # but this one does
    dataChanged = pyqtSignal()

    def __init__(self, parent):
        super(List, self).__init__(parent)
        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.setSortingEnabled(True)

    def leaveEvent(self, event):
        self.itemLeft.emit()


class ApplicationWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        # The ListWidget
        self.list = List(self)
        self.setCentralWidget(self.list)

        self.list.itemLeft.connect(self.doOnItemLeft)
        self.list.dataChanged.connect(self.doOnDrop)

        # Adding an item to self.list
        item = QListWidgetItem('List Item Name', self.list)

        textcolor, tooltip = QColor(), None
        textcolor.setRgb(50, 50, 115)
        tooltip = 'Tool tip'
        # Calling following methods gives causes
        # TypeError: native Qt signal is not callable
        print('calling: QListWidgetItem.setForeground() for', str(item.text()))
        item.setForeground(textcolor)
        print('calling: QListWidgetItem.setToolTip() for', str(item.text()))
        item.setToolTip(tooltip)

    def doOnItemLeft(self):
        # make gui adaptions...
        print('Widget left')

    def doOnDrop(self):
        # get data from widget and so on...
        pass

app = QApplication(sys.argv)
win = ApplicationWindow()

win.show()
sys.exit(app.exec_())

Version

>>> PyQt4.pyqtconfig.Configuration().pyqt_version_str
'4.9.6'
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=5, releaselevel='final', serial=0)
Was it helpful?

Solution

As Vahancho and Osterfeld identified, the issue is that QListWidget inherits from QAbstractItemView, which defines a protected slot called "dataChanged": the slot is called when items are changed in the model, thereby allowing the derived class (QListWidget in this case) to take action.

Hence creating a signal of the same name does not make sense. Calling methods setForeground or setTooltip on the list item causes the slot to be called, only the slot has been overridden by a signal, leading to the observed error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top