0

In QML, a models roles are usually used by their names as strings.
However in some cases, this is not so. An example is the ListModel.onDataChanged

Here we have three arguments (see here) topLeft, bottomRight and roles that we can use to handle the signal. While you can use the topLeft.row easily to determine the index, I found no way to usefully evaluate the roles, that are given as a QVector<int>, while for the QML-usage a QVector<string> would be advantageous. To make things worse, roleNames, available in C++ returning the mapping of the integer-representation of the role to the respective string representing the role name.

Luckily I have only a limited amount of roles, so I might handle it. But it would be really nice of QML to give me the information I so desperately seek. ;-)

So maybe you have a solution that does not need C++ (I might create a ProxyModel that then exposes the roleNames() for me)

Community
  • 1
  • 1
  • Just use an object model, no need for roles, no need for data change notifications, you use objects with notifiable properties directly, you can achieve amorphism without the penalty of dynamic roles, model items can specify what delegate to use. A single, versatile and extremely useful in my experience C++ class is all that's really needed to make your life easier, your work faster, and also eliminate the need to use a bunch of ill-conceived components as the stock way of doing things. You can nest models, have one object in multiple models and populate models declaratively or imperatively. – dtech Jan 24 '17 at 19:16
  • If I use the [`ObjectModel`](http://doc.qt.io/qt-5/qml-qtqml-models-objectmodel.html) I can use it only in one View at the same time, otherwise the thing crashes, as it is not really a `delegate` but rather an simple list that does no good, or at least none I know of. – derM - not here for BOT dreams Jan 25 '17 at 06:54
  • What I sometimes do is, to instantiate a `QtObject` for each entry in the `ListModel` just to be able to get all the signals. That the `ListModel` only supports *flat* models by default is a bummer, but if you don't add `ListItems` but *append* QtObjects, they can be nested (with some limitations) which is good enough for me. – derM - not here for BOT dreams Jan 25 '17 at 07:07
  • ObjectModel sucks, I mean something like this: http://stackoverflow.com/questions/35160909/how-to-create-a-generic-object-model-for-use-in-qml/35161903#35161903 Also ownership can be made optional. – dtech Jan 25 '17 at 07:08
  • @ddriver roles and data changed signal are very much needed for a generic model. Without them you can't use `section` in a `ListView`, or you have to recreate every delegates for a `ComboBox` instead of just using `textRole`, or you can't really use them in a SortFilterProxyModel. An alternative to your link could be [`QQmlObjectListModel`](http://gitlab.unique-conception.org/qt-qml-tricks/qt-qml-models) that exposes roles for your properties. It doesn't have the declarative filling functionality though. – GrecKo Jan 25 '17 at 08:49
  • @GrecKo - sure, the stock functionality will not work without those, but it is trivial to roll out your own and more versatile implementations. I have views with sections which can be expanded, contracted, extracted, inserted, have custom graphic representation, sorting, filtering, support for amorphic and very complex trees with expand and contract for branches, going in arbitrary direction, scale including, and with support for declarative syntax user made trees can be compiled to qml code and be available as ready to use components. Good luck doing all that with the stock components :) – dtech Jan 25 '17 at 15:29
  • I'd argue by saying that reimplementing a lot of the stock functionality is not trivial. Or it will be severely limited. Everything you said can be done with models with roles AFAIK. Your tree view also, just not with a `ListModel` which is limited regarding the nesting. – GrecKo Jan 25 '17 at 15:43

2 Answers2

1

Are you sure you need this, i.e. using the exposed role as a property in QML does not fit your need? If so a couple of ways you can get this information:

  • A slot in your model class itself (add Q_OBJECT as well), e.g.
public slots:
    QString roleIndexToString(int index) const
    { /* implement */ }
  • You could also define a new signal in your model class, connect it to the dataChanged signal and do the transformation inside
signals:
    void dataChangedString(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<QString> &roles = QVector<QString> ()))

// in the class constructor
connect(this, &MyClass::dataChanged,
        [](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles){
            // Fill string vector and emit dataChangedString
});
Adversus
  • 2,166
  • 20
  • 23
  • I know I can do it in C++, but I my desire was to not hack something around on the `ListModel` or reimplement my own `ListModel` with some extensions, just to solve this issue for a quick'n'dirty prototype. Later, when I reimplement everything in a clean manner, the data will come from C++ and therefore I will *then* create enough custom models, that will have entirely different requirements. Therefore implementing a lot of stuff in a ever-changing prototype is not what I desire. It will be trashed later anyway. – derM - not here for BOT dreams Jan 25 '17 at 16:15
  • 1
    Aha, now I understand, I was thrown off by you mentioning C++ in your question. – Adversus Jan 26 '17 at 10:56
1

After some more studying of the C++-code of the ListModel I came to the conclusion, that this is not possible without access to the C++-Layer.

But as I planned on using the QML ListModels for the prototyping, I decided to simply register a QIdentityProxyModel-descendant, which I extended by a method:

QString ProxyModel::getRoleIntToName(int roleID) const
{
    return (QString)(roleNames()[roleID]);
}

Now, whenever I need to have access to the C++-layer of a QML-model, I can put it into this ProxyModel, and retrive all information that might have been hidden to QML.