Question

After working with QListWidget and other 'listing' widgets I've finally arrived to what seems to be an easy solution to store and retrieve the List's Item classes (QListWidgetItem). The problem I was introducing to my self was behind the fact that I thought the QListWidgetItem could only be used to store its label name (the one used to display in ListWidget). By the time QListWidget was populated with QListWidgetItems I had to declare a dictionary where each key would be a label name of the item and a value would be equal to the object itself (dangerous approach since two or more items could have the same name while dictionaries can only have a single key with the same name). Then when an item would be clicked I would capture that List Item label (name) and look through the dictionary's keys to find a corresponding object. All these could be easily avoided if I declare my own custom myItem() class which inherits from QListWidgetItem. Now when a List Item clicked I can get object from it directly just like I call .getTime() method. Please let me know if I am missing or misunderstanding anything before committing to using this approach in my code.

from PyQt4 import QtGui, QtCore
import sys, os


class myItem(QtGui.QListWidgetItem):
    def __init__(self, name):
        super(myItem, self).__init__()
        self.name=name
    def getTime(self):
        import datetime
        return datetime.datetime.now()   

class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidget = QtGui.QListWidget()

        self.listWidget.currentItemChanged.connect(self.item_clicked)

        for i in range(12):
            name='Item '+str(i)
            my_item=myItem(name)
            my_item.setText('Item '+str(i))
            self.listWidget.addItem(my_item)

        myBoxLayout.addWidget(self.listWidget)

    def item_clicked(self, arg=None):
        print arg.text(), arg.getTime()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(480,320)
    sys.exit(app.exec_())
Was it helpful?

Solution

You can set user data of a QListWidgetItem via QListWidgetItem.setData (self, role, value).

You can specify your own roles and thus add specific data directly to this widget.

To retrieve the data, use QListWidgetItem.data (self, role) with the correct role.

OTHER TIPS

Thanks! Here is an attempt. First assigning myObject:

my_item.setData (QtCore.Qt.UserRole, myObject)

Then on click, getting it back with:

myObject = arg.data(QtCore.Qt.UserRole)

The resulted myObject on item_clicked is . Where is the mistake?

from PyQt4 import QtGui, QtCore
import sys, os


class MyClass(object):
    def __init__(self):
        super(MyClass, self).__init__()
    def getTime(self):
        import datetime
        return datetime.datetime.now()         


class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidget = QtGui.QListWidget()

        self.listWidget.currentItemChanged.connect(self.item_clicked)

        for i in range(12):
            name='Item '+str(i)
            my_item=QtGui.QListWidgetItem()
            my_item.setText('Item '+str(i))
            self.listWidget.addItem(my_item)

            myObject=MyClass()
            my_item.setData (QtCore.Qt.UserRole, myObject)

        myBoxLayout.addWidget(self.listWidget)

    def item_clicked(self, arg=None):
        myObject = arg.data(QtCore.Qt.UserRole)
        print dir(myObject)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(480,320)
    sys.exit(app.exec_())

I went one-by-one trying each of QVariant methods that starts with 'to':

'toBool', 'toByteArray', 'toChar', 'toDate', 'toDateTime', 'toDouble', 'toEasingCurve', 'toFloat', 'toHash', 'toInt', 'toLine', 'toLineF', 'toList', 'toLocale', 'toLongLong', 'toMap', 'toModelIndex', 'toPoint', 'toPointF', 'toPyObject', 'toReal', 'toRect', 'toRectF', 'toRegExp', 'toSize', 'toSizeF', 'toString', 'toStringList', 'toTime', 'toUInt', 'toULongLong', 'toUrl', 'toUuid'

and I found that toPyObject() returns exactly the same Object (in an example below it is MyClass() instance) stored in a List Item at the time it was created using:

        myObject=MyClass()            
        my_item.setData(QtCore.Qt.UserRole, myObject)

Here is the code that works for me. Please correct me if I am wrong here.

from PyQt4 import QtGui, QtCore
import sys, os

class MyClass(object):
    def __init__(self):
        super(MyClass, self).__init__()
    def getTime(self):
        import datetime
        return datetime.datetime.now()         

class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidget = QtGui.QListWidget()

        self.listWidget.currentItemChanged.connect(self.item_clicked)

        for i in range(12):
            name='Item '+str(i)
            my_item=QtGui.QListWidgetItem()
            my_item.setText('Item '+str(i))
            self.listWidget.addItem(my_item)

            myObject=MyClass()            
            my_item.setData(QtCore.Qt.UserRole, myObject)

        myBoxLayout.addWidget(self.listWidget)

        Button_01 = QtGui.QPushButton("Get Items")
        Button_01.clicked.connect(self.getListItemsFromQListWidget)               
        myBoxLayout.addWidget(Button_01)

    def item_clicked(self, arg=None):
        myObject = arg.data(QtCore.Qt.UserRole)
        print myObject.toPyObject().getTime()

    def getListItemsFromQListWidget(self):
        for i in range(self.listWidget.count()):
            print self.listWidget.item(i).data(QtCore.Qt.UserRole).toPyObject().getTime()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(480,320)
    sys.exit(app.exec_())

Here is a working implementation of same concept (storing data in Qt items). This time used with ComboBox:

from PyQt4 import QtGui, QtCore
import sys, os

class MyClass(object):
    def __init__(self):
        super(MyClass, self).__init__()
        self.myAttr=None
    def getTime(self):
        import datetime
        return datetime.datetime.now() 

class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.ComboBox = QtGui.QComboBox() 
        for i in range(12):
            name='Item '+str(i)
            myObject=MyClass()
            self.ComboBox.addItem( name, myObject )

        self.ComboBox.currentIndexChanged.connect(self.combobox_selected)
        myBoxLayout.addWidget(self.ComboBox)

    def combobox_selected(self, index):
        myObject=self.ComboBox.itemData(index).toPyObject()
        print myObject.getTime()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(480,320)
    sys.exit(app.exec_())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top