Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. HorizontalHeaderView not reading data from headerData
Forum Updated to NodeBB v4.3 + New Features

HorizontalHeaderView not reading data from headerData

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
2 Posts 1 Posters 582 Views
  • 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 have the following constellation:

    A QuestionSqlTableModel model which is based on QSqlTableModel.

    A QuestionsProxyModel model which is based on QIdentityProxyModel

    In Qml I expose QuestionsProxyModel it should work as an adaptor to adapt the role names in QML to the SQL columns in the QSqlTableModel.

    Now this already looks like it works fine. I see the correct data of the QSqlTableModel in QML. However what does not work anymore is the HorizontalHeaderView.

    In qml I disply the data like this in a tableView:

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import QtQuick.Window 2.15
    import Qt.labs.qmlmodels 1.0
    
    import "data"
    
    Item {
        id: root
        HorizontalHeaderView {
            id: horizontalHeaderView
            syncView: tableView
            anchors.left: tableView.left
        }
        TableView {
            id: tableView
            width: parent.width
            height: parent.height - horizontalHeaderView.height
            anchors.top: horizontalHeaderView.bottom
            boundsBehavior: Flickable.StopAtBounds
    
            reuseItems: true
            clip: true
            property var columnWidths: [60, 220, 220, 220, 220, 220, 100, 140]
            columnWidthProvider: function (column) {
                return columnWidths[column]
            }
    
            model: questionsProxyModel
    
            delegate: // Various delegates with Delegate Chooser ....
    
            ScrollBar.vertical: ScrollBar {}
        }
    }
    

    Now on start I get these errors with HorizontalHeaderView:

    file:///home/sandro/Qt/5.15.0/gcc_64/qml/QtQuick/Controls.2/Universal/HorizontalHeaderView.qml:60:13: Unable to assign [undefined] to QString
    

    The QuestionsProxyModel which is based on QIdentityProxyModel provides the header data like this:

    #ifndef QUESTIONSPROXYMODEL_H
    #define QUESTIONSPROXYMODEL_H
    
    #include <QObject>
    #include <QIdentityProxyModel>
    
    class QuestionsProxyModel : public QIdentityProxyModel
    {
        Q_OBJECT
    
        enum questionRoles {
            idRole = Qt::UserRole + 1,
            askedQuestionRole,
            answer1Role,
            answer2Role,
            answer3Role,
            answer4Role,
            correctAnswerRole,
            pictureRole
        };
    
    public:
        QuestionsProxyModel(QObject* parent = nullptr);
    
        QHash<int, QByteArray> roleNames() const override;
    
        Q_INVOKABLE QVariant headerData(int section, Qt::Orientation orientation,
                                        int role) const override;
    
        Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override;
    
    private:
        QModelIndex mapIndex(const QModelIndex &index, int role) const;
    };
    
    #endif // QUESTIONSPROXYQML_H
    
    #include "../include/questionsproxymodel.h"
    
    #include "../include/questionsqlcolumnnames.h"
    
    #include <QPixmap>
    #include <QBuffer>
    
    #include <QByteArray>
    
    QuestionsProxyModel::QuestionsProxyModel(QObject* parent)
        :QIdentityProxyModel(parent)
    {
    }
    
    QHash<int, QByteArray> QuestionsProxyModel::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 QuestionsProxyModel::headerData(int section,
                                             Qt::Orientation orientation, int role) const
    {
        if(orientation != Qt::Orientation::Horizontal) {
            return QVariant{};
        }
    
        if(role == Qt::DisplayRole) {
            switch (section) {
                case 0:
                    return tr("Id");
                case 1:
                    return tr("Question");
                case 2:
                    return tr("Answer 1");
                case 3:
                    return tr("Answer 2");
                case 4:
                    return tr("Answer 3");
                case 5:
                    return tr("Answer 4");
                case 6:
                    return tr("Correct Answer");
                case 7:
                    return tr("Picture");
            }
        }
        return QVariant{};
    }
    
    QVariant QuestionsProxyModel::data(const QModelIndex &index, int role) const
    {
        QModelIndex newIndex = mapIndex(index, role);
        if (role == idRole
                || role == askedQuestionRole
                || role == answer1Role
                || role == answer2Role
                || role == answer3Role
                || role == answer4Role
                || role == correctAnswerRole
                || role == pictureRole) {
    
            return QIdentityProxyModel::data(newIndex, Qt::DisplayRole);
        }
        return QIdentityProxyModel::data(newIndex, role);
    }
    
    QModelIndex QuestionsProxyModel::mapIndex(const QModelIndex &source, int role) const
    {
        switch(role) {
        case idRole:
            return createIndex(source.row(), QuestionColumn::id);
        case askedQuestionRole:
            return createIndex(source.row(), QuestionColumn::askedQuestion);
        case answer1Role:
            return createIndex(source.row(), QuestionColumn::answer1);
        case answer2Role:
            return createIndex(source.row(), QuestionColumn::answer2);
        case answer3Role:
            return createIndex(source.row(), QuestionColumn::answer3);
        case answer4Role:
            return createIndex(source.row(), QuestionColumn::answer4);
        case correctAnswerRole:
            return createIndex(source.row(), QuestionColumn::correct_answer);
        case pictureRole:
            return createIndex(source.row(), QuestionColumn::picture);
        }
        return source;
    }
    
    

    I assumed that horizontalHeaderView calls QuestionsProxyModel::headerData but it does not even call it somehow.

    The full code can be found here:
    https://github.com/SandroWissmann/Quiz/tree/Editable-Question-Table

    1 Reply Last reply
    0
    • S Offline
      S Offline
      sandro4912
      wrote on last edited by
      #2

      I think I found the reason why it is not working. The Qt docs state this for the model of headerView:

      If the model is a QAbstractTableModel, then the header will display the model's horizontal headerData(); otherwise, the model's data().
      

      So how do I have to implement data to show the headers? I tried this:

      QVariant QuestionsProxyModel::data(const QModelIndex &index, int role) const
      {
          if(role == Qt::DisplayRole) {
              switch (index.column()) {
                  case 0:
                      return tr("Id");
                  case 1:
                      return tr("Question");
                  case 2:
                      return tr("Answer 1");
                  case 3:
                      return tr("Answer 2");
                  case 4:
                      return tr("Answer 3");
                  case 5:
                      return tr("Answer 4");
                  case 6:
                      return tr("Correct Answer");
                  case 7:
                      return tr("Picture");
              }
          }
          
          QModelIndex newIndex = mapIndex(index, role);
          if (role == idRole
                  || role == askedQuestionRole
                  || role == answer1Role
                  || role == answer2Role
                  || role == answer3Role
                  || role == answer4Role
                  || role == correctAnswerRole
                  || role == pictureRole) {
      
              return QIdentityProxyModel::data(newIndex, Qt::DisplayRole);
          }
          return QIdentityProxyModel::data(newIndex, role);
      }
      

      With the same result as before.

      The hacky workarround was to set an own model on headerView with the names:

      HorizontalHeaderView {
          id: horizontalHeaderView
          syncView: tableView
          anchors.left: tableView.left
          model: [qsTr("Id"), qsTr("Question"), qsTr("Answer 1"), qsTr(
                  "Answer 2"), qsTr("Answer 3"), qsTr("Answer 4"), qsTr(
                  "Correct Answer"), qsTr("Picture")]
      }
      
      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