I've been trying to populate a tableview with dynamically created columns based on model headers (this works as intended now!) However I still can't seem to get the TableView to correctly read my model data. I checked to see if EmployeeTableModel::data() was ever called and it wasn't so thats a pretty big red flag.
My compiler errors are ReferenceError: score is not defined, etc for all user created roles. My EmployeeModelMaster works perfectly even though it has essentially the same class structure.
I think I'm missing something simple, the qml file will be attached below.
main.cpp
Code:
int main(int argc, char *argv[]) { QQmlApplicationEngine engine; EmployeeModelMaster* masterModel = new EmployeeModelMaster(); EmployeeModelTable* table = new EmployeeModelTable(); QObject::connect(masterModel, SIGNAL(updateMirrors(int,EmployeeModelMaster*)), table, SLOT(masterDataChanged(int,EmployeeModelMaster*))); masterModel->configSQL(); qDebug()<<"info successfully pulled from database? " << masterModel->pullFromSQL(); engine.rootContext()->setContextProperty("baseTableModel", table); engine.rootContext()->setContextProperty("headers", table->headerList()); qDebug()<<"right before loading shyftwrk.qml"; qDebug()<<"engine loaded shyftwrk.qml"; return app.exec(); }
table.h
Code:
#ifndef EMPLOYEEMODELTABLE_H #define EMPLOYEEMODELTABLE_H /* this model is a mirror of EmployeeModelMaster, it is not intended to have data directly set; to update this table * please connect the masterChanged() slot. */ { Q_OBJECT public: typedef QList<QList<EmployeeData*> >::const_iterator const_iterator; //does this do anything? public: enum EmployeeModelTableDataRole { nameRole=Qt::UserRole+1, positionRole, portraitRole, scoreRole }; public: //virtual inherited members from QAbstractTableModel bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::DisplayRole); public: //new members specifically for our implementation const_iterator begin()const{return m_data.begin();} const_iterator end()const{return m_data.end();} signals: void headerDataChanged(int first, int last); //the only important signal from the tableModel public slots: void masterDataChanged(int rows, EmployeeModelMaster* master); //tells employeeModelTable to update, pulls from employeeModelMaster. protected: QHash<int, QByteArray> roleNames() const; QList < EmployeeData* > str_data; public: int headerItr; }; #endif // EMPLOYEEMODELTABLE_H
table.cpp
Code:
{ QList<EmployeeData*> null; m_data.append(null); headerItr =0; } { Q_UNUSED(parent); if(m_data[0].isEmpty()) return 0; return m_data[0].count(); // since each column is identical, get the count from column 0 } { Q_UNUSED(parent); return m_data.count(); } { if(!index.isValid()) if(index.row() <0 || index.row()>= this->rowCount(index)) if(index.column() <0 || index.column()>= this->columnCount()) const EmployeeData *data = m_data[index.column()][index.row()]; if (role == nameRole) return data->name(); else if (role == portraitRole) return data->portrait(); else if(role == positionRole) return data->position(); else if(role == scoreRole) return data->score(); else } bool EmployeeModelTable::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { Q_UNUSED(orientation); //orientation will always be horizontal if(role != Qt::DisplayRole) return false; for(int i=0; i <= m_headerData.count(); i++) //if the header already exists, don't make another one { if(m_headerData.value(i) == value) return false; } m_headerData[section] = value.toString(); headerDataChanged(section, m_headerData.size()); return true; } { for(int i=0; i<m_headerData.size(); i++) //if the header already exists, don't make another one { if(!m_headerData.isEmpty()) { if(m_headerData[i] == value.toString()) { return false; } } } m_headerData[headerItr] = value.toString(); m_data.append(str_data); endInsertColumns(); headerItr++; return true; } { Q_UNUSED(orientation); //orientation will always be horizontal if(role != Qt::DisplayRole) return m_headerData.value(section); } { if(index.isValid()) return QAbstractTableModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::NoItemFlags; } QHash<int, QByteArray> EmployeeModelTable::roleNames() const { QHash<int, QByteArray> roles; roles[nameRole] = "name"; roles[portraitRole] = "portrait"; roles[positionRole] = "position"; roles[scoreRole] = "score"; return roles; } void EmployeeModelTable::masterDataChanged(int rows, EmployeeModelMaster* master) { for(int k=0; k < this->columnCount(); k++) { while(rows > this->m_data[k].count()) // if the new row is bigger than the current, append with dummies { EmployeeData* nullperson = new EmployeeData(); this->m_data[k].append(nullperson); this->str_data.append(nullperson); endInsertRows(); } for(int i=0; i < rows; i++) { if(i > m_data[k].count()) { this->m_data[k].append(master->m_data[i]); endInsertRows(); } if(i > str_data.count()) { this->str_data.append(master->m_data[i]); } this->m_data[k][i] = master->m_data[i]; //replace existing data in table with new data from master endInsertRows(); this->str_data[i] = master->m_data[i]; newHeader(this->m_data[k][i]->position()); } } } { return m_headerData.values(); }
qml snippet
Code:
import QtQuick 2.0 import QtQuick.Controls 1.2 Rectangle{ id: root radius: 5 TableView{ id: schedulerTableView itemDelegate: tableDelegate resources: { var headerData = headers var temp = [] for(var i=0; i<headerData.length; i++) { var role = headerData[i] temp.push(columnComponent.createObject(schedulerTableView, { "role": role, "title": role})) console.log("column #" + i + " is named : " + role); } return temp } model: baseTableModel anchors.fill: root } Component { id: columnComponent TableViewColumn{width: 220 } } Component{ id: tableDelegate Rectangle{ id: delRectangle height: 250 z:0 Clickable{ id: portraitText source: portrait smooth: true antialiasing: true anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter height: 150 fillMode: Image.PreserveAspectFit overlayOpacity: 0.4 } Text{ id: nameText text: name anchors.horizontalCenter: parent.horizontalCenter anchors.top: portraitText.bottom } Text{ id: positionText anchors.top: nameText.bottom anchors.horizontalCenter: parent.horizontalCenter text: position } Text{ id:scoreText anchors.top: positionText.bottom anchors.horizontalCenter: parent.horizontalCenter text: score } } } }
Added after 21 minutes:
also I should mention, if I convert my TableView to a ListView, it populates with the first column from the model as intended, which makes me think I'm very close.
Added after 18 minutes:
I figured it out: If add the prefix "model." to each of my itemDelegate sources (image src, text text, etc) then it is read correctly. Not entirely sure why that's the case but I'm happy I figured it out.