如何根据 QML 中不同 QAbstractListModel 的元素实现列表?
How to implement a list depending on the elements of a different QAbstractListModel in QML?
在 QML 中,我想指定一个选项(字符串)列表,用户可以选择将其插入到我的后端。但我不希望列表包含后端 already 的字符串。如果后端更新,那么选项列表也应该更新。
首先,我编写了一个子类 QAbstractListModel
,它为我的后端公开了一个 QString
接口列表。它遵循文档中的指南,并公开了两个自定义函数 push_back
和 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
};
我在我的 QML 中考虑过这样的事情。首先查看后端中已有的字符串。这部分工作正常。
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}
}
}
然后是可以添加到后端的选项列表,这些选项还不是后端的一部分。这部分不行。
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 }
}
}
问题是,当后台添加字符串时,这个列表没有刷新。我不认为 Qt 理解 backend.indexOf
需要在修改时重新计算。
你对这个问题的看法是正确的。没有会重新调用 indexOf 的绑定。修复它的一种方法是您可以添加一个 Connections 对象,这样您就可以侦听特定信号,然后手动更新可见的 属性:
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)
}
}
在 QML 中,我想指定一个选项(字符串)列表,用户可以选择将其插入到我的后端。但我不希望列表包含后端 already 的字符串。如果后端更新,那么选项列表也应该更新。
首先,我编写了一个子类 QAbstractListModel
,它为我的后端公开了一个 QString
接口列表。它遵循文档中的指南,并公开了两个自定义函数 push_back
和 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
};
我在我的 QML 中考虑过这样的事情。首先查看后端中已有的字符串。这部分工作正常。
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}
}
}
然后是可以添加到后端的选项列表,这些选项还不是后端的一部分。这部分不行。
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 }
}
}
问题是,当后台添加字符串时,这个列表没有刷新。我不认为 Qt 理解 backend.indexOf
需要在修改时重新计算。
你对这个问题的看法是正确的。没有会重新调用 indexOf 的绑定。修复它的一种方法是您可以添加一个 Connections 对象,这样您就可以侦听特定信号,然后手动更新可见的 属性:
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)
}
}