Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Qt5.1: [Solved] Problems with Qlist when using ListView QML
Forum Updated to NodeBB v4.3 + New Features

Qt5.1: [Solved] Problems with Qlist when using ListView QML

Scheduled Pinned Locked Moved Mobile and Embedded
14 Posts 2 Posters 6.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • p3c0P Offline
    p3c0P Offline
    p3c0
    Moderators
    wrote on last edited by
    #2

    bq. Am I using completely different method than I’m suppose to, or am I missing something important here?

    The best way would be to create a model by subclassing "QAbstractListModel":http://qt-project.org/doc/qt-5/qabstractlistmodel.html. Please go through "subclassing":http://qt-project.org/doc/qt-5/qabstractlistmodel.html#subclassing topic.
    In this way to reload new items you will have to first "removeRows":qt-project.org/doc/qt-5/qabstractitemmodel.html#removeRows and then add new items after "beginInsertRows":http://qt-project.org/doc/qt-5/qabstractitemmodel.html#beginInsertRows so that the ListView gets notified and updates properly.
    An example "here":http://qt-project.org/doc/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel.

    157

    1 Reply Last reply
    0
    • H Offline
      H Offline
      heikkik
      wrote on last edited by
      #3

      Thanks for reply p3c0,

      No matter how hard I tried to find a solution (without any success, obviously) for some reason I couldn't find the answer from "QAbstractListModel":qt-project.org/doc/qt-5/qabstractlistmodel.html class. However, the links you gave me are indeed useful - at least when you quickly browse through them...

      I'll try this out in a few days and let you know how things worked out.

      1 Reply Last reply
      0
      • H Offline
        H Offline
        heikkik
        wrote on last edited by
        #4

        Okay, so...

        I read the whole "QAbstractListModel":http://qt-project.org/doc/qt-5/qabstractlistmodel.html and I tried to follow the example you linked and I'm having some issues without even getting to the part I actually need.

        To be honest, due all respect, I hate when there are suppose to be examples but the authors have left some of the critical parts out of them thinking that users know them already.

        Well, I started to study C++ like only few weeks a go and in the example there have been left out some important things. And I just can't figure them out how to write them.


        But before we go to the parts I know nothing about (or something, but not enough ...) here's my problem at the moment.

        Without any functions I tried to simply using the class. Below you can see my code.

        @// File: list.h

        #include <QAbstractItemModel>

        // I think something's really wrong with this class, right?
        class File {
        public:
        File ( const QString &file );
        };

        // And for some reason this seems incomplete as well ...
        class FileModel : public QAbstractItemModel {
        Q_OBJECT

        public:
        FileModel ( QObject * parent = 0 );
        };@

        @// File: list.cpp

        #include "list.h"

        FileModel :: FileModel ( QObject * parent ) : QObject ( parent ) {
        //
        }@

        @#include <QGuiApplication>
        #include <QQuickView>

        #include <sailfishapp.h>

        #include "list.h"

        int main ( int argc, char * argv [ ]) {
        QGuiApplication * q_application = SailfishApp :: application ( argc, argv );
        QQuickView * q_view = SailfishApp :: createView ( );

        // This is where I get my error - see below for quote.
        FileModel c_fileModel;
        
        q_view -> setSource ( SailfishApp :: pathTo ( "qml/cpp-listview.qml" ));
        q_view -> showFullScreen ( );
        
        return q_application -> exec &#40; &#41;;
        

        }@

        The error I get (in "cpp-listview.cpp" line #13):

        bq. Cannot declare variable 'c_fileModel' to be of abstract type 'FileModel'

        What's that suppose to mean? This is exactly like the one on the "example":http://qt-project.org/doc/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel p3c0 wrote.

        I also tried exactly the same code (without the dots, of course) and it gave me the same error and a bunch more.

        So what am I missing here?

        1 Reply Last reply
        0
        • p3c0P Offline
          p3c0P Offline
          p3c0
          Moderators
          wrote on last edited by
          #5

          Few issues here

          1. Why are you subclassing QAbstractItemModel ? For you purpose its good to subclass QAbstractListModel.

          bq. FileModel :: FileModel ( QObject * parent ) : QObject ( parent ) {
          //
          }

          FileModel should call the base class constructor viz. QAbstractItemModel (in current case, but change it to QAbstractListModel) instead of QObject.

          bq. Cannot declare variable ‘c_fileModel’ to be of abstract type ‘FileModel’

          For the custom model to work you should atleast reimplement "rowCount":http://qt-project.org/doc/qt-5/qabstractitemmodel.html#rowCount and "data()":http://qt-project.org/doc/qt-5/qabstractitemmodel.html#data

          Please go through "description":http://qt-project.org/doc/qt-5/qabstractlistmodel.html#details again.

          bq. Simple models can be created by subclassing this class and implementing the minimum number of required functions. For example, we could implement a simple read-only QStringList-based model that provides a list of strings to a QListView widget. In such a case, we only need to implement the rowCount() function to return the number of items in the list, and the data() function to retrieve items from the list.

          157

          1 Reply Last reply
          0
          • H Offline
            H Offline
            heikkik
            wrote on last edited by
            #6

            Thanks for your effor, p3c0

            1. I don't really understand what you're trying to tell me. First you ask why I'm subclassing (like it's the wrong way to do) but right after it you say it's the right way.

            2. Sorry, my bad. Completely forgot to change it to the header file as well.

            3. I'm still getting this very same error no matter I've defined "rowCount()":http://qt-project.org/doc/qt-5/qabstractitemmodel.html#rowCount and "data()":http://qt-project.org/doc/qt-5/qabstractitemmodel.html#data functions. I've also used "roleNames()":http://qt-project.org/doc/qt-5/qabstractitemmodel.html#roleNames because I know I'm going to need it later on this project.

            The error I'm getting also says the following:

            bq. Because the following virtual functions are pure within 'FileModel':
            virtual QModelIndex QAbstractItemModel::index(int, int, const QModelIndex&) const
            virtual QModelIndex QAbstractItemModel::parent(const QModelIndex&) const
            virtual int QAbstractItemModel::columnCount(const QModelIndex&) const

            What does it mean when (virtual) functions are pure within the class I've created.

            Below you can see the source codes:

            @// File: "list.h"

            class FileModel : public QAbstractItemModel {
            Q_OBJECT

            public:
            explicit FileModel ( QAbstractItemModel * parent = 0 );

            enum Roles {
                Role
            };
            
            virtual QHash <int, QByteArray> roleNames ( ) const;
            virtual int rowCount ( const QModelIndex &parent = QModelIndex ( )) const;
            virtual QVariant data ( const QModelIndex &index, int i_role ) const;
            

            private:
            QList <QString> l_files;
            };@

            @// File: "list.cpp"

            FileModel :: FileModel ( QAbstractItemModel * parent ) : QAbstractItemModel ( parent ) {
            beginInsertRows ( QModelIndex ( ), rowCount ( ), rowCount ( ));
            //
            endInsertRows ( );
            }

            QHash <int, QByteArray> FileModel :: roleNames ( ) const {
            QHash <int, QByteArray> h_roles;
            h_roles [ Role ] = "file";

            return h_roles;
            

            }

            int FileModel :: rowCount ( const QModelIndex &/* parent */ ) const {
            return l_files.size ( );
            }

            QVariant FileModel :: data ( const QModelIndex &q_index, int i_role ) const {
            if ( !q_index.isValid ( ) || q_index.row ( ) < 0.0 || q_index.row ( ) >= rowCount ( )) {
            return QVariant ( );
            }

            switch ( i_role ) {
            /*
            case Qt :: DisplayRole :
                return "Qt :: DisplayRole";
                break;
            */
            case Role :
                return "Role";
                break;
            
            default:
                return QVariant ( );
            }
            

            }@

            @// File "(project).cpp"

            int main ( int argc, char * argv [ ]) {
            QGuiApplication * q_application = SailfishApp :: application ( argc, argv );
            QQuickView * q_view = SailfishApp :: createView ( );

            // This is where the error comes!
            FileModel c_fileModel;
            
            // q_view -> rootContext ( ) -> setContextProperty ( "filesModel", &c_fileModel );
            q_view -> setSource ( SailfishApp :: pathTo ( "qml/cpp-listview.qml" ));
            q_view -> showFullScreen ( );
            
            return q_application -> exec &#40; &#41;;
            

            }@

            I also have a question - or an issue if you prefer. In the "example":http://qt-project.org/doc/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel the author uses addAnimal() function which obviously is a custom function inside Animal class. Why that part has been wiped off from this example? I have absolutely no clue (at this point) what there could possibly be...

            I do know that my beginInsertRows() and endInsertRows() functions should be there, but at first I'd just like to get some data pushed into my FileModel class and that I'm able to use this in my QML.

            And do I need nothing more than just the part written in the example when I'm creating my own Animal type of class, e.g. File? Because it seems a little bit too weird in my case to work as is and the author has placed some dots (argh!) that there is something.

            1 Reply Last reply
            0
            • p3c0P Offline
              p3c0P Offline
              p3c0
              Moderators
              wrote on last edited by
              #7

              bq. 1. I don’t really understand what you’re trying to tell me. First you ask why I’m subclassing (like it’s the wrong way to do) but right after it you say it’s the right way.

              What i'm saying is you need to subclass QAbstractListModel and not QAbstractItemModel and Cannot declare variable ‘c_fileModel’ to be of abstract type ‘FileModel’ error should go.

              bq. I also have a question – or an issue if you prefer. In the example [qt-project.org] the author uses addAnimal() function which obviously is a custom function inside Animal class. Why that part has been wiped off from this example? I have absolutely no clue (at this point) what there could possibly be…

              That's not a complete code. "Here":http://qt-project.org/doc/qt-5/qtquick-models-abstractitemmodel-example.html is the complete one.
              Also you would get the complete source code in the Installation path of your Qt.

              bq. The complete source code for this example is available in examples/quick/modelviews/abstractitemmodel within the Qt install directory.

              Also please check how the Roles are defined properly in the example.

              157

              1 Reply Last reply
              0
              • H Offline
                H Offline
                heikkik
                wrote on last edited by
                #8

                Oops, how the heck I could've read it wrong so many times? ~Shame on me! ~ And the reason why I couldn't find any complete source is that I don't actually have Qt5.1, I have *SailfishSDK *and it doesn't provide any other examples than those which are specially created for *Sailfish *applications. :)

                But hey, I finally got it working - kind of...

                The result is actually exactly the same than I had in the very beginning; I am able to create a model in *C++ *which can be used in QML. I'm also able to execute correct function to add new items to the list from QML. But the problem is, that the list doesn't update -- I'm not able to see any of the new items.

                Below you can see the complete source code which I've tried:

                @// File: "list.h"

                #ifndef LIST_H
                #define LIST_H

                #include <QAbstractItemModel>
                #include <QHash>
                #include <QByteArray>

                class File {
                public:
                File ( const QString &filename );

                QString filename ( &#41; const;
                

                private:
                QString s_file;

                };

                class FileModel : public QAbstractListModel {
                Q_OBJECT

                public:
                explicit FileModel ( QAbstractListModel * parent = 0 );

                enum Roles {
                    Filename
                };
                
                void _addFile &#40; const File &filename &#41;;
                
                int rowCount ( const QModelIndex &parent = QModelIndex ( &#41;) const;
                QVariant data ( const QModelIndex &index, int i_role = Qt :: DisplayRole ) const;
                
                QList <File> l_files;
                

                protected:
                QHash <int, QByteArray> roleNames ( ) const;

                private:
                //

                };

                class Files : public QObject {
                Q_OBJECT

                public:
                explicit Files ( QObject * parent = 0 );

                public slots:
                void addFile ( const QString &s_filename );

                signals:
                void countChanged ( );

                };

                #endif // LIST_H@

                @// File: "list.cpp"

                #include <QDebug>

                #include "list.h"

                File :: File ( const QString &filename ) : s_file ( filename ) {
                //
                }

                QString File :: filename ( ) const {
                return s_file;
                }

                FileModel :: FileModel ( QAbstractListModel * parent ) : QAbstractListModel ( parent ) {
                //
                }

                void FileModel :: _addFile ( const File &s_filename ) {
                beginInsertRows ( QModelIndex ( ), rowCount ( ), rowCount ( ));

                l_files << s_filename;
                
                endInsertRows ( );
                
                qDebug ( ) << "C++ function";
                

                }

                int FileModel :: rowCount ( const QModelIndex &parent ) const {
                Q_UNUSED ( parent );

                return l_files.size ( );
                

                }

                QVariant FileModel :: data ( const QModelIndex &q_index, int i_role ) const {
                if ( !q_index.isValid ( ) || q_index.row ( ) < 0.0 || q_index.row ( ) >= l_files.count ( )) {
                return QVariant ( );
                }

                const File &file = l_files [ q_index.row ( )];
                
                if ( i_role == Filename ) {
                    return file.filename ( );
                }
                
                return QVariant ( );
                

                }

                QHash <int, QByteArray> FileModel :: roleNames ( ) const {
                QHash <int, QByteArray> h_roles;
                h_roles [ Filename ] = "filename";

                return h_roles;
                

                }

                Files :: Files ( QObject * parent ) : QObject ( parent ) {
                //
                }

                void Files :: addFile ( const QString &s_filename ) {
                FileModel c_fileModel;
                c_fileModel._addFile ( File ( s_filename ));

                qDebug ( ) << "QML function";
                

                }@

                @// File: "(project).h"

                #ifdef QT_QML_DEBUG
                #include <QtQuick>
                #endif

                #include <QGuiApplication>
                #include <QQuickView>
                #include <QtQml>
                #include <QQmlContext>

                #include <sailfishapp.h>

                #include "list.h"

                int main ( int argc, char * argv [ ]) {
                QGuiApplication * q_application = SailfishApp :: application ( argc, argv );
                QQuickView * q_view = SailfishApp :: createView ( );

                qmlRegisterType <Files> ( "Custom.Component", 1, 0, "Files" );
                
                FileModel c_fileModel;
                c_fileModel._addFile &#40; File ( "Default item" &#41;&#41;;
                c_fileModel._addFile &#40; File ( "Default item" &#41;&#41;;
                c_fileModel._addFile &#40; File ( "Default item" &#41;&#41;;
                
                QQmlContext * q_qmlContext = q_view -> rootContext ( );
                q_qmlContext -> setContextProperty ( "filesModel", &c_fileModel );
                
                q_view -> setSource ( SailfishApp :: pathTo ( "qml/cpp-listview.qml" ));
                q_view -> showFullScreen ( );
                
                return q_application -> exec &#40; &#41;;
                

                }@

                @// File: "(project).qml"
                // NOTICE: This is just a part of my QML code.

                import Custom.Component 1.0

                Page {
                id: page_First

                Files {
                    id: files_CustomComponent
                }
                
                SilicaListView {
                    id: silicaListView
                
                    anchors.fill: page_First
                
                    header: PageHeader {
                        title: "Custom model"
                    }
                
                    model: filesModel
                
                    delegate: ListItem {
                        id: listItem
                
                        Label {
                            width: ( listItem.width - ( 2.0 * Theme.paddingLarge ))
                            height: listItem.height
                            x: Theme.paddingLarge
                
                            text: filename
                            color: ( listItem.highlighted ? Theme.highlightColor : Theme.primaryColor )
                            verticalAlignment: Text.AlignVCenter
                        }
                
                        onClicked: {
                            files_CustomComponent.addFile &#40; "New item" &#41;
                
                            console.log ( silicaListView.count &#41;
                        }
                    }
                }
                

                }@

                So any ideas why the *SilicaListView *won't update the items in the list? Debugging shows me that those functions are indeed executed when I click on any of the excisting items in the list.

                1 Reply Last reply
                0
                • p3c0P Offline
                  p3c0P Offline
                  p3c0
                  Moderators
                  wrote on last edited by
                  #9

                  bq. Files {
                  id: files_CustomComponent
                  }

                  This will create a new Files Component, don't use it to add new item

                  It will be nice if the Files Class contain only setter and getter methods for eg. in your case set a filename.

                  You should create a new "Q_INVOKABLE ":http://qt-project.org/doc/qt-5/qobject.html#Q_INVOKABLE function. This will allow you to call a C++ function from QML.
                  So for eg. you can move addFile("New item") to the model itself and make it Q_INVOKABLE
                  @
                  Q_INVOKABLE void addItem(QString filename);
                  @

                  Then you need to add the file there encapsulated in beginInsertRows(QModelIndex(), rowCount(), rowCount()) and endInsertRows() just as you have done in _addFile function.

                  157

                  1 Reply Last reply
                  0
                  • H Offline
                    H Offline
                    heikkik
                    wrote on last edited by
                    #10

                    Thanks for helping me with this!

                    Unfortunately I'm still not able to update the list from QML. I did what you suggested and used Q_INVOKABLE instead, but nothing actually changes. All the functions are normally executed and the string (given in QML) is recognized as it should be.

                    I haven't used Q_INVOKABLE before, actually, so this was new to me. Of course I've read about it, but never had to use one. So I read "this":http://developer.nokia.com/community/wiki/Calling_Qt_class_methods_from_QML tutorial and the functions do work properly.

                    Any idea?

                    1 Reply Last reply
                    0
                    • p3c0P Offline
                      p3c0P Offline
                      p3c0
                      Moderators
                      wrote on last edited by
                      #11

                      Did you use beginInsertRows and endInsertRows when adding new elements ?

                      I have created the following complete working example depending upon your example above, the only change is it doesnot use SailFish SDK. But i think that should not be an issue, or you can adjust it using SailFish's SDK.

                      main.cpp
                      @
                      #include <QGuiApplication>
                      #include <QtQuick>
                      #include "filemodel.h"

                      int main(int argc, char *argv[])
                      {
                      QGuiApplication app(argc, argv);

                      QQuickView view;
                      QObject::connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit()));
                      
                      FileModele model(view.engine());
                      view.rootContext()->setContextProperty("filesModel",&model);
                      view.setSource(QUrl(QStringLiteral("qrc:///main.qml")));
                      view.show();
                      
                      return app.exec();
                      

                      }
                      @

                      filemodel.h
                      @
                      #ifndef FILEMODEL_H
                      #define FILEMODEL_H

                      #include <QAbstractListModel>
                      #include "file.h"

                      class FileModele : public QAbstractListModel
                      {
                      Q_OBJECT
                      public:
                      explicit FileModele(QObject *parent = 0);

                      enum Roles {
                          FileNameRole = Qt::UserRole + 10,
                      };
                      
                      virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
                      virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
                      
                      Q_INVOKABLE void addItem(QString filename);
                      Q_INVOKABLE void init();
                      void loadItems();
                      void newItem(QString filename); //Internal
                      

                      signals:

                      public slots:

                      protected:
                      QHash<int, QByteArray> roleNames() const;

                      private:
                      QList<File*> m_items;
                      QStringList m_list;
                      int m_count;

                      };

                      #endif // FILEMODEL_H
                      @

                      filemodel.cpp
                      @
                      #include "filemodel.h"

                      FileModele::FileModele(QObject *parent) :
                      QAbstractListModel(parent)
                      {
                      m_count = 0;
                      m_list << "File1" << "File2" << "File3" << "File4";
                      }

                      QVariant FileModele::data(const QModelIndex &index, int role) const
                      {
                      if (index.row() < 0 || index.row() >= m_items.count())
                      return QVariant();

                      File *item = m_items.at(index.row());
                      switch (role) {
                      case FileNameRole:
                          return QVariant::fromValue(item->filename());
                      }
                      

                      }

                      int FileModele::rowCount(const QModelIndex &parent) const
                      {
                      return m_count;
                      }

                      QHash<int, QByteArray> FileModele::roleNames() const
                      {
                      QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
                      roles.insert(FileNameRole, QByteArray("filename"));
                      return roles;
                      }

                      void FileModele::addItem(QString filename)
                      {
                      beginInsertRows(QModelIndex(), rowCount(), rowCount());
                      newItem(filename);
                      endInsertRows();
                      }

                      void FileModele::init()
                      {
                      beginResetModel();
                      loadItems();
                      endResetModel();
                      }

                      void FileModele::loadItems()
                      {
                      beginInsertRows(QModelIndex(), rowCount(), rowCount());
                      for(int i=0; i<m_list.count();i++)
                      newItem(m_list.at(i));
                      endInsertRows();
                      }

                      void FileModele::newItem(QString filename)
                      {
                      File *item = new File;
                      item->setFilename(filename);
                      ++m_count;
                      m_items.append(item);
                      }
                      @

                      file.h
                      @
                      #ifndef FILE_H
                      #define FILE_H

                      #include <QObject>

                      class File : public QObject
                      {
                      Q_OBJECT
                      public:
                      explicit File(QObject *parent = 0);

                      QString filename() const;
                      void setFilename(const QString &filename);
                      

                      signals:

                      public slots:

                      private:
                      QString m_filename;

                      };

                      #endif // FILE_H
                      @

                      file.cpp
                      @
                      #include "file.h"

                      File::File(QObject *parent) :
                      QObject(parent)
                      {
                      }

                      QString File::filename() const
                      {
                      return m_filename;
                      }

                      void File::setFilename(const QString &filename)
                      {
                      m_filename = filename;
                      }
                      @

                      main.qml
                      @
                      import QtQuick 2.2
                      import QtQuick.Controls 1.2

                      Item {
                      width: 300
                      height: 400

                      ListView {
                          anchors.fill: parent
                      
                          model: filesModel
                      
                          delegate: Text {
                              text: model.filename
                          }
                      }
                      
                      Button {
                          width: 300
                          height: 50
                          text: "Add Item"
                          anchors.left: parent.left
                          anchors.bottom: parent.bottom
                          onClicked: filesModel.addItem("NewItem")
                      }
                      
                      Component.onCompleted: filesModel.init()
                      

                      }
                      @

                      To add new item just click on the Button and it should add new Item to the ListView.
                      Hope this helps you ...

                      157

                      1 Reply Last reply
                      0
                      • H Offline
                        H Offline
                        heikkik
                        wrote on last edited by
                        #12

                        Thank you for this p3c0

                        At first look at your code (I don't have my own code with me at the moment ..) I haven't forgot anything. Therefore I assume that I have forgot to link some functions together, or so..

                        I'll check it later and come back at you. Thank you again!

                        .

                        -- By the way, in some examples I've seen people using
                        @Qt :: UserRole + 1@

                        in their examples, but you are using @Qt :: UserRole +10@

                        And to be honest, I have never read any good explanation what this actually does. I do know it's somehow linked to the first (default?) role, but that's all there is to is.

                        1 Reply Last reply
                        0
                        • p3c0P Offline
                          p3c0P Offline
                          p3c0
                          Moderators
                          wrote on last edited by
                          #13

                          There are some predefined Role's used by Qt, for user defined Role's Qt::UserRole's are used. It doesnot matter if it starts from UserRole + 1 or UserRole + 100 or UserRole + 1000 unless it doesnot clashes with other Qt::UserRole's.

                          157

                          1 Reply Last reply
                          0
                          • H Offline
                            H Offline
                            heikkik
                            wrote on last edited by
                            #14

                            Okay, problem solved. I accidently tried to add more items to the QAbstractListModel itself, instead of QStringList.

                            Thank you p3c0 for helping me out, and explaining the meaning of Qt :: UserRole.

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved