Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct
Populating a ListView with Python Objects
-
I want to populate a ListView with objects from Python. I've been able to make a ListView work using ListModel+ ListElement in QML but not from Python. From what I've read, it seems I should use a QAbstractListModel but so far I haven't been able to get the values of the python objects to show up. It seems my QAbstractListModel's rowCount() and data() functions don't even get called.
I posted a (hopefully) lean example in a GitLab project
What am I missing?
Thanks,
-chris
-
I cannot speak to your QML code specifically but you are using PyQt4 syntax within your example
This
sys.exit(app.exec_())
is either just thisapp.exec()
or if necessarysys.exit(app.exec())
Next if you are not using Command Line arguments as you are not then
This
app = QGuiApplication(sys.argv)
should be thisapp = QGuiApplication([])
Further if you are going to handle Command Line arguments look into argparser as it does a much better job of handling them and it is already been invented
Lastly always import any none PySide2 libraries after you declare your PySide2 objects as this makes sure that they utilize the correct version of PySide
-
@Denni-0 Thanks for the tips Denni!
-
@christofer
Having glanced at your code. I can't help you if you sayrowCount()
ordata()
are never called. I know nothing about QML so only you know if your code is being called. It looks fine as-is except that yourdata()
method needs work.def data(self, index, role=Qt.DisplayRole): print("data: " + self.items) return self.items
First it must return the correct indvidual element according to the
index: QModelIndex
parameter, and second it must only do so for theDisplayRole
case on therole
parameter, not for all cases as you have done. Until you have done those 2 it won't work right.If/when that's sorted out, you're trying to have
data()
return aclass MyItem
data item, say for theDisplayRole
when it wants to show it. I can't imagine what a Qt view is going to make of that. If you're lucky it might usestr(instanceMyItem)
, and I don't know what that looks like.
-
@JonB @Denni-0 I've made changes based on your feedback. Thanks. Still not sure the changes are correct because the functions do not get called. But at least it's closer to correct.
-
@Denni-0 just a side note, but the PySide2
QCoreApplication
,QGuiApplication
, andQApplication
haveexec_()
functions. The docs say things like "seeexec()
" but it doesn't exist. I get anAttributeError
if I try to use it. I'm using PySide2 version 5.14.1
-
@christofer You cannot expose a Python Object to QML, what you can do is export a QObject through the model as I have implemented in the PR to your repo.
-
@christofer You can also make the model expose each attribute of the items through the roles as I show in my second PR
-
@christofer said in Populating a ListView with Python Objects:
Still not sure the changes are correct because the functions do not get called
That sounds like a QML issue. You should heed what @eyllanesc has written, as he seems to know about Python to QML.
It really does not matter to try to change from
exec_()
toexec()
. PyQt exposes anexec()
(as well asexec_()
), PySide does not. As I said, nothing in your existing code I saw needed changing, it was not PyQt4 syntax, it was all correct, except for the implementation ofdata()
.
-
Thanks @eyllanesc for the MRs! They're very helpful.
On using roles for
a
andb
(commit 1e5447) vs just using thedisplay
role (commit 83b42b) ... which do you recommend? I like the simple access in the QMLmodel.a
,model.b
but it seems like making custom roles could conflict with Qt expecting the roles in PySide2.QtCore.Qt.ItemDataRole which makes me thinkmodel.display.a
,model.display.b
is a safer long-term solution.
-
Note I just glanced at your new code and you have
app.exec_()
and that requires thesys.exit( )
wrapper remove the underscore and just haveapp.exec()
as that is the Qt5 version of it
-
Okay I tried to use your example and create a similar more simplistic example using straight PySide2 but stumbled over using that QAbstractListModel so dropped back to an even more simplistic version the QStandardItemModel -- I am also including a link to where someone explains the QAbstractListModel a bit more clearly. Hopefully these two items in conjunction will help you with your issue.
from PySide2.QtCore import QAbstractListModel, Qt, QModelIndex, QVariant from PySide2.QtGui import QStandardItemModel, QStandardItem from PySide2.QtWidgets import QApplication, QWidget, QListView, QHBoxLayout, QVBoxLayout #https://stackoverflow.com/questions/46814961/how-to-insert-edit-qabstractlistmodel-in-python-and-qml-updates-automatically class MyItem: def __init__(self, a, b): self.MyName = a self.MyAge = b @property def Name(self): return self.MyName @property def Age(self): return self.MyAge @property def NameAge(self): MyNameAge = str(self.MyName) + ' ' + str(self.MyAge) return MyNameAge class ListView(QListView): def __init__(self): QListView.__init__(self) Hght = 100 Wdth = 100 self.setMaximumWidth(Wdth) self.setMaximumHeight(Hght) class ApplicationWindow(QWidget): def __init__(self): QWidget.__init__(self) Hght = 150 Wdth = 225 self.resize(Wdth, Hght) self.setWindowTitle('ListView') self.Model = QStandardItemModel() NamesAges = [['Al', 10],['Bob',20],['Chad',30]] for Vals in NamesAges: Item = MyItem(Vals[0], Vals[1]).NameAge Row = QStandardItem(Item) self.Model.appendRow(Row) self.TheView = ListView() self.TheView.setModel(self.Model) HBox = QHBoxLayout() HBox.addWidget(self.TheView) HBox.addStretch(1) VBox = QVBoxLayout() VBox.addLayout(HBox) VBox.addStretch(1) self.setLayout(VBox) print("app initialized") if __name__ == '__main__': MainEvntHndlr = QApplication([]) MainApp = ApplicationWindow() MainApp.show() MainEvntHndlr.exec() # If anyone wants more extensive free help I run an online lab-like classroom-like # message server feel free and drop by you will not be able to post until I clear # you as a student as this prevents spammers so if interested here is the invite # https://discord.gg/3D8huKC