[SOLVED} filling a ListView with a custom Model?



  • So I got QDjango, a ORM library, configured with my postgres database. it's up and running and I can either iterate over each row, storing them in a QList<T> or use one of two functions to get either a QList<QVariantList> or a QList<QVariantMap> for displaying it in a simple ListView in QML

    So I have tried binding either list to QML with
    main.cpp
    @
    QDjangoQuerySet<Product> query; //automatically grabs all the rows from the Product table
    QList<QVariantMap> list = query.valuesList();

    QtQuick2ApplicationViewer viewer;
    viewer.rootContext()->setContextProperty("productlist", &list)
    @

    and trying to use it in qml:
    main.qml
    @
    ..

    ListView{
    anchors.fill: parent
    model: productlist
    delegate: Rectangle{
    height:20
    width:20
    Text{ text: display_name }
    }
    ..
    @

    all I get is an empty rectangle..
    if i just change one line though..

    main.cpp
    @
    viewer.rootContext()->setContextProperty("productlist", &list[0])
    @

    I can at least get ONE row.. but that's not really helping though. So I didn't manage to make this work so I had a look at QAbstractListModel.

    tried implementing that failed miserably cause I didn't understand it well enough.
    It all fell apart when implementing the QAbstractListModel::data() function..
    it got some parameters like roles.. which I by life can't figure out what that suppose to be or what they are for.. but what bothers me there is a fixed type I have to return: QVariant.

    But what about all the QDjangoModel's I have made? I want return those,..
    thats when I decided that I don't know c++ or programming well enough to go any further on my own. I tried searching the forums were there are several very similar problems.. but either no solution or very very confusing code snippets.

    If there is decent documentation somewhere out there, it seems I have missed it or didn't understand it properly, either way I would be very happy if someone could help me out here.

    thank you for your time.



  • I made some complex list models in the past using QAbstractListModel, and they worked great in QML. However I watched a talk with Adenilson Calvacanti on Qt Dev days 2012 where he had made a generic model in C++.

    http://www.youtube.com/watch?v=m_-8B4acawE&list=PLizsthdRd0YzYe5T3Txgg7TUGVi-ijq4d&index=14

    The source can be found here:
    https://code.google.com/p/cellardoor/source/browse/?r=cd45960b47d3e9ae74132b56a54c727dd8c8c307#git/src

    Take a look at genericmodel.cpp and controller.cpp especially. The basic idea is that you just use the genericmodel class in your code and forget about how to implement QAbstractListModel yourself. I have not tried this, but will eventually when I find the need.

    I hope this might help you.



  • ah thank you! it seems i tried watching this video already in the past. but, to be honest, the accent put me really off and i didn't get 1/3 of the stuff he said. it was quiet annoying. but it seems i can't get around not watching it now can i :).

    the link to the source is very interesting and i will try i tout right away! if it works i will get back and mark this thread as solved.



  • The most important thing is to look at the code, I don't think the video was that helpful, but it was there I got the information. :)

    Looking forward to hear if it works for you!



  • now i integrated generalmodel and generalmodelbase to my project and looked closely at the example you gave me and made little changes here and there to make it look like the example. there was one major thing: the function QAbstractModelList::setRoleNames() is depracted since Qt5 and reimplementing roleNames() should be used instead. So i copied the constructor of GeneralModel 1:1 into the function roleNames(). that wasn't too hard but still no luck, it won't compile..

    i have a bad feeling that it has to do something with qdjango and not being able to copy things?
    here is the full log:
    @
    In file included from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qobject.h:51:0,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qcoreapplication.h:48,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtGui/qguiapplication.h:45,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtGui/QGuiApplication:1,
    from ../kassomat/main.cpp:1:
    /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qlist.h: In instantiation of 'void QList<T>::node_copy(QList<T>::Node*, QList<T>::Node*, QList<T>::Node*) [with T = Product]':
    /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qlist.h:726:9: required from 'QList<T>::QList(const QList<T>&) [with T = Product]'
    /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qlist.h:428:23: required from 'QList<T>& QList<T>::operator=(const QList<T>&) [with T = Product]'
    ../kassomat/genericmodel.cpp:75:5: required from 'void GenericModel<ModelTemplate>::addItems(const QList<T>&) [with ModelTemplate = Product]'
    ../kassomat/main.cpp:22:21: required from here
    /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qlist.h:387:17: error: use of deleted function 'Product::Product(const Product&)'
    In file included from ../kassomat/databasecontroller.h:6:0,
    from ../kassomat/main.cpp:5:
    ../kassomat/product.h:5:7: note: 'Product::Product(const Product&)' is implicitly deleted because the default definition would be ill-formed:
    ../kassomat/product.h:5:7: error: use of deleted function 'QDjangoModel::QDjangoModel(const QDjangoModel&)'
    In file included from ../kassomat/project.h:4:0,
    from ../kassomat/databasecontroller.h:5,
    from ../kassomat/main.cpp:5:
    ../kassomat/db/QDjangoModel.h:77:22: note: 'QDjangoModel::QDjangoModel(const QDjangoModel&)' is implicitly deleted because the default definition would be ill-formed:
    In file included from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qcoreapplication.h:48:0,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtGui/qguiapplication.h:45,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtGui/QGuiApplication:1,
    from ../kassomat/main.cpp:1:
    /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qobject.h:426:5: error: 'QObject::QObject(const QObject&)' is private
    In file included from ../kassomat/project.h:4:0,
    from ../kassomat/databasecontroller.h:5,
    from ../kassomat/main.cpp:5:
    ../kassomat/db/QDjangoModel.h:77:22: error: within this context
    In file included from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qobject.h:51:0,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qcoreapplication.h:48,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtGui/qguiapplication.h:45,
    from /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtGui/QGuiApplication:1,
    from ../kassomat/main.cpp:1:
    /home/vierlex/Qt5.1.0/5.1.0-beta1/gcc_64/include/QtCore/qlist.h:400:17: error: use of deleted function 'Product::Product(const Product&)'
    make: *** [main.o] Error 1
    09:09:57: The process "/usr/bin/make" exited with code 2.@



  • Looks to me that you have an object inherited from QObject that tries to use a Copy constructor.

    According to this : http://qt-project.org/doc/qt-4.8/object.html#qt-objects-identity-vs-value

    bq. QObject and all subclasses of QObject (direct or indirect) have their copy constructor and assignment operator disabled.

    Perhaps your Product class should not inherit from QObject. Are there any reasons you need it to be a subclass of QObject? Do you need signals and slots?

    Anyway, let me know if I mistook the log, I am not familiar with QDjango.



  • Product is a subclass of QDjangoModel which in turn is a subclass of QObject.. I need this to access the database like this:

    @
    QDjangoQuerySet<Product> all_the_products;
    QDjangoQuerySet<Product> some_products;
    some_products = all_the_products.filter(QDjangoWhere("name", QDjangoWhere::Equals, "foo") &&
    QDjangoWhere("brand", QDjangoWhere::NotEquals, "bar"));
    @

    where class Product : public QDjangoModel

    meh, it seems i have to make a google account to get into the discussion group on qdjangos website..



  • Hmmm... Maybe we have done this the wrong way.

    I have read the OP a few more times and perhaps there is something about the ListView, Model and Delegate that might be the problem. I would like to see a printout of the list model in main.cpp.

    And perhaps you could do a printout of the list when it is in QML aswell?

    @for(var propertyName in myObject) {
    // propertyName is what you want
    // you can get the value like this: myObject[propertyName]
    }@



  • hi, sorry for my absence,

    ive managed to get the code to compile cause i changed some things into pointers cause, yea, some things couldn't be copied because it was a qobject and stuff..
    to get a better idea i paste.bin'ed the interesting code parts. if something is missing just ask.

    main.cpp http://pastebin.com/j6GvpXsy
    genericmodel.cpp http://pastebin.com/X1FtAPUS
    projectlist.qml http://pastebin.com/Vf68qVb6
    project.h http://pastebin.com/w7k5gZB7

    also the requested output: http://pastebin.com/hQxkwXaK
    (this one is very wierd)



  • What does this print out?

    @p = databaseController.listProducts();@

    And in qml you could do as you do in cpp. Have a for loop that gets each item based on index.



  • hah I got it to work!

    The problem was one of the functions of util.cpp was not working as intended which is used to get role names. some posts before, i mentioned overriding QAbstractListModel::setRoleNames is depracted as of Qt5.. so overriding QAbstractListModel::roleNames() is the new way to go..
    it all happens in the constructor of GenericModel

    util.cpp - not in use anymore
    @
    void extractObjectProperties(const QMetaObject *object,
    QStringList *list,
    bool cleanup,
    const char *prefix)
    {
    QStringList &properties = *list;
    const int count = object->propertyCount();
    for (int i = 0; i < count; ++i) {
    QString propertyName = object->property(i).name();
    if (propertyName.startsWith(prefix)) {
    properties << propertyName;
    }
    }

    if (cleanup) {
        properties.replaceInStrings(prefix, "");
    }
    

    }
    @

    genericmodel.cpp - before, little bit modified from the example
    @
    template <class ModelTemplate>
    GenericModel<ModelTemplate>::GenericModel(QObject *parent, bool cleanupPrefix)
    : GenericModelBase(parent), m_cleanup(cleanupPrefix), m_propertyCount(0)
    {
    //const ModelTemplate object;
    QStringList properties;
    ModelTemplate tmp;
    Utils::extractObjectProperties(tmp.metaObject(), &properties, m_cleanup);

    m_propertyCount = properties.count();
    

    }

    ...

    template <class ModelTemplate>
    QHash<int, QByteArray> GenericModel<ModelTemplate>::roleNames() const{
    QHash<int, QByteArray> roles;

    QStringList properties;
    ModelTemplate tmp;
    Utils::extractObjectProperties(tmp.metaObject(), &properties, m_cleanup);
    
    for (int i = 0; i < properties.count(); ++i) {
        roles[i] = properties[i].toUtf8();
        //qDebug() << roles[i] << "hello";
    }
    
    return roles;
    

    }
    @

    it's rather self explanatory, all the Q_PROPERTIES i defined at project.h get collected and should be returned by that function, so qml knows about the properties properly using the QAbstractListModel::roleNames()

    so the huge key thing here was understanding that:
    roles (cpp) = properties (qml).
    or it wont work.

    the function provided in the example had some sort of filter for whatever reason, i just copy/cut/pasted my version without that filter and voila, it worked. here is the proper function for the genericmodel class which got it to work for me :)

    genericmodel.cpp - after
    @
    template <class ModelTemplate>
    GenericModel<ModelTemplate>::GenericModel(QObject *parent, bool cleanupPrefix)
    : GenericModelBase(parent), m_cleanup(cleanupPrefix), m_propertyCount(0)
    {
    ModelTemplate tmp;

    m_propertyCount = tmp.metaObject()->propertyCount();
    for (int i = 0; i < m_propertyCount; ++i) {
        QString propertyName = tmp.metaObject()->property(i).name();
        m_roles[i] = propertyName.toUtf8();
    }
    

    }

    ...

    template <class ModelTemplate>
    QHash<int, QByteArray> GenericModel<ModelTemplate>::roleNames() const{

    return m_roles;
    

    }
    @

    as you can see i have added also a member variable called QHash<int, > m_roles for storing.

    oh btw, dont be confused about the product / project thing..
    if someone in the future has a similar problem i'm glad to provide further code/explanations so dont hesitate to grave dig it up or PM me.

    thanks for your help gennon


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.