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
    #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