Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Exposed model to QML does not Update
Forum Updated to NodeBB v4.3 + New Features

Exposed model to QML does not Update

Scheduled Pinned Locked Moved Solved General and Desktop
6 Posts 2 Posters 351 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.
  • S Offline
    S Offline
    sandro4912
    wrote on last edited by sandro4912
    #1

    I use QSortFilterProxyModel to randomly select rows from the source model it is installed on.

    Then I expose the model to qml and call from there the method generateRandomQuestions. If I check mAcceptedRows it looks like there are indeed new valid indexes generated so the model should contain new data.

    However in QML the View does not update to the new data.

    the Model:

    #include <QSortFilterProxyModel>
    #include <QVector>
    
    class RandomQuestionFilterModel : public QSortFilterProxyModel
    {
        Q_OBJECT
    
        enum questionRoles {
            idRole = Qt::UserRole + 1,
            askedQuestionRole,
            answer1Role,
            answer2Role,
            answer3Role,
            answer4Role,
            correctAnswerRole,
            pictureRole
        };
    
    public:
        RandomQuestionFilterModel(QObject *parent = nullptr);
    
        QHash<int, QByteArray> roleNames() const override;
        QVariant data(const QModelIndex &index, int role) const override;
    
        Q_INVOKABLE void generateRandomQuestions(int count);
    protected:
        bool filterAcceptsRow(int source_row,
                              const QModelIndex &source_parent) const override;
    private:
        QVector<int> mAcceptedRows;
    };
    
    #include "../include/randomquestionfiltermodel.h"
    
    #include <algorithm>
    #include <random>
    
    #include <QDebug>
    
    RandomQuestionFilterModel::RandomQuestionFilterModel(QObject *parent)
        :QSortFilterProxyModel{parent}
    {
    }
    
    QHash<int, QByteArray> RandomQuestionFilterModel::roleNames() const
    {
        QHash <int,QByteArray> roles;
        roles[idRole] = "id";
        roles[askedQuestionRole] = "askedQuestion";
        roles[answer1Role] = "answer1";
        roles[answer2Role] = "answer2";
        roles[answer3Role] = "answer3";
        roles[answer4Role] = "answer4";
        roles[correctAnswerRole] = "correctAnswer";
        roles[pictureRole] = "picture";
    
        return roles;
    }
    
    QVariant RandomQuestionFilterModel::data(const QModelIndex &index, int role) const
    {
        switch(role) {
        case idRole:
            return index.sibling(index.row(), 0).data().toInt();
        case askedQuestionRole:
            return index.sibling(index.row(), 1).data().toString();
        case answer1Role:
            return index.sibling(index.row(), 2).data().toString();
        case answer2Role:
            return index.sibling(index.row(), 3).data().toString();
        case answer3Role:
            return index.sibling(index.row(), 4).data().toString();
        case answer4Role:
            return index.sibling(index.row(), 5).data().toString();
        case correctAnswerRole:
            return index.sibling(index.row(), 6).data().toInt();
        case pictureRole:
            return index.sibling(index.row(), 7).data().toByteArray().toBase64();
        }
        return QSortFilterProxyModel::data(index, role);
    }
    
    void RandomQuestionFilterModel::generateRandomQuestions(int count)
    {
        mAcceptedRows.resize(sourceModel()->rowCount());
        std::iota(std::begin(mAcceptedRows), std::end(mAcceptedRows), 0);
        std::shuffle(std::begin(mAcceptedRows), std::end(mAcceptedRows),
                     std::mt19937(std::random_device()()));
    
        mAcceptedRows.resize(count);
    
        auto start = createIndex(0,0);
        auto end = createIndex(rowCount(),columnCount());
        emit dataChanged(start, end);
    }
    
    bool RandomQuestionFilterModel::filterAcceptsRow(
            int source_row, const QModelIndex &source_parent) const
    {
        Q_UNUSED(source_parent)
        auto it = std::find(mAcceptedRows.begin(), mAcceptedRows.end(), source_row);
        return it != mAcceptedRows.end();
    }
    

    I thought emitting dataChanged in generateRandomQuestions would notify the view that the data changed but it does not.

    In QML I generate the random questions first and then open the page were the random questions are used.

    ToolButton {
                   id: newQuizButton
                   text: qsTr("New Quiz")
                   icon.name: "address-book-new"
                   onClicked: {
                       randomQuestionFilterModel.generateRandomQuestions(
                                   countOfQuestions)
                       loader.setSource(root.__newQuizPath)
                   }
               }
    

    On the page I pass the rows like this:

    SwipeView {
           id: quizSwipeView
           interactive: false
           anchors.fill: parent
    
           Repeater {
               id: quizPageRepeater
               model: randomQuestionFilterModel
               delegate: QuizPage {
                   questionId: model.id
                   askedQuestion: model.askedQuestion
                   answer1: model.answer1
                   answer2: model.answer2
                   answer3: model.answer3
                   answer4: model.answer4
                   correctAnswer: model.correctAnswer
                   picture: model.picture
                   onAnsweredCorrectly: quiz.answeredCorrectly()
                   onAnsweredWrong: quiz.answeredWrong()
               }
           }
       }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      I do not know for sure but in that method you are not merely changing data, the complet model content is changed. Sounds rather like a use case for beginResetModel and endResetModel.

      However it looks like a strange use of QSortFilterProxyModel which states usually between the model actually containing the data and the view.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      S 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi,

        I do not know for sure but in that method you are not merely changing data, the complet model content is changed. Sounds rather like a use case for beginResetModel and endResetModel.

        However it looks like a strange use of QSortFilterProxyModel which states usually between the model actually containing the data and the view.

        S Offline
        S Offline
        sandro4912
        wrote on last edited by
        #3

        @SGaist

        Your right that solved my Issue.

        I'm open for a better solution to get the questions.

        Currently I have the following:

        In C++:
        A questions model derrived from QSqlTableModel to store and fetch questions (with possible answers).

        The Filter model derrived from QSortFilterProxyModel to fetch n random questions from the questions model.

        These models get exposed to qml.

        In QML:

        Show all the questions in the database. -> I use the questions model for that.
        Add new questions to the database -> I use the questions model for that.

        Present random questions as a Quiz to the User. Here I use the filter model to filter random entries from the question model.

        If this is not a good approach I would love to here suggestions how else I could get the random questions.

        An even worst appraoch I used before was getting the questions directly from the question model by exposing them as

        QQmlListProperty <Question> getRandomQuestions(); member function.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          One way, you can use a QSqlQueryModel and make the randomization in the request itself.

          The proxy model is not a bad idea, you just need to separate it from the data themselves.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          S 1 Reply Last reply
          1
          • SGaistS SGaist

            One way, you can use a QSqlQueryModel and make the randomization in the request itself.

            The proxy model is not a bad idea, you just need to separate it from the data themselves.

            S Offline
            S Offline
            sandro4912
            wrote on last edited by
            #5

            @SGaist What do you mean separate it from the data? The SQL Access is only done in the table model the proxy model filters.

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by SGaist
              #6

              It was just a general statement. It happens from time to time that people try to use the proxy model as a standard model. This is indeed not your case :-)

              Sorry for the confusion !

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              1

              • Login

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