QListWidget is one of the "convenience" classes (like QTreeWidget and QTableWidget). Using them is fine as long as your requirements are quite simple. But as soon as you want something a little more sophisticated, the inflexibility soon begins to show.
You can solve your problems fairly easily by switching to the more generic QListView class with a a QStandardItemModel. This requires a little more work to set up, but it will immediately bring a lot more flexibility.
Here's a demo of that approach based on your sample code:
from PyQt4 import QtGui
class ProductListItem(QtGui.QStandardItem):
def __lt__(self, other):
listview = self.model().parent()
this_widget = listview.indexWidget(self.index())
other_widget = listview.indexWidget(other.index())
return this_widget.getText() < other_widget.getText()
class ProductItemWidget(QtGui.QWidget):
def __init__(self, product_name, parent=None):
super(ProductItemWidget, self).__init__(parent)
self.label = QtGui.QLabel(product_name, self)
layout = QtGui.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.label)
def getText(self):
return self.label.text()
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.list = QtGui.QListView(self)
layout = QtGui.QHBoxLayout(self)
layout.addWidget(self.list)
# model must have the listview as parent
model = QtGui.QStandardItemModel(self.list)
self.list.setModel(model)
for key in 'MHFCLNIBJDAEGK':
item = ProductListItem()
model.appendRow(item)
widget = ProductItemWidget('Item %s' % key, self.list)
self.list.setIndexWidget(item.index(), widget)
model.sort(0)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 150, 300)
window.show()
sys.exit(app.exec_())