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
Qt 6.11 is out! See what's new in the release blog

HorizontalHeaderView not reading data from headerData

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
2 Posts 1 Posters 704 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