Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign thumb or icon to QListView Item while using .model

Tags:

python

qt

pyqt

The code below creates a single QListView with three items. This QListView gets populated via its .model's. Without using the model I could go ahead and do something like this:

view=QtGui.QListWidget()
item=QtGui.QListWidgetItem()
item.setText('Item Name')
icon=QtGui.QIcon('/Volumes/path/to/file.jpg')
item.setIcon(icon)
view.addItem(item) 

But with `.model' in use there are no items available (the indexes instead). Please advise.

enter image description here

    import os,sys
    from PyQt4 import QtCore, QtGui
    app=QtGui.QApplication(sys.argv)
    elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}

    class Model(QtCore.QAbstractListModel):
        def __init__(self):
            QtCore.QAbstractListModel.__init__(self)
            self.items=[] 
            self.modelDict={} 
        def rowCount(self, parent=QtCore.QModelIndex()):
            return len(self.items)
        def data(self, index, role):
            if not index.isValid() or not (0<=index.row()<len(self.items)):  return QtCore.QVariant()
            if role==QtCore.Qt.DisplayRole:      return self.items[index.row()]
        def addItems(self):
            for key in self.modelDict:
                index=QtCore.QModelIndex()
                self.beginInsertRows(index, 0, 0)
                self.items.append(key)      
            self.endInsertRows()        

    class ListView(QtGui.QListView):
        def __init__(self):
            super(ListView, self).__init__()
            self.model= Model()
            self.model.modelDict=elements
            self.model.addItems()
            self.setModel(self.model)
            self.show()        

    window=ListView()
    sys.exit(app.exec_())

EDIT: Thanks to Jeffrey for a detailed explanation!


The code below is revised fully working version of the one posted earlier. Basically we have to supply model with the data requested. The actual icon "assignment" will be handled by the model itself. We only need to make sure the request for icon happens under correct if Role==x scope. The icons should be requested/returned in if DecorationRole portion of .data() method. There are other roles available: Qt.DisplayRole, Qt.TextAlignmentRole, Qt.TextColorRole, Qt.BackgroundColorRole, Qt.ItemDataRole, Qt.UserRole and etc)

enter image description here

import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}

icon=QtGui.QIcon('C:\\myIcon.png')

class Model(QtCore.QAbstractListModel):
    def __init__(self):
        QtCore.QAbstractListModel.__init__(self)
        self.items=[] 
        self.modelDict={}       

    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self.items)

    def data(self, index, role):
        if not index.isValid() or not (0<=index.row()<len(self.items)):  return QtCore.QVariant()
        if role==QtCore.Qt.DisplayRole:
            return self.items[index.row()]
        elif role==QtCore.Qt.DecorationRole:
            return icon

    def addItems(self):
        for key in self.modelDict:
            index=QtCore.QModelIndex()
            self.beginInsertRows(index, 0, 0)
            self.items.append(key)      
        self.endInsertRows()        

class ListView(QtGui.QListView):
    def __init__(self):
        super(ListView, self).__init__()
        self.model= Model()
        self.model.modelDict=elements
        self.model.addItems()
        self.setModel(self.model)
        self.show()        

window=ListView()
sys.exit(app.exec_()) 
like image 634
alphanumeric Avatar asked Nov 28 '25 04:11

alphanumeric


1 Answers

First off, you'll need Model.data to be able to return a QIcon (or QPixmap, if that's more convenient) when the role passed in is DecorationRole. With this current code, it'll return None, which not only doesn't do what you want, is actually invalid. If it doesn't know how to deal with the passed role, it should return an invalid QVariant (like you do on the first line of the method). PyQt is probably smart enough to handle None properly, though.

Secondly, you already appear to be using the QModelIndex correctly. You can just have the icon be another field attached to the model itself that you access similarly. QListWidgetItem is simply a convenience class, and there's nothing stopping you from encapsulating all of the data associated with a row in a similar class that you stash on the model (like you're already doing with the DisplayRole data) and access via the QModelIndex.row().

Something like this:

def data(self, index, role):
    if not index.isValid() or not (0 <= index.row() < len(self.items)):
        return QtCore.QVariant()
    if role == QtCore.Qt.DisplayRole:
        return self.items[index.row()]
    if role == QtCore.Qt.DecorationRole:
        return self.icons[index.row()]
    return QtCore.QVariant()

Although I'd personally recommend having a dict whose values contain both the DisplayRole and DecorationRole data as fields on a class.

I don't know off-hand if a QListView will request the DecorationRole from the model by default. You might need to set the iconSize property on the list view, or similar. These are all the changes you need to make to the model itself, though.

like image 99
Jeffrey Pfau Avatar answered Nov 29 '25 19:11

Jeffrey Pfau



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!