Reputation: 5513
In QML, I want to specify a list of options (strings) that the user can choose to insert into my backend. But I don't want the list to contain strings that are already in the backend. And if the backend is updated, then the list of options should also update.
First I wrote a subclass QAbstractListModel
which exposes a list of QString
interface for my backend. It follows the guidelines from the docs, and exposes two custom functions push_back
and indexOf
.
class MyModel: public QAbstractListModel {
Q_OBJECT
public:
MyModel() { ... } // connect to the backend
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override {
Q_UNUSED(role);
if (!hasIndex(index.row(), index.column())) {
return {};
}
return ... // retreive backend object at index.row() and convert to QString
}
Q_INVOKABLE void push_back(const QString& item) {
beginInsertRows(QModelIndex(), int(_data->size()), int(_data->size()));
... // convert QString to backend data type and insert into backend
endInsertRows();
}
Q_INVOKABLE int indexOf(const QString& item) {
return ... // convert QString to backend type, and search backend for this object. return -1 if not found
}
private:
// pointer to backend object
};
I was thinking something like this in my QML. First a view of the strings that are already in the backend. This part works fine.
ListView {
anchors.fill: parent
spacing: 5
model: backend // an instance MyModel interface, passed in from main.cpp
delegate: Rectangle {
height: 25
width: 200
Text { text: model.display}
}
}
And then the list of options that can be added to the backend, which are not already part of the backend. This part doesn't work.
ListView {
anchors.fill: parent
spacing: 5
model: ["option1", "option2", "option3"]
delegate: Rectangle {
visible: backend.indexOf(model.modelData) >= 0
height: 25
width: 200
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: {
backend.push_back(model.modelData)
}
}
Text { text: model.modelData }
}
}
The problem is, when strings are added to the backend, this list does not refresh. I don't think Qt understands that backend.indexOf
needs to be recomputed whenever its modified.
Upvotes: 0
Views: 460
Reputation: 8277
You are correct about the problem. There's no binding that will re-call indexOf. One way to fix it is you could add a Connections object so you can listen for a specific signal and then manually update the visible property:
delegate: Rectangle {
visible: backend.indexOf(model.modelData) >= 0
height: 25
width: 200
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: {
backend.push_back(model.modelData)
}
}
Text { text: model.modelData }
Connections {
target: backend
onCountChanged: visible = (backend.indexOf(model.modelData) >= 0)
}
}
Upvotes: 2