0
votes

I have a matrix

QVector<QVector<double>> A;

that I want to output and edit. In QWidgets I put this matrix into QAbstractTableModel subclass and set this as a model for QTableView. In qml this doesn't seem to work with TableView.

As I understood, for fixed size matrices I can explicitly write roles for each column:

TableViewColumn {
        role: "first" // "second", "third" etc.
}

And then for each role return corresponding column from QAbstractTableModel::data(...).

But what if matrix dimensions are computed in runtime? What is the best way to work with such matrices in qml?

1
I guess you should notify the table with insertColumns, removeColumns if your data source has changed. - folibis
@folibis: I don't think that will do the trick, as, afaik, QML does not care for model columns. I think you should expose a property, e.g. roleNames which you then use as a Repeater to create TableViewColumns with role: modelData - derM

1 Answers

0
votes

Note: Might be hacky but works

I have not worked with a QAbstractTableModel and QML so far, but to my understanding, QML does not care for columns, so a ListModel should be a sufficient subsitution for an example:

import QtQuick 2.7
import QtQml 2.2
import QtQuick.Controls 1.4

ApplicationWindow {
    id: myWindow
    visible: true
    width: 600
    height: 600
    color: 'white'

    ListModel {
        id: lv
        property var roleNames: ['role1', 'role2']
        ListElement { role1: 'a'; role2: 'b' }
    }

    ListModel {
        id: tm
        property var roleNames: [ 'myID', 'age', 'name']
        ListElement { myID:  1; name: 'Egon';    age: 15 }
        ListElement { myID:  2; name: 'Herbert'; age: 21 }
        ListElement { myID:  3; name: 'Jan';     age: 11 }
        ListElement { myID:  4; name: 'Dieter';  age: 23 }
        ListElement { myID:  5; name: 'Ulrich';  age:  6 }
        ListElement { myID:  6; name: 'Hans';    age: 45 }
        ListElement { myID:  7; name: 'Frieder'; age: 31 }
        ListElement { myID:  8; name: 'Gerd';    age: 28 }
    }

    TableView {
        id: tv
        model: lv
        anchors.fill: parent
        Instantiator {
            model: tv.model ? tv.model.roleNames : 0
            delegate: TableViewColumn {
                title: modelData
                role: modelData
                Component.onCompleted: tv.addColumn(this)
                Component.onDestruction: tv.removeColumn(0)
            }
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: tv.model = (tv.model === lv ? tm : lv)
    }
}

By adding a second model, I create a sufficient and accordingly configured amount of TableViewColumns that I then add to the TableView utilizing a Instantiator (as TableViewColumn is no Item as it seems).

A problem that arrises here, is that I don't find a way to access the column index, I need to call tv.removeColumn with the proper index. But in this case, where I always replace the whole model, this is no problem as long I delete all columns, one after another by always removing the first with tv.removeColumn(0). I will still get a error

Error: Invalid attempt to destroy() an indestructible object

as this method tries to invoke destroy() on a object that is not created with JS, but this is no problem. The Instantiator will delete it right after.

So: Though there is a error message, this will work, as long as you completely reset the model of the Instantiator everytime there is a change.